sampling-mining-workflows-dsl 0.0.1__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.
Files changed (79) hide show
  1. sampling_mining_workflows_dsl/ __init__.py +0 -0
  2. sampling_mining_workflows_dsl/CompleteWorkflow.py +23 -0
  3. sampling_mining_workflows_dsl/Workflow.py +242 -0
  4. sampling_mining_workflows_dsl/WorkflowBuilder.py +11 -0
  5. sampling_mining_workflows_dsl/analysis/ChiSquareAnalysis.py +37 -0
  6. sampling_mining_workflows_dsl/analysis/CochranTest.py +44 -0
  7. sampling_mining_workflows_dsl/analysis/CochranWorkflowAnalysis.py +37 -0
  8. sampling_mining_workflows_dsl/analysis/CoverageTest.py +60 -0
  9. sampling_mining_workflows_dsl/analysis/DistributionWorkflowAnalysis.py +57 -0
  10. sampling_mining_workflows_dsl/analysis/HistAnalysis.py +201 -0
  11. sampling_mining_workflows_dsl/analysis/HistWorkflowAnalysis.py +72 -0
  12. sampling_mining_workflows_dsl/analysis/KSWorkflowAnalysis.py +217 -0
  13. sampling_mining_workflows_dsl/analysis/WorkflowAnalysis.py +7 -0
  14. sampling_mining_workflows_dsl/analysis/YamaneTest.py +16 -0
  15. sampling_mining_workflows_dsl/analysis/YamaneWorkflowAnalysis.py +27 -0
  16. sampling_mining_workflows_dsl/analysis/kolmogorov_smirnov.py +31 -0
  17. sampling_mining_workflows_dsl/constraint/BoolComparator.py +23 -0
  18. sampling_mining_workflows_dsl/constraint/BoolConstraint.py +50 -0
  19. sampling_mining_workflows_dsl/constraint/BoolConstraintString.py +66 -0
  20. sampling_mining_workflows_dsl/constraint/Comparator.py +16 -0
  21. sampling_mining_workflows_dsl/constraint/Constraint.py +23 -0
  22. sampling_mining_workflows_dsl/constraint/NaturalComparator.py +17 -0
  23. sampling_mining_workflows_dsl/element/Element.py +45 -0
  24. sampling_mining_workflows_dsl/element/Loader.py +17 -0
  25. sampling_mining_workflows_dsl/element/Repository.py +28 -0
  26. sampling_mining_workflows_dsl/element/Set.py +210 -0
  27. sampling_mining_workflows_dsl/element/Writer.py +9 -0
  28. sampling_mining_workflows_dsl/element/loader/CsvLoader.py +67 -0
  29. sampling_mining_workflows_dsl/element/loader/JsonLoader.py +84 -0
  30. sampling_mining_workflows_dsl/element/loader/LoaderFactory.py +14 -0
  31. sampling_mining_workflows_dsl/element/writer/CsvWriter.py +46 -0
  32. sampling_mining_workflows_dsl/element/writer/JsonWriter.py +58 -0
  33. sampling_mining_workflows_dsl/element/writer/WriterFactory.py +7 -0
  34. sampling_mining_workflows_dsl/exec_visualizer/WorkflowVisualizer.py +189 -0
  35. sampling_mining_workflows_dsl/github_seart/loader.py +17 -0
  36. sampling_mining_workflows_dsl/github_seart/metadata.py +106 -0
  37. sampling_mining_workflows_dsl/metadata/Metadata.py +117 -0
  38. sampling_mining_workflows_dsl/metadata/MetadataBoolean.py +14 -0
  39. sampling_mining_workflows_dsl/metadata/MetadataDate.py +75 -0
  40. sampling_mining_workflows_dsl/metadata/MetadataDict.py +33 -0
  41. sampling_mining_workflows_dsl/metadata/MetadataList.py +32 -0
  42. sampling_mining_workflows_dsl/metadata/MetadataNumber.py +29 -0
  43. sampling_mining_workflows_dsl/metadata/MetadataString.py +13 -0
  44. sampling_mining_workflows_dsl/metadata/MetadataValue.py +24 -0
  45. sampling_mining_workflows_dsl/operator/Operator.py +165 -0
  46. sampling_mining_workflows_dsl/operator/OperatorBuilder.py +191 -0
  47. sampling_mining_workflows_dsl/operator/OperatorFactory.py +76 -0
  48. sampling_mining_workflows_dsl/operator/clustering/GroupingOperator.py +36 -0
  49. sampling_mining_workflows_dsl/operator/clustering/SubWorkflowOperatorBuilder.py +76 -0
  50. sampling_mining_workflows_dsl/operator/selection/SelectionOperator.py +5 -0
  51. sampling_mining_workflows_dsl/operator/selection/filter/FilterOperator.py +30 -0
  52. sampling_mining_workflows_dsl/operator/selection/sampling/SamplingOperator.py +11 -0
  53. sampling_mining_workflows_dsl/operator/selection/sampling/automatic/AutomaticSamplingOperator.py +9 -0
  54. sampling_mining_workflows_dsl/operator/selection/sampling/automatic/RandomSelectionOperator.py +24 -0
  55. sampling_mining_workflows_dsl/operator/selection/sampling/automatic/RandomSelectionPartitionOperator.py +62 -0
  56. sampling_mining_workflows_dsl/operator/selection/sampling/automatic/SystematicRandomSelectionOperator.py +14 -0
  57. sampling_mining_workflows_dsl/operator/selection/sampling/automatic/SystematicSelectionOperator.py +31 -0
  58. sampling_mining_workflows_dsl/operator/selection/sampling/manual/InteractiveManualSamplingOperator.py +40 -0
  59. sampling_mining_workflows_dsl/operator/selection/sampling/manual/ManualSamplingOperator.py +28 -0
  60. sampling_mining_workflows_dsl/operator/set_algebra/ExternalSetOperator.py +33 -0
  61. sampling_mining_workflows_dsl/operator/set_algebra/InternalSetOperator.py +47 -0
  62. sampling_mining_workflows_dsl/operator/set_algebra/SetOperator.py +30 -0
  63. sampling_mining_workflows_dsl/operator/set_algebra/external_set_operator/DifferenceOperator.py +17 -0
  64. sampling_mining_workflows_dsl/operator/set_algebra/external_set_operator/IntersectionOperator.py +19 -0
  65. sampling_mining_workflows_dsl/operator/set_algebra/external_set_operator/UnionOperator.py +17 -0
  66. sampling_mining_workflows_dsl/operator/set_algebra/internal_set_operator/DifferenceOperator.py +17 -0
  67. sampling_mining_workflows_dsl/operator/set_algebra/internal_set_operator/IntersectionOperator.py +18 -0
  68. sampling_mining_workflows_dsl/operator/set_algebra/internal_set_operator/UnionOperator.py +17 -0
  69. sampling_mining_workflows_dsl/operator/set_algebra/set_operator/DifferenceOperator.py +15 -0
  70. sampling_mining_workflows_dsl/operator/set_algebra/set_operator/IntersectionOperator.py +18 -0
  71. sampling_mining_workflows_dsl/operator/set_algebra/set_operator/UnionOperator.py +17 -0
  72. sampling_mining_workflows_dsl/test/ __init__.py +0 -0
  73. sampling_mining_workflows_dsl/test/Workflow_simple.py +38 -0
  74. sampling_mining_workflows_dsl/test/input.json +401 -0
  75. sampling_mining_workflows_dsl/toolbox.py +42 -0
  76. sampling_mining_workflows_dsl-0.0.1.dist-info/METADATA +236 -0
  77. sampling_mining_workflows_dsl-0.0.1.dist-info/RECORD +79 -0
  78. sampling_mining_workflows_dsl-0.0.1.dist-info/WHEEL +4 -0
  79. sampling_mining_workflows_dsl-0.0.1.dist-info/licenses/LICENSE.txt +674 -0
File without changes
@@ -0,0 +1,23 @@
1
+ from typing import TypeVar
2
+
3
+ T = TypeVar("T")
4
+
5
+
6
+ class CompleteWorkflow:
7
+ def __init__(self, workflow):
8
+ if not workflow.is_complete():
9
+ raise ValueError(
10
+ "Workflow is incomplete. Ensure it has an input, output, and at least one operator."
11
+ )
12
+ self._workflow = workflow
13
+
14
+ def execute_workflow(self):
15
+ self._workflow.execute_workflow()
16
+ return self
17
+
18
+ def analyze_workflow(self, metadata):
19
+ self._workflow.analyze_workflow(metadata)
20
+ return self
21
+
22
+ def __str__(self):
23
+ return str(self._workflow)
@@ -0,0 +1,242 @@
1
+ from typing import TypeVar, cast
2
+
3
+ from sampling_mining_workflows_dsl import CompleteWorkflow
4
+ from sampling_mining_workflows_dsl.analysis.DistributionWorkflowAnalysis import (
5
+ DistributionWorkflowAnalysis,
6
+ )
7
+ from sampling_mining_workflows_dsl.analysis.HistWorkflowAnalysis import HistWorkflowAnalysis
8
+ from sampling_mining_workflows_dsl.analysis.YamaneWorkflowAnalysis import YamaneWorkflowAnalysis
9
+ from sampling_mining_workflows_dsl.constraint.Constraint import Constraint
10
+ from sampling_mining_workflows_dsl.element.Element import Element
11
+ from sampling_mining_workflows_dsl.element.Loader import Loader
12
+ from sampling_mining_workflows_dsl.element.Set import Set
13
+ from sampling_mining_workflows_dsl.element.Writer import Writer
14
+ from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
15
+ from sampling_mining_workflows_dsl.operator.clustering.GroupingOperator import GroupingOperator
16
+ from sampling_mining_workflows_dsl.operator.Operator import Operator
17
+ from sampling_mining_workflows_dsl.operator.selection.filter.FilterOperator import FilterOperator
18
+ from sampling_mining_workflows_dsl.operator.selection.sampling.automatic.RandomSelectionOperator import (
19
+ RandomSelectionOperator,
20
+ )
21
+ from sampling_mining_workflows_dsl.operator.selection.sampling.manual.ManualSamplingOperator import (
22
+ ManualSamplingOperator,
23
+ )
24
+
25
+ T = TypeVar("T")
26
+
27
+
28
+ class Workflow:
29
+ def __init__(self):
30
+ self._input: Set | None = None
31
+ self._output: Set | None = None
32
+ self._output_writer: Writer | None = None
33
+ self._root: Operator | None = None
34
+ self._last_operator: Operator | None = None
35
+ self._metadata: list[Metadata] = []
36
+
37
+ def get_all_Metadata(self) -> list[Metadata]:
38
+ return self._metadata
39
+
40
+ def add_metadata_type(self, metadata: Metadata) -> "Workflow":
41
+ self._metadata.append(metadata)
42
+ return self
43
+
44
+ def grouping_operator(self, *workflows: "Workflow") -> "Workflow":
45
+ if not workflows:
46
+ raise ValueError("At least one workflow must be provided.")
47
+
48
+ # Create a GroupingOperator with the provided sub workflows
49
+ grouping_operator = GroupingOperator(self, *workflows)
50
+
51
+ # Add the grouping operator to the current workflow
52
+ self.add_operator(cast("Operator", grouping_operator))
53
+ return self
54
+
55
+ def random_selection_operator(self, cardinality: int, seed: int = -1) -> "Workflow":
56
+ random_selection_operator = RandomSelectionOperator(
57
+ self, cardinality=cardinality, seed=seed
58
+ )
59
+ self.add_operator(cast("Operator", random_selection_operator))
60
+ return self
61
+
62
+ def filter_operator(self, constraint: Constraint):
63
+ filter_operator = FilterOperator(self, constraint)
64
+ self.add_operator(cast("Operator", filter_operator))
65
+ return self
66
+
67
+ def manual_sampling_operator(self, *ids: T) -> "Workflow":
68
+ if not ids:
69
+ raise ValueError(
70
+ "At least one element must be provided for manual sampling."
71
+ )
72
+
73
+ manual_sampling_operator = ManualSamplingOperator(self, *ids)
74
+ self.add_operator(cast("Operator", manual_sampling_operator))
75
+ return self
76
+
77
+ def get_all_set_from_workflow(self, index=0):
78
+ sets = {}
79
+ if index==0:
80
+ sets[index] = (self._input,None)
81
+ index += 1
82
+
83
+ op = self.get_root()
84
+ while op is not None:
85
+ if not isinstance(op, GroupingOperator):
86
+ if hasattr(op, "_output") and op._output is not None:
87
+ sets[index] = (op._output,op) # Fix: use index as key, not the Set object
88
+ index += 1
89
+ else:
90
+ for internal_w in op.get_workflows():
91
+ grouping_sets = internal_w.get_all_set_from_workflow(index)
92
+ index = index + len(grouping_sets)
93
+ sets.update(grouping_sets) # Fix: use update() instead of extend()
94
+ op = op.get_next_operator()
95
+ return sets
96
+
97
+ def get_internal_set_by_index(self,index):
98
+ return self.get_all_set_from_workflow()[index]
99
+
100
+ def get_internal_set_by_id(self, set_id: str) -> Set | None:
101
+ current: Operator= self._root
102
+ while current is not None:
103
+ output:Set = current.get_output()
104
+ if not output is None and output.get_id() == set_id:
105
+ return output
106
+ if current.isinstance(GroupingOperator):
107
+ for w in current.get_workflows():
108
+ internal_set = w.get_internal_set_by_id(set_id)
109
+ if internal_set is not None:
110
+ return internal_set
111
+ current = current._next_operator
112
+ return None
113
+
114
+ def input(self, loader: Loader) -> "Workflow":
115
+ self._metadata = list(loader.metadatas.values())
116
+ self._input = loader.load_set()
117
+ return self
118
+
119
+ def add_metadata(self, loader: Loader) -> "Workflow":
120
+ # Add metadata value to last declared operator
121
+ current_operator: Operator = self.get_last_operator()
122
+ if current_operator:
123
+ current_operator.add_metadata_loader(loader)
124
+ return self
125
+
126
+ def output(self, writer: Writer) -> "Workflow":
127
+ self._output_writer = writer
128
+ last_operator = self.get_last_operator()
129
+ if last_operator:
130
+ last_operator.output(writer)
131
+ return self
132
+
133
+ def is_complete(self) -> bool:
134
+ return (
135
+ self._root is not None
136
+ and self._input is not None
137
+ and self._output_writer is not None
138
+ )
139
+
140
+ def add_operator(self, operator: Operator):
141
+ # If the workflow is empty, set the root operator
142
+ if self._root is None:
143
+ self._root = operator
144
+ self._last_operator = operator
145
+
146
+ # If the workflow already has operators, append the new operator to the end
147
+ else:
148
+ self._last_operator._next_operator = operator
149
+ operator._previous_operator = self._last_operator
150
+ operator.input_set(self._last_operator.get_output())
151
+ self._last_operator.output_set(operator.get_output())
152
+ self._last_operator = operator
153
+
154
+ if self.is_complete():
155
+ return CompleteWorkflow(self)
156
+ return None
157
+
158
+ def set_workflow_input(self, input_set: Set | None) -> "Workflow":
159
+ self._input = input_set
160
+ if self._root is not None:
161
+ self._root.input_set(input_set)
162
+ return self
163
+
164
+ def set_root_input(self, input_set: Set | None) -> "Workflow":
165
+ if self._root is None:
166
+ raise ValueError("Cannot set root input when no root operator is defined.")
167
+ self._root.input_set(input_set)
168
+ return self
169
+
170
+ def get_workflow_input(self) -> Element | None:
171
+ return self._input
172
+
173
+ def set_workflow_output(self, output_element: Element) -> "Workflow":
174
+ self._output = output_element
175
+ return self
176
+
177
+ def get_workflow_output(self) -> Set | None:
178
+ return self._output
179
+
180
+ def get_root(self) -> Operator | None:
181
+ return self._root
182
+
183
+ def get_last_operator(self) -> Operator | None:
184
+ if self._root is None:
185
+ return None
186
+ current = self._root
187
+ while current._next_operator is not None:
188
+ current = current._next_operator
189
+ return current
190
+
191
+ def get_operator_by_position(self, position: int) -> Operator | None:
192
+ if position < 0:
193
+ return None
194
+ current = self._root
195
+ index = 0
196
+ while current is not None:
197
+ if index == position:
198
+ return current
199
+ current = current._next_operator
200
+ index += 1
201
+ return None
202
+
203
+ def execute_workflow(self) -> "Workflow":
204
+ root = self._root
205
+ root.input_set(self._input)
206
+ root.execute()
207
+ self._output = self._last_operator.get_output()
208
+ return self
209
+
210
+ def print(self) -> "Workflow":
211
+ print(self)
212
+ return self
213
+
214
+ def analyze_workflow(self, metadata: Metadata[T]) -> "Workflow":
215
+ # Perform analysis on a given metadata
216
+ # workflow_analysis = HistWorkflowAnalysis(metadata)
217
+ workflow_distrib_analysis = DistributionWorkflowAnalysis(metadata=metadata)
218
+ workflow_distrib_analysis.analyze(self)
219
+
220
+ workflow_yamane_analysis = YamaneWorkflowAnalysis()
221
+ workflow_yamane_analysis.analyze(self)
222
+
223
+ workflow_hist_analysis = HistWorkflowAnalysis(metadata=metadata)
224
+ workflow_hist_analysis.analyze(self)
225
+ return self
226
+
227
+ # --- Methods for workflow printing ---
228
+
229
+ def __str__(self) -> str:
230
+ return self.to_string(0)
231
+
232
+ def to_string(self, level: int):
233
+ indent = " " * level
234
+ res = f"{indent}Workflow: [[[\n"
235
+ # res = ""
236
+ if self._root is not None:
237
+ res += self._root.to_string(level)
238
+ else:
239
+ res += f"{indent}No operators defined in this workflow.\n"
240
+
241
+ res += "\n" + indent + "]]]\n"
242
+ return res
@@ -0,0 +1,11 @@
1
+ from sampling_mining_workflows_dsl.operator.OperatorBuilder import OperatorBuilder
2
+ from sampling_mining_workflows_dsl.Workflow import Workflow
3
+
4
+
5
+ class WorkflowBuilder:
6
+ def __init__(self):
7
+ self.workflow = Workflow()
8
+
9
+ def input(self, loader) -> "OperatorBuilder":
10
+ self.workflow.input(loader)
11
+ return OperatorBuilder(self.workflow)
@@ -0,0 +1,37 @@
1
+ from collections import Counter
2
+
3
+ from scipy.stats import chisquare
4
+
5
+ from sampling_mining_workflows_dsl.element.Set import Set
6
+ from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
7
+
8
+ class ChiSquareAnalysis:
9
+ def __init__(self, metadata: Metadata[str]):
10
+ self.metadata = metadata
11
+
12
+ def analyze(self, set_1: Set, set_2: Set):
13
+ # Extract keywords from both sets
14
+ keywords_1 = self.extract_keywords(set_1)
15
+ keywords_2 = self.extract_keywords(set_2)
16
+
17
+ all_labels = sorted(set(keywords_1 + keywords_2))
18
+
19
+ pop_counts = [Counter(keywords_1).get(label, 0) for label in all_labels]
20
+ sample_counts = [Counter(keywords_2).get(label, 0) for label in all_labels]
21
+
22
+ total_pop = sum(pop_counts)
23
+ total_sample = sum(sample_counts)
24
+ scaled_pop = [x * (total_sample / total_pop) for x in pop_counts]
25
+
26
+ chi2, p = chisquare(f_obs=sample_counts, f_exp=scaled_pop)
27
+
28
+ print("Chi2:", chi2)
29
+ print("p-value:", p)
30
+
31
+ def extract_keywords(self, s: Set):
32
+ keywords = []
33
+ for element in s.get_elements():
34
+ metadata_value = element.get_metadata_value(self.metadata)
35
+ if metadata_value:
36
+ keywords.extend(metadata_value.get_value())
37
+ return keywords
@@ -0,0 +1,44 @@
1
+ import math
2
+
3
+ from sampling_mining_workflows_dsl.operator.selection.sampling.automatic.RandomSelectionOperator import RandomSelectionOperator
4
+ from scipy.stats import norm
5
+
6
+ class CochranTest:
7
+ def __init__(self, op :RandomSelectionOperator,confidence_level=0.95,margin_error=0.05,p=0.5):
8
+ self.op: RandomSelectionOperator = op
9
+ self.confidence_level=confidence_level
10
+ self.e=margin_error
11
+ self.p=p
12
+ """
13
+ Calculate sample size using Cochran's formula.
14
+
15
+ Parameters:
16
+ confidence_level (float): Confidence level (e.g. 0.95 for 95%)
17
+ p (float): Estimated proportion of the population (use 0.5 if unknown)
18
+ e (float): Margin of error (e.g. 0.05 for 5%)
19
+ population (int or None): Population size, optional for finite correction
20
+
21
+ Returns:
22
+ float: Required sample size
23
+ """
24
+ def cochran_sample_size(self):
25
+ sampling_frame_size = self.op.get_input().size()
26
+
27
+ # Get Z-value for given confidence level
28
+ z = norm.ppf(1 - (1 - self.confidence_level) / 2)
29
+
30
+ # Cochran's initial sample size
31
+ n0 = (z**2 * self.p * (1 - self.p)) / (self.e**2)
32
+
33
+ # Adjust for finite population if given
34
+ if sampling_frame_size:
35
+ n = n0 / (1 + (n0 - 1) / sampling_frame_size)
36
+ return n
37
+ else:
38
+ return n0
39
+
40
+
41
+ def is_representative(self) -> bool:
42
+ required_sample_size = self.cochran_sample_size()
43
+ sample_size = self.op.get_cardinality()
44
+ return sample_size >= required_sample_size
@@ -0,0 +1,37 @@
1
+ from sampling_mining_workflows_dsl.Workflow import Workflow
2
+ from sampling_mining_workflows_dsl.analysis.WorkflowAnalysis import WorkflowAnalysis
3
+ from sampling_mining_workflows_dsl.operator.selection.sampling.automatic.RandomSelectionOperator import RandomSelectionOperator
4
+ from sampling_mining_workflows_dsl.analysis.CochranTest import CochranTest
5
+
6
+
7
+ class CochranWorkflowAnalysis(WorkflowAnalysis):
8
+ def __init__(self,confidence_level=0.95,margin_error=0.05,p=0.5):
9
+ self.confidence_level=confidence_level
10
+ self.margin_error=margin_error
11
+ self.p=p
12
+
13
+ def analyze(self,workflow : Workflow):
14
+ #dict set_num --> (set,op)
15
+ set_op_dict = workflow.get_all_set_from_workflow()
16
+ for (set_nb,value) in set_op_dict.items():
17
+ set_,op = value
18
+ if isinstance(op,RandomSelectionOperator):
19
+ print(f"Set #{set_nb} produced by a random selection operator, checking sample size")
20
+ cochran_test = CochranTest(op,self.confidence_level,self.margin_error,self.p)
21
+ required_sample_size = cochran_test.cochran_sample_size()
22
+ actual_sample_size = op.get_cardinality()
23
+ print(f"Cochran's Test Analysis for set {set_nb}:")
24
+ print("Required Sample Size:", required_sample_size)
25
+ print("Actual Sample Size:", actual_sample_size)
26
+
27
+ if cochran_test.is_representative():
28
+ print("The sample pass Cochran's test.")
29
+ else:
30
+ print("The sample do not pass Cochran's test.")
31
+
32
+ print("------------------------------------------")
33
+
34
+
35
+
36
+
37
+
@@ -0,0 +1,60 @@
1
+ from collections import Counter
2
+
3
+ from sampling_mining_workflows_dsl.element.Set import Set
4
+ from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
5
+
6
+
7
+ class CoverageTest:
8
+ def __init__(self, metadata: Metadata, set_1: Set, set_2: Set):
9
+ self.metadata = metadata
10
+ self.set_1 = set_1
11
+ self.set_2 = set_2
12
+
13
+ def compute_coverage(self, top_x: int = None) -> float:
14
+ counter = Counter()
15
+ for element in self.set_1.get_elements():
16
+ values = element.get_metadata_value(self.metadata).get_value()
17
+ counter.update(self.flatten(values))
18
+
19
+ if top_x is not None:
20
+ top_values = {item for item, _ in counter.most_common(top_x)}
21
+ else:
22
+ top_values = set(counter.elements())
23
+
24
+ set_1_unique = {
25
+ v
26
+ for element in self.set_1.get_elements()
27
+ for v in self.flatten(element.get_metadata_value(self.metadata).get_value())
28
+ if v in top_values
29
+ }
30
+
31
+ set_2_unique = {
32
+ v
33
+ for element in self.set_2.get_elements()
34
+ for v in self.flatten(element.get_metadata_value(self.metadata).get_value())
35
+ }
36
+
37
+ if not set_1_unique:
38
+ print(
39
+ f"No value for {self.metadata.name}. Couverture = 0.0"
40
+ )
41
+ return 0.0
42
+
43
+ intersection = set_1_unique.intersection(set_2_unique)
44
+ coverage = len(intersection) / len(set_1_unique)
45
+
46
+ print(
47
+ f"Coverage for {self.metadata.name} (top {top_x if top_x is not None else 'all'}): {coverage:.2f}"
48
+ )
49
+ return coverage
50
+
51
+ def flatten(self, values):
52
+ if isinstance(values, list):
53
+ result = []
54
+ for v in values:
55
+ if isinstance(v, list):
56
+ result.extend(v)
57
+ else:
58
+ result.append(v)
59
+ return result
60
+ return [values]
@@ -0,0 +1,57 @@
1
+
2
+ from typing import TYPE_CHECKING
3
+
4
+ from sampling_mining_workflows_dsl.analysis.kolmogorov_smirnov import kolmogorov_smirnov
5
+ from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
6
+ from sampling_mining_workflows_dsl.operator.clustering.GroupingOperator import GroupingOperator
7
+
8
+ if TYPE_CHECKING:
9
+ from sampling_mining_workflows_dsl.element.Set import Set
10
+
11
+
12
+ class DistributionWorkflowAnalysis:
13
+ def __init__(self, metadata: Metadata[int]):
14
+ self.map: dict[str, Set] = {}
15
+ self.metadata = metadata
16
+
17
+ def analyze(self, workflow):
18
+ # Retrieve the root operator from the workflow
19
+ root_operator = workflow.get_root()
20
+ self.populate_map(root_operator, "")
21
+ analyzer = kolmogorov_smirnov(self.metadata)
22
+ entries = list(self.map.items())
23
+
24
+ print("Kolmogorov-Smirnov Test:")
25
+
26
+ for i in range(len(entries) - 1):
27
+ for j in range(i + 1, len(entries)):
28
+ name = f"{entries[i][0]} /// {entries[j][0]}"
29
+ result = analyzer.analyze(entries[i][1], entries[j][1])
30
+
31
+ print(name)
32
+ print(result)
33
+ print("------------------------------------------")
34
+
35
+ def populate_map(self, workflow, prefix: str):
36
+ op = workflow.get_workflow_root_operator()
37
+ self.map[f"{prefix}input"] = op.get_input()
38
+ count = 1
39
+
40
+ while op is not None:
41
+ if isinstance(op, GroupingOperator):
42
+ grouping_operator: GroupingOperator = op
43
+ self.map[f"{prefix}operator_{count}_merged"] = (
44
+ grouping_operator.get_merged_output()
45
+ )
46
+
47
+ child_count = 1
48
+ for internal_w in grouping_operator.get_workflows():
49
+ self.populate_map(
50
+ internal_w, f"{prefix}operator_{count}_Child_{child_count}_"
51
+ )
52
+ child_count += 1
53
+ else:
54
+ self.map[f"{prefix}operator_{count}"] = op.get_output()
55
+
56
+ count += 1
57
+ op = op.get_next_operator()