pymodrev 0.1.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.
Files changed (45) hide show
  1. pymodrev/__init__.py +0 -0
  2. pymodrev/__main__.py +5 -0
  3. pymodrev/asp_rules/async.lp +28 -0
  4. pymodrev/asp_rules/base.lp +17 -0
  5. pymodrev/asp_rules/complete.lp +15 -0
  6. pymodrev/asp_rules/steady_state.lp +30 -0
  7. pymodrev/asp_rules/sync.lp +20 -0
  8. pymodrev/asp_rules/time_series.lp +33 -0
  9. pymodrev/cli.py +171 -0
  10. pymodrev/configuration.py +87 -0
  11. pymodrev/network/__init__.py +0 -0
  12. pymodrev/network/edge.py +70 -0
  13. pymodrev/network/exceptions.py +27 -0
  14. pymodrev/network/function.py +455 -0
  15. pymodrev/network/inconsistency_solution.py +420 -0
  16. pymodrev/network/inconsistent_node.py +168 -0
  17. pymodrev/network/network.py +182 -0
  18. pymodrev/network/node.py +49 -0
  19. pymodrev/network/observation.py +31 -0
  20. pymodrev/network/repair_set.py +146 -0
  21. pymodrev/parsers/__init__.py +0 -0
  22. pymodrev/parsers/boolean_expression.py +563 -0
  23. pymodrev/parsers/network_parser.py +32 -0
  24. pymodrev/parsers/parser_asp.py +236 -0
  25. pymodrev/parsers/parser_bnet.py +154 -0
  26. pymodrev/parsers/parser_factory.py +31 -0
  27. pymodrev/parsers/parser_ginml.py +348 -0
  28. pymodrev/repair/__init__.py +1 -0
  29. pymodrev/repair/consistency.py +181 -0
  30. pymodrev/repair/engine.py +118 -0
  31. pymodrev/repair/function_search.py +275 -0
  32. pymodrev/repair/repair.py +52 -0
  33. pymodrev/repair/topology.py +335 -0
  34. pymodrev/updaters/__init__.py +0 -0
  35. pymodrev/updaters/async_updater.py +154 -0
  36. pymodrev/updaters/complete_updater.py +152 -0
  37. pymodrev/updaters/steady_state_updater.py +113 -0
  38. pymodrev/updaters/sync_updater.py +140 -0
  39. pymodrev/updaters/time_series_updater.py +57 -0
  40. pymodrev/updaters/updater.py +173 -0
  41. pymodrev-0.1.0.dist-info/METADATA +156 -0
  42. pymodrev-0.1.0.dist-info/RECORD +45 -0
  43. pymodrev-0.1.0.dist-info/WHEEL +5 -0
  44. pymodrev-0.1.0.dist-info/entry_points.txt +2 -0
  45. pymodrev-0.1.0.dist-info/top_level.txt +1 -0
pymodrev/__init__.py ADDED
File without changes
pymodrev/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ import sys
2
+ from pymodrev.cli import main
3
+
4
+ if __name__ == '__main__':
5
+ main()
@@ -0,0 +1,28 @@
1
+ %only one node updates at each time
2
+ 1{update(P,T,V):vertex(V)}1 :- exp(P), time(P,T), time(P,T+1).
3
+
4
+ vlabel(P,T+1,V,1) :- update(P,T,V), 1{noneNegative(P,T,V,Id):functionOr(V,Id)}, vertex(V), exp(P), not r_part(V), not topologicalerror(V), time(P,T+1).
5
+ vlabel(P,T+1,V,0) :- update(P,T,V), {noneNegative(P,T,V,Id):functionOr(V,Id)}0, vertex(V), exp(P), functionOr(V,_), not r_gen(V), not topologicalerror(V), time(P,T+1).
6
+
7
+ %keep all others
8
+ vlabel(P,T+1,V,S) :- not update(P,T,V), vlabel(P,T,V,S), time(P,T+1).
9
+
10
+ %prevent updates that do not change the state of the network
11
+ :- update(P,T,V), vlabel(P,T,V,S), vlabel(P,T+1,V,S).
12
+
13
+ %there cannot exists 2 different times with the same update, which function's inputs are the same and the output is different
14
+ %any function applied in two time points with the same inputs cannot have different outputs
15
+ %ignore this to consider topological repairs
16
+ topologicalerror(V) :- time(P1,T1), time(P2,T2), T1 != T2, time(P1,T1+1), time(P2,T2+1), update(P1, T1, V), update(P2, T2, V), {vlabel(P1,T1,V1,S1) : vlabel(P2,T2,V1,S2), functionAnd(V,Id, V1), S1!=S2}0, vlabel(P1,T1+1,V,S3), vlabel(P2,T2+1,V,S4), S3 != S4, not input(V).
17
+ topologicalerror(V) :- time(P1,T), time(P2,T), time(P1,T+1), time(P2,T+1), update(P1, T, V), update(P2, T, V), P1 != P2, {vlabel(P1,T,V1,S1) : vlabel(P2,T,V1,S2), S1!=S2, functionAnd(V,Id, V1)}0, vlabel(P1,T+1,V,S3), vlabel(P2,T+1,V,S4), S3 != S4, not input(V).
18
+
19
+ repair(V) :- topologicalerror(V).
20
+
21
+ #minimize {1@2,top,V : topologicalerror(V)}.
22
+
23
+ #show update/3.
24
+
25
+ % show inconsistent nodes per exeperiment
26
+ inc(P,V) :- vlabel(P,T+1,V,0), 1{noneNegative(P,T,V,Id):functionOr(V,Id)}, vertex(V), exp(P), r_part(V), not topologicalerror(V), time(P,T), time(P,T+1), update(P,T,V).
27
+ inc(P,V) :- vlabel(P,T+1,V,1), {noneNegative (P,T,V,Id):functionOr(V,Id)}0, vertex(V), exp(P), functionOr(V,_), r_gen(V), not topologicalerror(V), time(P,T), time(P,T+1), update(P,T,V).
28
+ #show inc/2.
@@ -0,0 +1,17 @@
1
+ sign(0;1).
2
+ complement(T,S) :- sign(S),sign(T),T!=S.
3
+
4
+ %inferring vertex from edges
5
+ vertex(V) :- edge(V,_,_).
6
+ vertex(V) :- edge(_,V,_).
7
+
8
+ % each vertex may or may not be in need of repair
9
+ {r_gen(V)} :- vertex(V), not fixed(V).
10
+ {r_part(V)} :- vertex(V), not fixed(V).
11
+
12
+ repair(V) :- r_gen(V).
13
+ repair(V) :- r_part(V).
14
+
15
+ #show repair/1.
16
+ #show r_gen/1.
17
+ #show r_part/1.
@@ -0,0 +1,15 @@
1
+ %at least one node updates at each time
2
+ 1{update(P,T,V):vertex(V)} :- exp(P), time(P,T), time(P,T+1).
3
+
4
+ vlabel(P,T+1,V,1) :- update(P,T,V), 1{noneNegative(P,T,V,Id):functionOr(V,Id)}, vertex(V), exp(P), not r_part(V), time(P,T+1).
5
+ vlabel(P,T+1,V,0) :- update(P,T,V), {noneNegative(P,T,V,Id):functionOr(V,Id)}0, vertex(V), exp(P), functionOr(V,_), not r_gen(V), time(P,T+1).
6
+
7
+ %keep all others
8
+ vlabel(P,T+1,V,S) :- not update(P,T,V), vlabel(P,T,V,S), time(P,T+1).
9
+
10
+ #show update/3.
11
+
12
+ % show inconsistent nodes per exeperiment
13
+ inc(P,V) :- vlabel(P,T+1,V,0), 1{noneNegative(P,T,V,Id):functionOr(V,Id)}, vertex(V), exp(P), r_part(V), time(P,T), time(P,T+1), update(P,T,V).
14
+ inc(P,V) :- vlabel(P,T+1,V,1), {noneNegative (P,T,V,Id):functionOr(V,Id)}0, vertex(V), exp(P), functionOr(V,_), r_gen(V), time(P,T), time(P,T+1), update(P,T,V).
15
+ #show inc/2.
@@ -0,0 +1,30 @@
1
+ %guarantee of stable state observation
2
+ ss(P) :- exp(P), not time(P,_).
3
+
4
+ %generate
5
+ 1{vlabel(P,V,S):sign(S)}1 :- vertex(V), ss(P).
6
+
7
+ :-vlabel(P,V,S1), obs_vlabel(P,V,S2),complement(S1,S2).
8
+
9
+ % functions
10
+ % one positive or negative contribution in a clause
11
+ onePositive(P,V,Id) :- functionAnd(V,Id, V2), edge(V2,V,S), vlabel(P,V2,S), ss(P).
12
+ oneNegative(P,V,Id) :- functionAnd(V,Id, V2), edge(V2,V,S), vlabel(P,V2,T), complement(S,T), ss(P).
13
+
14
+ % none positive or none negative on a clause
15
+ % nonePositive(V,Id) :- not onePositive(V,Id), oneNegative(V,Id).
16
+ noneNegative(P,V,Id) :- onePositive(P,V,Id), not oneNegative(P,V,Id).
17
+
18
+ vlabel(P,V,1) :- 1{noneNegative(P,V,Id):functionOr(V,Id)}, vertex(V), ss(P), not r_part(V).
19
+ vlabel(P,V,0) :- {noneNegative(P,V,Id):functionOr(V,Id)}0, vertex(V), ss(P), functionOr(V,_), not r_gen(V).
20
+
21
+ #minimize {1,V : repair(V)}.
22
+ #minimize {1,g,V : r_gen(V)}.
23
+ #minimize {1,p,V : r_part(V)}.
24
+
25
+ #show vlabel/3.
26
+
27
+ % show inconsistent nodes per experiments
28
+ inc(P,V) :- vlabel(P,V,0), 1{noneNegative(P,V,Id):functionOr(V,Id)}, vertex(V), ss(P), r_part(V).
29
+ inc(P,V) :- vlabel(P,V,1), {noneNegative(P,V ,Id):functionOr(V,Id)}0, vertex(V), ss(P), functionOr(V,_), r_gen(V).
30
+ #show inc/2.
@@ -0,0 +1,20 @@
1
+ vlabel(P,T+1,V,1) :- 1{noneNegative(P,T,V,Id):functionOr(V,Id)}, vertex(V), exp(P), not r_part(V), not topologicalerror(V), time(P,T), time(P,T+1).
2
+ vlabel(P,T+1,V,0) :- {noneNegative(P,T,V,Id):functionOr(V,Id)}0, vertex(V), exp(P), functionOr(V,_), not r_gen(V), not topologicalerror(V), time(P,T), time(P,T+1).
3
+
4
+ %there cannot exists 2 different times with the same update, which function's inputs are the same and the output is different
5
+ %any function applied in two time points with the same inputs cannot have different outputs
6
+ %ignore this to consider topological repairs
7
+ topologicalerror(V) :- time(P1,T1), time(P2,T2), T1 != T2, time(P1,T1+1), time(P2,T2+1), vertex(V), {vlabel(P1,T1,V1,S1): vlabel(P2,T2,V1,S2), S1!=S2, functionAnd(V,Id, V1)}0, vlabel(P1,T1+1,V,S3), vlabel(P2,T2+1,V,S4), S3 != S4, not input(V).
8
+ topologicalerror(V) :- time(P1,T), time(P2,T), time(P1,T+1), time(P2,T+1), exp(P1), exp(P2), P1 != P2, vertex(V), {vlabel(P1,T,V1,S1): vlabel(P2,T,V1,S2), S1!=S2, functionAnd(V,Id, V1)}0, vlabel(P1,T+1,V,S3), vlabel(P2,T+1,V,S4), S3 != S4, not input(V).
9
+
10
+ repair(V) :- topologicalerror(V).
11
+
12
+ #minimize {1@2,top,V : topologicalerror(V)}.
13
+ #show topologicalerror/1.
14
+
15
+ % show inconsistent nodes per exeperiment
16
+ inc(P,V) :- vlabel(P,T+1,V,0), 1{noneNegative(P,T,V,Id):functionOr(V,Id)}, vertex(V), exp(P), r_part(V), not topologicalerror(V), time(P,T), time(P,T+1).
17
+ inc(P,V) :- vlabel(P,T+1,V,1), {noneNegative (P,T,V,Id):functionOr(V,Id)}0, vertex(V), exp(P), functionOr(V,_), r_gen(V), not topologicalerror(V), time(P,T), time(P,T+1).
18
+ incT(P1,P2,V) :- time(P1,T1), time(P2,T2), T1!= T2, time(P1,T1+1), time(P2,T2+1), vertex(V), {vlabel( P1,T1,V1,S1): vlabel(P2,T2,V1,S2), S1!=S2, functionAnd(V, Id, V1)}0, vlabel(P1,T1+1,V,S3), vlabel(P2,T2+1,V,S4), S3 != S4, not input(V), P1 <= P2.
19
+ #show inc/2.
20
+ #show incT/3.
@@ -0,0 +1,33 @@
1
+ %time control per experiment
2
+ time(P,T) :- exp(P), obs_vlabel(P,T,_,_).
3
+ time(P,T) :- time(P,T+1), T+1 > 0.
4
+
5
+ %generate
6
+ 1{vlabel(P,T,V,S):sign(S)}1:-vertex(V), exp(P), time(P,T).
7
+
8
+ :-vlabel(P,T,V,S1), obs_vlabel(P,T,V,S2), complement(S1,S2).
9
+
10
+ % functions
11
+ %one positive or negative contribution in a clause
12
+ onePositive(P,T,V,Id) :- functionAnd(V,Id, V2), edge(V2,V,S), vlabel(P,T,V2,S), exp(P), time(P,T).
13
+ oneNegative(P,T,V,Id) :- functionAnd(V,Id, V2), edge(V2,V,S1), vlabel(P,T,V2,S2), complement(S1,S2), exp(P), time(P,T).
14
+
15
+ % none negative on a clause
16
+ noneNegative(P,T,V,Id) :- onePositive(P,T,V,Id), not oneNegative(P,T,V,Id).
17
+
18
+ %input nodes
19
+ input(V) :- not functionOr(V,_), vertex(V).
20
+
21
+ vlabel(P,T+1,V,0) :- input(V), vlabel(P,T,V,0), exp(P), time(P,T+1), not r_gen(V).
22
+ vlabel(P,T+1,V,1) :- input(V), vlabel(P,T,V,1), exp(P), time(P,T+1), not r_part(V).
23
+
24
+
25
+ #minimize {1@1,V : repair(V)}.
26
+ #minimize {1@1,g,V : r_gen(V)}.
27
+ #minimize {1@1,p,V : r_part(V)}.
28
+ #show vlabel/4.
29
+
30
+ % show inconsistent nodes per exeperiment
31
+ inc(P,V) :- vlabel(P,T+1,V,1), input(V), vlabel(P,T,V,0), exp(P), time(P,T+1), r_gen(V).
32
+ inc(P,V) :- vlabel(P,T+1,V,0), input(V), vlabel(P,T,V,1), exp(P), time(P,T+1), r_part(V).
33
+ #show inc/2.
pymodrev/cli.py ADDED
@@ -0,0 +1,171 @@
1
+ """
2
+ This script analyzes a given network model to determine its consistency.
3
+ If inconsistencies are found, it attempts to compute the minimal set of repair
4
+ operations needed to restore consistency.
5
+ """
6
+
7
+ import argparse
8
+ import sys
9
+ import os
10
+ import logging
11
+
12
+ from importlib import util
13
+ from pymodrev.network.network import Network
14
+ from pymodrev.parsers.parser_factory import get_parser
15
+ from pymodrev.configuration import config
16
+ from pymodrev.repair.engine import model_revision
17
+ from pymodrev.repair.consistency import check_consistency
18
+ from pymodrev.repair.engine import print_consistency
19
+ from pymodrev.repair.repair import apply_repair
20
+
21
+ # Configure logger
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def process_arguments(network: Network) -> None:
26
+ """
27
+ Process command-line arguments and configure network accordingly.
28
+ """
29
+ parser = argparse.ArgumentParser(
30
+ description="Model Revision program. Given a model and a set of observations, it determines if the model is consistent. If not, it computes all the minimum number of repair operations in order to render the model consistent.",
31
+ formatter_class=argparse.RawTextHelpFormatter,
32
+ epilog=f"Version: {config.version}"
33
+ )
34
+
35
+ parser.add_argument("-m", "--model",
36
+ required=True, help="Input model file.")
37
+ parser.add_argument("-obs", "--observations", nargs='+',
38
+ required=True, metavar=('OBS', 'UPDATER'),
39
+ help="""List of observation files and updater pairs.
40
+ Each observation must be followed by its updater type.
41
+ Example: -obs obs1.lp asyncupdater obs2.lp syncupdater""")
42
+ parser.add_argument('-t', '--task', choices=['c', 'r', 'm'], required=True,
43
+ help="""Specify the task to perform (default=r):
44
+ c - check for consistency
45
+ r - get repairs
46
+ m - get repaired models""")
47
+ parser.add_argument("--exhaustive-search", action="store_true",
48
+ help="Force exhaustive search of function repair operations (default=false).")
49
+ parser.add_argument("--sub-opt", action="store_true",
50
+ help="Show sub-optimal solutions found (default=false).")
51
+ parser.add_argument("--all-opt", action="store_true",
52
+ help="""Computes all optimal solutions (default=true).
53
+ Stops at first optimal solution if false.""")
54
+ parser.add_argument("-v", "--verbose", type=int, choices=[0, 1, 2], default=2,
55
+ help="""Specify output verbose level (default=2):
56
+ 0 - compact format
57
+ 1 - json format
58
+ 2 - human-readable format""")
59
+ parser.add_argument("-d", "--debug", action="store_true", help="Enable debug mode.")
60
+
61
+ args = parser.parse_args()
62
+
63
+ # Apply arguments to config and network
64
+ network.input_file_network = args.model
65
+ config.task = args.task
66
+ config.force_optimum = args.exhaustive_search
67
+ config.show_solution_for_each_inconsistency = args.sub_opt
68
+ config.verbose = args.verbose
69
+ config.debug = args.debug
70
+
71
+ # Activate debug mode
72
+ if args.debug:
73
+ logging.basicConfig(level=logging.DEBUG, format='%(name)s - %(levelname)s: %(message)s')
74
+
75
+ obs_args = args.observations
76
+ if len(obs_args) % 2 != 0:
77
+ parser.error("Expected an even number of arguments for -obs (pairs of obs_file and updater_name)")
78
+
79
+ # Load updaters dynamically from updaters/ directory
80
+ updaters = {}
81
+ updater_dir = os.path.join(os.path.dirname(__file__), "updaters")
82
+ for filename in os.listdir(updater_dir):
83
+ if filename.endswith(".py") and filename not in ("__init__.py", "updater.py", "time_series_updater.py"):
84
+ module_name = os.path.splitext(filename)[0]
85
+ class_name = "".join(word.capitalize() for word in module_name.split("_"))
86
+ file_path = os.path.join(updater_dir, filename)
87
+ # Load module dynamically
88
+ spec = util.spec_from_file_location(module_name, file_path)
89
+ module = util.module_from_spec(spec)
90
+ spec.loader.exec_module(module)
91
+ # Get class from module
92
+ updater_class = getattr(module, class_name)()
93
+ # Add class to updaters dictionary
94
+ updaters[module_name.replace('_','')] = updater_class
95
+
96
+ for i in range(0, len(obs_args), 2):
97
+ obs_path = obs_args[i]
98
+ updater_name = obs_args[i+1]
99
+
100
+ try:
101
+ network.add_observation_file(obs_path)
102
+ if updater_name not in updaters:
103
+ raise Exception(f"Updater '{updater_name}' not found in updaters directory")
104
+ network.add_updater(updaters[updater_name])
105
+ if updater_name == 'steadystateupdater':
106
+ network.has_ss_obs = True
107
+ else:
108
+ network.has_ts_obs = True
109
+ except Exception as e:
110
+ parser.error(str(e))
111
+
112
+ def main():
113
+ network = Network()
114
+ process_arguments(network)
115
+
116
+ # Delegate parsing to the correct reader based on file extension
117
+ try:
118
+ parser = get_parser(network.input_file_network)
119
+ parse = parser.read(network, network.input_file_network)
120
+ except ValueError as e:
121
+ logger.error(str(e))
122
+ sys.exit(1)
123
+
124
+ if parse < 1 and not config.ignore_warnings:
125
+ logger.error('Model definition with errors. Check documentation for input definition details.')
126
+ sys.exit(1)
127
+
128
+ # Check consistency
129
+ f_inconsistencies, optimization = check_consistency(network)
130
+ if config.task == 'c' or optimization == 0:
131
+ print_consistency(f_inconsistencies, optimization)
132
+ sys.exit(0)
133
+
134
+ # Model revision
135
+ repairs2apply = model_revision(network, f_inconsistencies, optimization)
136
+ if config.task == 'm':
137
+ import copy
138
+ import itertools
139
+
140
+ # 1. Collect all possible model combinations (Cartesian product of repair sets per solution)
141
+ all_models_to_save = []
142
+ for repair_sol in repairs2apply:
143
+ nodes_with_repairs = []
144
+ # Sort node IDs for deterministic output order
145
+ for node_id in sorted(repair_sol.inconsistent_nodes.keys()):
146
+ i_node = repair_sol.inconsistent_nodes[node_id]
147
+ if i_node.repair_sets:
148
+ node_options = [(node_id, rs) for rs in i_node.repair_sets]
149
+ nodes_with_repairs.append(node_options)
150
+
151
+ # Cartesian product of options across all nodes for THIS solution
152
+ for combination in itertools.product(*nodes_with_repairs):
153
+ node_repair_map = dict(combination)
154
+ all_models_to_save.append((repair_sol, node_repair_map))
155
+
156
+ # 2. Apply repairs and write files
157
+ total_models = len(all_models_to_save)
158
+ if total_models == 0:
159
+ logger.info("No repaired models to generate.")
160
+ else:
161
+ padding = len(str(total_models))
162
+ prefix, ext = os.path.splitext(network.input_file_network)
163
+ for i, (repair_sol, node_repair_map) in enumerate(all_models_to_save):
164
+ newNetwork = copy.deepcopy(network)
165
+ apply_repair(newNetwork, repair_sol, node_repair_map)
166
+ filename = f"{prefix}_{str(i+1).zfill(padding)}{ext}"
167
+ parser.write(newNetwork, filename)
168
+ print(f"Generated repaired model: {filename}")
169
+
170
+ if __name__ == '__main__':
171
+ main()
@@ -0,0 +1,87 @@
1
+ """
2
+ This module defines enumerations and configuration settings for handling
3
+ inconsistencies and update types in a network analysis system.
4
+ """
5
+
6
+ from enum import Enum
7
+ from dataclasses import dataclass
8
+
9
+ class Inconsistencies(Enum):
10
+ """
11
+ Enumeration representing different levels of inconsistencies in the system.
12
+
13
+ Attributes:
14
+ CONSISTENT (int): No inconsistency detected.
15
+ SINGLE_INC_GEN (int): A general single inconsistency.
16
+ SINGLE_INC_PART (int): A partial single inconsistency.
17
+ DOUBLE_INC (int): A double inconsistency.
18
+ """
19
+ CONSISTENT = (0, "No inconsistency detected")
20
+ SINGLE_INC_GEN = (1, "General single inconsistency")
21
+ SINGLE_INC_PART = (2, "Partial single inconsistency")
22
+ DOUBLE_INC = (3, "Double inconsistency")
23
+
24
+ def __init__(self, int_val, description):
25
+ self._value_ = int_val
26
+ self.description = description
27
+ def __str__(self):
28
+ return f"{self.name} ({self.value}): {self.description}"
29
+
30
+
31
+ class UpdateType(Enum):
32
+ """
33
+ Enumeration representing the types of update strategies that can be used.
34
+
35
+ Attributes:
36
+ ASYNC (int): Asynchronous update strategy.
37
+ SYNC (int): Synchronous update strategy.
38
+ MASYNC (int): Mixed asynchronous update strategy.
39
+ """
40
+ ASYNC = (0, "Asynchronous update strategy")
41
+ SYNC = (1, "Synchronous update strategy")
42
+ MASYNC = (2, "Mixed asynchronous update strategy")
43
+
44
+ def __init__(self, int_val, description):
45
+ self._value_ = int_val
46
+ self.description = description
47
+ def __str__(self):
48
+ return f"{self.name} ({self.value}): {self.description}"
49
+
50
+
51
+ import importlib.metadata
52
+
53
+ try:
54
+ _package_version = importlib.metadata.version('pymodrev')
55
+ except Exception:
56
+ _package_version = '1.0.0-dev'
57
+
58
+ @dataclass
59
+ class Configuration:
60
+ """Class representing the configuration settings for the system"""
61
+ name: str = 'pyModRev'
62
+ version: str = _package_version
63
+ task: str = 'r' # default is show the repairs
64
+ verbose: int = 2 # default is human-readable format
65
+ update: UpdateType = UpdateType.ASYNC # Setting the update type to ASYNC
66
+ debug: bool = False
67
+ check_asp: bool = True # Use ASP consistency check program
68
+ function_asp: bool = True # Use ASP function program
69
+ all_opt: bool = True # Show one or more solutions
70
+ labelling: bool = False
71
+ multiple_profiles: bool = True
72
+ compare_level_function: bool = True
73
+ exact_middle_function_determination: bool = True
74
+ ignore_warnings: bool = False
75
+ force_optimum: bool = False
76
+ show_solution_for_each_inconsistency: bool = False # Show best solution for each consistency check even if it is not globally optimum
77
+ show_all_functions: bool = True # Show all function repairs for a given node
78
+ check_consistency: bool = False # Just check the consistency of the model and return
79
+
80
+ def __getitem__(self, key):
81
+ return getattr(self, key)
82
+
83
+ def __setitem__(self, key, value):
84
+ setattr(self, key, value)
85
+
86
+
87
+ config = Configuration()
File without changes
@@ -0,0 +1,70 @@
1
+ """
2
+ This module defines the Edge class, which represents a connection between two
3
+ nodes in a network.
4
+ The Edge class provides methods to manage and query the properties of the edge,
5
+ such as its start node, end node, sign, and whether it is fixed.
6
+ """
7
+
8
+ from pymodrev.network.node import Node
9
+
10
+
11
+ class Edge:
12
+ """
13
+ Represents an edge in a network, connecting two nodes with a specific sign.
14
+ Provides methods to manage and query the edge's properties.
15
+ """
16
+
17
+ def __init__(self, start_node: Node, end_node: Node, sign: int) -> None:
18
+ """
19
+ Initializes an edge with a start node, end node, and sign.
20
+ """
21
+ self._start_node = start_node
22
+ self._end_node = end_node
23
+ self._sign = sign
24
+ self._fixed = False
25
+
26
+ @property
27
+ def start_node(self) -> Node:
28
+ """Returns the start node of the edge."""
29
+ return self._start_node
30
+
31
+ @property
32
+ def end_node(self) -> Node:
33
+ """Returns the end node of the edge."""
34
+ return self._end_node
35
+
36
+ @property
37
+ def sign(self) -> int:
38
+ """Returns the sign of the edge."""
39
+ return self._sign
40
+
41
+ @sign.setter
42
+ def sign(self, value: int):
43
+ """Sets the sign of the edge."""
44
+ self._sign = value
45
+
46
+ @property
47
+ def fixed(self) -> bool:
48
+ """Returns whether the edge is fixed."""
49
+ return self._fixed
50
+
51
+ @fixed.setter
52
+ def fixed(self, value: bool):
53
+ """Sets whether the edge is fixed."""
54
+ self._fixed = value
55
+
56
+ def flip_sign(self) -> None:
57
+ """
58
+ Flips the sign of the edge (from 0 to 1 or from 1 to 0).
59
+ """
60
+ self.sign = 1 if self.sign == 0 else 0
61
+
62
+ def __eq__(self, other) -> bool:
63
+ if not isinstance(other, Edge):
64
+ return False
65
+ return self.start_node == other.start_node and \
66
+ self.end_node == other.end_node and \
67
+ self.sign == other.sign
68
+
69
+ def __hash__(self) -> int:
70
+ return hash((self.start_node, self.end_node, self.sign))
@@ -0,0 +1,27 @@
1
+ """
2
+ This module defines custom exception classes for the pyModRev system.
3
+ """
4
+
5
+ class PyModRevError(Exception):
6
+ """Base class for exceptions in this module."""
7
+ pass
8
+
9
+ class NetworkError(PyModRevError):
10
+ """Exception raised for errors related to network structure."""
11
+ pass
12
+
13
+ class EdgeNotFoundError(NetworkError):
14
+ """Exception raised when an edge is not found in the network."""
15
+ pass
16
+
17
+ class ParseError(PyModRevError):
18
+ """Exception raised for errors during network or observation file parsing."""
19
+ pass
20
+
21
+ class SolverError(PyModRevError):
22
+ """Exception raised when the ASP solver encounters an error or impossibility."""
23
+ pass
24
+
25
+ class ConfigurationError(PyModRevError):
26
+ """Exception raised for invalid configurations or command-line arguments."""
27
+ pass