GLDF 0.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
GLDF/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .frontend import\
2
+ run_hccd_temporal_regimes, run_hccd_spatial_regimes
File without changes
@@ -0,0 +1,185 @@
1
+ try:
2
+ import causallearn.search
3
+ except ModuleNotFoundError:
4
+ raise RuntimeError("Causal-learn bridge could not be loaded. Is causal-learn installed?")
5
+
6
+ from causallearn.utils import cit
7
+
8
+ import numpy as np
9
+ from functools import partial
10
+ from typing import Callable
11
+
12
+ from ..hccd import CI_Identifier, abstract_cit_t, abstract_cd_t
13
+ from ..data_management import IManageData
14
+
15
+
16
+ # in theory pyhton can copy functions, in practise it cannot (as of v3.13), so we copy-paste the code fromcausallearn.utils instead
17
+ def named_CIT(data, method='fisherz', **kwargs):
18
+ if method == cit.fisherz:
19
+ return cit.FisherZ(data, **kwargs)
20
+ elif method == cit.kci:
21
+ return cit.KCI(data, **kwargs)
22
+ elif method in [cit.chisq, cit.gsq]:
23
+ return cit.Chisq_or_Gsq(data, method_name=method, **kwargs)
24
+ elif method == cit.mv_fisherz:
25
+ return cit.MV_FisherZ(data, **kwargs)
26
+ elif method == cit.mc_fisherz:
27
+ return cit.MC_FisherZ(data, **kwargs)
28
+ elif method == cit.d_separation:
29
+ return cit.D_Separation(data, **kwargs)
30
+ else:
31
+ raise ValueError("Unknown method: {}".format(method))
32
+
33
+
34
+
35
+ def pick_CIT(data, method, **kwargs):
36
+ if isinstance(method, str):
37
+ return named_CIT(data, method, **kwargs)
38
+ else:
39
+ return method.provide_with_cl_args(**kwargs)
40
+
41
+ cit.CIT = pick_CIT
42
+
43
+ cit.CIT_Base = object # fix "validation" in fci
44
+
45
+ from causallearn.search.ConstraintBased.PC import pc as _cl_impl_pc
46
+ from causallearn.search.ConstraintBased.FCI import fci as _cl_impl_fci
47
+ import causallearn.search.ConstraintBased.FCI as _FCI_module
48
+
49
+ # in 'get_color_edges', l. 627 of causallearn.search.ConstraintBased.FCI there is a print command
50
+ # apparently left over from debugging, which will spam links,
51
+ # suppress all prints from this modul by brute-force:
52
+ _FCI_module.print = lambda *args : None
53
+
54
+
55
+ def causallearn_graph_to_tigramite_graph_pc(G):
56
+ N, validate = G.shape
57
+ assert validate == N
58
+ result = np.full_like(G, '', dtype='<U3')
59
+ for i in range(N):
60
+ for j in range(N):
61
+ if G[i,j] == +1:
62
+ if G[j,i] == +1:
63
+ result[i,j] = "<->"
64
+ else:
65
+ assert G[j,i] == -1
66
+ result[i,j] = "<--"
67
+ elif G[i,j] == -1:
68
+ if G[j,i] == +1:
69
+ result[i,j] = "-->"
70
+ else:
71
+ assert G[j,i] == -1
72
+ result[i,j] = "o-o"
73
+ return result
74
+
75
+ def _np_replace_char(data, i, j, idx, value):
76
+ current = list(data[i,j])
77
+ current[idx] = value
78
+ data[i,j] = "".join(current)
79
+
80
+
81
+ def causallearn_graph_to_tigramite_graph_fci(G):
82
+ N, validate = G.shape
83
+ assert validate == N
84
+ result = np.full_like(G, '', dtype='<U3')
85
+ for i in range(N):
86
+ for j in range(N):
87
+ if G[i,j] == 0:
88
+ assert G[j,i] == 0
89
+ continue
90
+ result[i,j] = "?-?"
91
+ if G[i,j] == +1:
92
+ _np_replace_char( result, i, j, 0, '<' )
93
+ elif G[i,j] == -1:
94
+ _np_replace_char( result, i, j, 0, '-' )
95
+ elif G[i,j] == 2:
96
+ _np_replace_char( result, i, j, 0, 'o' )
97
+ else:
98
+ assert False
99
+ if G[j,i] == +1:
100
+ _np_replace_char( result, i, j, 2, '>' )
101
+ elif G[j,i] == -1:
102
+ _np_replace_char( result, i, j, 2, '-' )
103
+ elif G[j,i] == 2:
104
+ _np_replace_char( result, i, j, 2, 'o' )
105
+ else:
106
+ assert False
107
+ return result
108
+
109
+
110
+ def causallearn_graph_to_tigramite_graph(graph):
111
+ G = None
112
+ if isinstance(graph, tuple):
113
+ general_graph, _ = graph
114
+ G = general_graph.graph # fci
115
+ return causallearn_graph_to_tigramite_graph_fci(G)
116
+ else:
117
+ G = graph.G.graph # pc
118
+ return causallearn_graph_to_tigramite_graph_pc(G)
119
+
120
+
121
+ class WrapCIT_CausalLearnIndexing:
122
+ def __init__(self, generalized_cit: abstract_cit_t):
123
+ self.generalized_cit = generalized_cit
124
+ self.method = "custom"
125
+
126
+ def __call__(self, x_idx: int, y_idx: int, Z: list[int]) -> float:
127
+ ci = CI_Identifier(idx_x=x_idx, idx_y=y_idx, idx_list_z=Z)
128
+ result = self.generalized_cit(ci)
129
+ # cl wants a pvalue under independence (signigicance is decided by test, cf run_pc)
130
+ return 0.0 if result else 1.0
131
+
132
+ def provide_with_cl_args(self, **args) -> Callable[[int, int, list[int]], float]:
133
+ return self
134
+
135
+
136
+ def run_pc(data_format: IManageData, generalized_cit: abstract_cit_t, **args):
137
+ # Note: alpha param of cl is unused (signigicance is decided by test, cf cit-wrapper)
138
+ data_ignored_but_need_correct_shape_and_type = np.empty(shape=(data_format.total_sample_size(), data_format.number_of_variables()), dtype=np.void)
139
+ result = _cl_impl_pc(data=data_ignored_but_need_correct_shape_and_type, indep_test=WrapCIT_CausalLearnIndexing(generalized_cit), show_progress=False, **args)
140
+ return causallearn_graph_to_tigramite_graph(result)
141
+
142
+
143
+
144
+ def run_fci(data_format: IManageData, generalized_cit: abstract_cit_t, **args):
145
+ # Note: alpha param of cl is unused (signigicance is decided by test, cf cit-wrapper)
146
+ data_ignored_but_need_correct_shape_and_type = np.empty(shape=(data_format.total_sample_size(), data_format.number_of_variables()), dtype=np.void)
147
+ result = _cl_impl_fci(dataset=data_ignored_but_need_correct_shape_and_type, independence_test_method=WrapCIT_CausalLearnIndexing(generalized_cit), show_progress=False, **args)
148
+ return causallearn_graph_to_tigramite_graph(result)
149
+
150
+
151
+ def alg_pc(data_format: IManageData, **runtime_args) -> abstract_cd_t:
152
+ """
153
+ Get PC [SG91]_ implementation from causal learn.
154
+
155
+ :param data_format: data manager
156
+ :type data_format: IManageData
157
+ :param runtime_args: forwarded to causal-learns run_pc (together with "stable=False")
158
+ :return: PC as abstract CD-algorithm.
159
+ :rtype: abstract_cd_t
160
+ """
161
+ return partial(run_pc, data_format=data_format, stable=False, **runtime_args)
162
+
163
+ def alg_pc_stable(data_format: IManageData, **runtime_args) -> abstract_cd_t:
164
+ """
165
+ Get PC-stable [CM+14]_ implementation from causal learn.
166
+
167
+ :param data_format: data manager
168
+ :type data_format: IManageData
169
+ :param runtime_args: forwarded to causal-learns run_pc (together with "stable=True")
170
+ :return: PC-stable as abstract CD-algorithm.
171
+ :rtype: abstract_cd_t
172
+ """
173
+ return partial(run_pc, data_format=data_format, stable=True, **runtime_args)
174
+
175
+ def alg_fci(data_format: IManageData, **runtime_args) -> abstract_cd_t:
176
+ """
177
+ Get FCI [SGS01]_ implementation from causal learn.
178
+
179
+ :param data_format: data manager
180
+ :type data_format: IManageData
181
+ :param runtime_args: forwarded to causal-learns run_fci
182
+ :return: FCI as abstract CD-algorithm.
183
+ :rtype: abstract_cd_t
184
+ """
185
+ return partial(run_fci, data_format=data_format, **runtime_args)
@@ -0,0 +1,143 @@
1
+ try:
2
+ from tigramite.pcmci import PCMCI
3
+ from tigramite.lpcmci import LPCMCI
4
+ except ModuleNotFoundError:
5
+ raise RuntimeError("Tigramite bridge could not be loaded. Is tigramite installed?")
6
+
7
+ import numpy as np
8
+ from typing import Literal
9
+ np.fastCopyAndTranspose = lambda a: a.T.copy() # this was deprecated since 1.24.0, removed in 2.0.0, but is used in some places in tigramite
10
+
11
+ from ..hccd import IHandleExplicitTransitionToMCI, CI_Identifier_TimeSeries, abstract_cit_t, abstract_cd_t
12
+ from ..data_management import IManageData
13
+
14
+ class WrapCIT_TigramiteIndexing:
15
+ def __init__(self, generalized_cit: abstract_cit_t):
16
+ self.generalized_cit = generalized_cit
17
+ self.method = "custom"
18
+ self.measure = "custom" # used only on higher verbosity of PCMCI(?)
19
+ self.confidence = None
20
+ self.significance = "custom"
21
+ def run_test(self, X: list[tuple[int,int]], Y: list[tuple[int,int]], Z: list[tuple[int,int]], tau_max: int, alpha_or_thres: float) -> tuple[float, float, bool]:
22
+ if len(X) != 1 or len(Y) != 1:
23
+ raise NotImplementedError("Currently this implementation supports only univariate X, Y.")
24
+ ci = CI_Identifier_TimeSeries(idx_x=X[0], idx_y=Y[0], idx_list_z=Z)
25
+ result = self.generalized_cit(ci)
26
+ # return dependency-score, pvalue, dependent (yes/no)
27
+ return 1.0 if result else 0.0, 0.0 if result else 1.0, result
28
+ def get_confidence(*args, **args_dict):
29
+ return None # run_mci with val_only=True does not seem to work
30
+
31
+ class WrapPCMCI(PCMCI):
32
+ def __init__(self, data_format: IManageData, mode: Literal["PCMCI", "PCMCI+"]="PCMCI", mci_transition_callback: IHandleExplicitTransitionToMCI=None, pcmci_obj_init_args: dict={}, pcmci_obj_run_args: dict={}):
33
+ class PlaceholderTest:
34
+ def set_dataframe(self, not_a_dataframe):
35
+ pass
36
+ class PlaceholderDataframe:
37
+ def __init__(self):
38
+ self.var_names = None
39
+ self.T = None
40
+ self.N = None
41
+
42
+ super().__init__(dataframe=PlaceholderDataframe(), cond_ind_test=PlaceholderTest(), **pcmci_obj_init_args)
43
+ self.data_format = data_format
44
+ self.mci_transition_callback = mci_transition_callback
45
+ self.runtime_args = pcmci_obj_run_args
46
+ if mode == "PCMCI":
47
+ self.run = self.run_pcmci
48
+ elif mode == "PCMCIplus" or mode == "PCMCI+":
49
+ self.run = self.run_pcmciplus
50
+ else:
51
+ raise ValueError("Unknown mode for PCMCI, supported values are 'PCMCI' or 'PCMCI+'. Did you want to use WrapLPCMCI instead?")
52
+
53
+ def run_pc_stable(self, *args_tuple, **args_dict):
54
+ self.mci_transition_callback.enter_pc1()
55
+ return super().run_pc_stable(*args_tuple, **args_dict)
56
+ def run_mci(self, *args_tuple, **args_dict):
57
+ self.mci_transition_callback.enter_mci()
58
+ return super().run_mci(*args_tuple, **args_dict)
59
+ def _pcmciplus_mci_skeleton_phase(self, *args_tuple, **args_dict):
60
+ self.mci_transition_callback.enter_mci()
61
+ return super()._pcmciplus_mci_skeleton_phase(*args_tuple, **args_dict)
62
+
63
+ def __call__(self, generalized_cit: abstract_cit_t):
64
+ self.T, self.N = {0: self.data_format.total_sample_size()}, self.data_format.number_of_variables()
65
+ self.cond_ind_test = WrapCIT_TigramiteIndexing(generalized_cit)
66
+ result = self.run(**self.runtime_args)
67
+ return result['graph']
68
+
69
+
70
+ class WrapLPCMCI(LPCMCI):
71
+ def __init__(self, data_format: IManageData, lpcmci_obj_init_args: dict={}, lpcmci_obj_run_args: dict={}):
72
+ class PlaceholderTest:
73
+ def set_dataframe(self, not_a_dataframe):
74
+ pass
75
+ class PlaceholderDataframe:
76
+ def __init__(self):
77
+ self.var_names = None
78
+ self.T = None
79
+ self.N = None
80
+ super().__init__(dataframe=PlaceholderDataframe(), cond_ind_test=PlaceholderTest(), **lpcmci_obj_init_args)
81
+ self.data_format = data_format
82
+ self.runtime_args = lpcmci_obj_run_args
83
+
84
+ def __call__(self, generalized_cit: abstract_cit_t):
85
+ self.T, self.N = {0: self.data_format.total_sample_size()}, self.data_format.number_of_variables()
86
+ self.cond_ind_test = WrapCIT_TigramiteIndexing(generalized_cit)
87
+ result = self.run_lpcmci(**self.runtime_args)
88
+ return result['graph']
89
+
90
+
91
+ def alg_pcmci(data_format: IManageData, mci_transition_callback: IHandleExplicitTransitionToMCI=None, pcmci_obj_init_args: dict={}, pcmci_obj_run_args: dict={}) -> abstract_cd_t:
92
+ """
93
+ Get PCMCI [RNK+19]_ implementation from tigramite. Use with :py:class:`ControllerTimeseries<GLDF.hccd.ControllerTimeseries>`.
94
+
95
+ :param data_format: data manager
96
+ :type data_format: IManageData
97
+ :param mci_transition_callback: transition callback (typically :py:class:`IndependenceAtoms_TimeSeries<GLDF.independence_atoms.IndependenceAtoms_TimeSeries>`)
98
+ :type mci_transition_callback: IHandleExplicitTransitionToMCI
99
+ :param pcmci_obj_init_args: forwarded to tigramites PCMCI constructor
100
+ :type pcmci_obj_init_args: dict
101
+ :param pcmci_obj_run_args: forwarded to tigramites PCMCI.run_pcmci
102
+ :type pcmci_obj_run_args: dict
103
+ :return: PCMCI as abstract CD-algorithm.
104
+ :rtype: abstract_cd_t
105
+ """
106
+ return WrapPCMCI(data_format=data_format, mode="PCMCI", mci_transition_callback=mci_transition_callback,
107
+ pcmci_obj_init_args=pcmci_obj_init_args, pcmci_obj_run_args=pcmci_obj_run_args)
108
+
109
+ def alg_pcmciplus(data_format: IManageData, mci_transition_callback: IHandleExplicitTransitionToMCI=None, pcmci_obj_init_args: dict={}, pcmci_obj_run_args: dict={}) -> abstract_cd_t:
110
+ """
111
+ Get PCMCI+ [R20]_ implementation from tigramite. Use with :py:class:`ControllerTimeseries<GLDF.hccd.ControllerTimeseries>`.
112
+
113
+ :param data_format: data manager
114
+ :type data_format: IManageData
115
+ :param mci_transition_callback: transition callback (typically :py:class:`IndependenceAtoms_TimeSeries<GLDF.independence_atoms.IndependenceAtoms_TimeSeries>`)
116
+ :type mci_transition_callback: IHandleExplicitTransitionToMCI
117
+ :param pcmci_obj_init_args: forwarded to tigramites PCMCI constructor
118
+ :type pcmci_obj_init_args: dict
119
+ :param pcmci_obj_run_args: forwarded to tigramites PCMCI.run_pcmciplus
120
+ :type pcmci_obj_run_args: dict
121
+ :return: PCMCI+ as abstract CD-algorithm.
122
+ :rtype: abstract_cd_t
123
+ """
124
+ return WrapPCMCI(data_format=data_format, mode="PCMCI+", mci_transition_callback=mci_transition_callback,
125
+ pcmci_obj_init_args=pcmci_obj_init_args, pcmci_obj_run_args=pcmci_obj_run_args)
126
+
127
+ def alg_lpcmci(data_format: IManageData, lpcmci_obj_init_args: dict={}, lpcmci_obj_run_args: dict={}) -> abstract_cd_t:
128
+ """
129
+ Get LPCMCI [GR20]_ implementation from tigramite. Use with :py:class:`ControllerTimeseriesLPCMCI<GLDF.hccd.ControllerTimeseriesLPCMCI>`.
130
+
131
+ *Note: In this case a transition callback* :py:class:`IHandleExplicitTransitionToMCI<GLDF.hccd.IHandleExplicitTransitionToMCI>` *is*
132
+ *notified by the controller* :py:class:`ControllerTimeseriesLPCMCI<GLDF.hccd.ControllerTimeseriesLPCMCI>`\\ *.*
133
+
134
+ :param data_format: data manager
135
+ :type data_format: IManageData
136
+ :param lpcmci_obj_init_args: forwarded to tigramites LPCMCI constructor
137
+ :type lpcmci_obj_init_args: dict
138
+ :param lpcmci_obj_run_args: forwarded to tigramites LPCMCI.run_lpcmci
139
+ :type lpcmci_obj_run_args: dict
140
+ :return: LPCMCI as abstract CD-algorithm.
141
+ :rtype: abstract_cd_t
142
+ """
143
+ return WrapLPCMCI(data_format=data_format, lpcmci_obj_init_args=lpcmci_obj_init_args, lpcmci_obj_run_args=lpcmci_obj_run_args)