gnps 0.0.0__tar.gz

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 (49) hide show
  1. gnps-0.0.0/PKG-INFO +78 -0
  2. gnps-0.0.0/README.md +63 -0
  3. gnps-0.0.0/pyproject.toml +104 -0
  4. gnps-0.0.0/src/gnps/__init__.py +3 -0
  5. gnps-0.0.0/src/gnps/__main__.py +4 -0
  6. gnps-0.0.0/src/gnps/_version.py +1 -0
  7. gnps-0.0.0/src/gnps/cell.py +26 -0
  8. gnps-0.0.0/src/gnps/cli.py +89 -0
  9. gnps-0.0.0/src/gnps/cli_transform.py +134 -0
  10. gnps-0.0.0/src/gnps/parser/__init__.py +6 -0
  11. gnps-0.0.0/src/gnps/parser/ast/__init__.py +31 -0
  12. gnps-0.0.0/src/gnps/parser/ast/boolean_expression.py +151 -0
  13. gnps-0.0.0/src/gnps/parser/ast/expression.py +243 -0
  14. gnps-0.0.0/src/gnps/parser/ast/value/__init__.py +4 -0
  15. gnps-0.0.0/src/gnps/parser/ast/value/array_value.py +62 -0
  16. gnps-0.0.0/src/gnps/parser/ast/value/base_value.py +33 -0
  17. gnps-0.0.0/src/gnps/parser/ast/value/float_value.py +43 -0
  18. gnps-0.0.0/src/gnps/parser/ast/value/math_functions.py +126 -0
  19. gnps-0.0.0/src/gnps/parser/ast/value/numerical_value.py +313 -0
  20. gnps-0.0.0/src/gnps/parser/ast/variable.py +16 -0
  21. gnps-0.0.0/src/gnps/parser/parser.py +215 -0
  22. gnps-0.0.0/src/gnps/rule.py +24 -0
  23. gnps-0.0.0/src/gnps/system.py +146 -0
  24. gnps-0.0.0/src/gnps/transformers/__init__.py +6 -0
  25. gnps-0.0.0/src/gnps/transformers/base_transformer.py +51 -0
  26. gnps-0.0.0/src/gnps/transformers/python_transformer.py +475 -0
  27. gnps-0.0.0/tests/__init__.py +0 -0
  28. gnps-0.0.0/tests/functional_tests/sequence_test.py +39 -0
  29. gnps-0.0.0/tests/functional_tests/test_example1.py +46 -0
  30. gnps-0.0.0/tests/functional_tests/test_example1.yaml +14 -0
  31. gnps-0.0.0/tests/functional_tests/test_example1a.py +28 -0
  32. gnps-0.0.0/tests/functional_tests/test_example2.yaml +27 -0
  33. gnps-0.0.0/tests/functional_tests/test_example2_all_operators.py +23 -0
  34. gnps-0.0.0/tests/functional_tests/test_math_functions.py +141 -0
  35. gnps-0.0.0/tests/functional_tests/test_math_functions.yaml +31 -0
  36. gnps-0.0.0/tests/unit_tests/__init__.py +0 -0
  37. gnps-0.0.0/tests/unit_tests/test_array_value.py +111 -0
  38. gnps-0.0.0/tests/unit_tests/test_boolean_expression.py +132 -0
  39. gnps-0.0.0/tests/unit_tests/test_expression.py +171 -0
  40. gnps-0.0.0/tests/unit_tests/test_function_call.py +334 -0
  41. gnps-0.0.0/tests/unit_tests/test_system.py +36 -0
  42. gnps-0.0.0/tests/unit_tests/test_value.py +114 -0
  43. gnps-0.0.0/tests/unit_tests/transformers/__init__.py +2 -0
  44. gnps-0.0.0/tests/unit_tests/transformers/test_base_transformer.py +135 -0
  45. gnps-0.0.0/tests/unit_tests/transformers/test_cli_transform.py +221 -0
  46. gnps-0.0.0/tests/unit_tests/transformers/test_final_coverage.py +154 -0
  47. gnps-0.0.0/tests/unit_tests/transformers/test_python_transformer.py +597 -0
  48. gnps-0.0.0/tests/unit_tests/transformers/test_remaining_coverage.py +253 -0
  49. gnps-0.0.0/tests/unit_tests/transformers/test_transformers_init.py +25 -0
gnps-0.0.0/PKG-INFO ADDED
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.1
2
+ Name: gnps
3
+ Version: 0.0.0
4
+ Summary: Generalized Numerical P Systems simulator package
5
+ Author-Email: Sergey Verlan <dont-spam-me@no.spam>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Development Status :: 4 - Beta
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: lark~=1.1
13
+ Requires-Dist: PyYAML~=6.0
14
+ Description-Content-Type: text/markdown
15
+
16
+ # GNPS project
17
+
18
+ The *GNPS* project (Generalized Numerical P Systems) aims to create a
19
+ library for simulation of different variants of Numerical P Systems (NPS).
20
+
21
+ It contains:
22
+
23
+ * GNPS core (the core classes for NPS simulation)
24
+ * GNPS parser (parsers for different inputs)
25
+ * GNPS generator (generates outputs, i.e. Verilog, Amaranth and Lustre) *work in progress.*
26
+ * Utils (like the main runner)
27
+
28
+ ## Input Files
29
+
30
+ - **System description**: YAML file describing the GNPS system (required as the first argument).
31
+ - **Input file**: Optional CSV file, each row representing input variable values for a simulation step. The header must match the input variable names defined in the YAML.
32
+ - **Output file**: Optional CSV file, each row representing output variable values for each step.
33
+
34
+ ## Command Line Options
35
+
36
+ Run the simulator with:
37
+
38
+ python -m gnps <gnps_file.yaml> [input.csv] [output.csv] [options]
39
+
40
+ Options:
41
+ - `-c`, `--compute_mode` Run in continuous compute mode (no input variables allowed)
42
+ - `-s`, `--steps N` Number of steps to run (default: 1)
43
+ - `--csv` Output in CSV format in continuous compute mode
44
+
45
+ - `gnps_file` (YAML): Required. GNPS system description.
46
+ - `input` (CSV): Optional. Input values per step (default: stdin).
47
+ - `output` (CSV): Optional. Output values per step (default: stdout).
48
+
49
+ ## Modes
50
+
51
+ - **IO mode (default)**: Reads input variables from CSV for each step, writes output variables for each step.
52
+ - **Continuous compute mode**: Runs for a set number of steps without input variables, outputs results at each step (CSV or text).
53
+
54
+ ## Example Input YAML
55
+
56
+ Below is an example of a GNPS system description in YAML format (from `test_math_functions.yaml`):
57
+
58
+ ```yaml
59
+ description: "A test system"
60
+
61
+ cells:
62
+ - id: 1
63
+ contents:
64
+ - x = 0, y = 0, E = 0, z = 0, u = 1
65
+ # Comments can be added like this
66
+ # input variables should be empty for continuous compute mode
67
+ input: [u]
68
+ output: [x,y,z]
69
+
70
+ rules:
71
+ - E > x | x + 3 -> x # guarded rule
72
+ - E + 1 -> E # unguarded rule
73
+ - 0*z + x + y -> z
74
+ - (E > u || E > x || E > y) | u + x + y -> y # step will be reset to 0
75
+ ```
76
+
77
+
78
+ For more details, see the CHANGELOG.md and documentation in the docs/ folder.
gnps-0.0.0/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # GNPS project
2
+
3
+ The *GNPS* project (Generalized Numerical P Systems) aims to create a
4
+ library for simulation of different variants of Numerical P Systems (NPS).
5
+
6
+ It contains:
7
+
8
+ * GNPS core (the core classes for NPS simulation)
9
+ * GNPS parser (parsers for different inputs)
10
+ * GNPS generator (generates outputs, i.e. Verilog, Amaranth and Lustre) *work in progress.*
11
+ * Utils (like the main runner)
12
+
13
+ ## Input Files
14
+
15
+ - **System description**: YAML file describing the GNPS system (required as the first argument).
16
+ - **Input file**: Optional CSV file, each row representing input variable values for a simulation step. The header must match the input variable names defined in the YAML.
17
+ - **Output file**: Optional CSV file, each row representing output variable values for each step.
18
+
19
+ ## Command Line Options
20
+
21
+ Run the simulator with:
22
+
23
+ python -m gnps <gnps_file.yaml> [input.csv] [output.csv] [options]
24
+
25
+ Options:
26
+ - `-c`, `--compute_mode` Run in continuous compute mode (no input variables allowed)
27
+ - `-s`, `--steps N` Number of steps to run (default: 1)
28
+ - `--csv` Output in CSV format in continuous compute mode
29
+
30
+ - `gnps_file` (YAML): Required. GNPS system description.
31
+ - `input` (CSV): Optional. Input values per step (default: stdin).
32
+ - `output` (CSV): Optional. Output values per step (default: stdout).
33
+
34
+ ## Modes
35
+
36
+ - **IO mode (default)**: Reads input variables from CSV for each step, writes output variables for each step.
37
+ - **Continuous compute mode**: Runs for a set number of steps without input variables, outputs results at each step (CSV or text).
38
+
39
+ ## Example Input YAML
40
+
41
+ Below is an example of a GNPS system description in YAML format (from `test_math_functions.yaml`):
42
+
43
+ ```yaml
44
+ description: "A test system"
45
+
46
+ cells:
47
+ - id: 1
48
+ contents:
49
+ - x = 0, y = 0, E = 0, z = 0, u = 1
50
+ # Comments can be added like this
51
+ # input variables should be empty for continuous compute mode
52
+ input: [u]
53
+ output: [x,y,z]
54
+
55
+ rules:
56
+ - E > x | x + 3 -> x # guarded rule
57
+ - E + 1 -> E # unguarded rule
58
+ - 0*z + x + y -> z
59
+ - (E > u || E > x || E > y) | u + x + y -> y # step will be reset to 0
60
+ ```
61
+
62
+
63
+ For more details, see the CHANGELOG.md and documentation in the docs/ folder.
@@ -0,0 +1,104 @@
1
+ [build-system]
2
+ requires = [
3
+ "pdm-backend",
4
+ ]
5
+ build-backend = "pdm.backend"
6
+
7
+ [project]
8
+ name = "gnps"
9
+ dynamic = []
10
+ authors = [
11
+ { name = "Sergey Verlan", email = "dont-spam-me@no.spam" },
12
+ ]
13
+ description = "Generalized Numerical P Systems simulator package"
14
+ readme = "README.md"
15
+ dependencies = [
16
+ "lark~=1.1",
17
+ "PyYAML~=6.0",
18
+ ]
19
+ requires-python = ">=3.10"
20
+ classifiers = [
21
+ "Programming Language :: Python :: 3",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Operating System :: OS Independent",
24
+ "Development Status :: 4 - Beta",
25
+ ]
26
+ version = "0.0.0"
27
+
28
+ [project.license]
29
+ text = "MIT"
30
+
31
+ [project.scripts]
32
+ gnps = "gnps.__main__:main"
33
+ gnps-transformer = "gnps.cli_transform:main"
34
+
35
+ [tool.pdm]
36
+ autoexport = [
37
+ { filename = "requirements.txt", without-hashes = true },
38
+ ]
39
+
40
+ [tool.pdm.version]
41
+ source = "scm"
42
+ fallback_version = "0.0.0"
43
+ tag_filter = "v*"
44
+ tag_regex = "^v(.*)$"
45
+ write_to = "gnps/_version.py"
46
+ write_template = "__version__ = '{}'"
47
+
48
+ [tool.pdm.scripts]
49
+ test = "pytest --cov=gnps --cov-report=xml --cov-report=term-missing"
50
+
51
+ [tool.coverage.run]
52
+ branch = true
53
+ source = [
54
+ "src/gnps/",
55
+ "tests/",
56
+ ]
57
+ omit = [
58
+ "*/__main__.py",
59
+ "*/_version.py",
60
+ "venv/*",
61
+ "cli.py",
62
+ ]
63
+
64
+ [tool.coverage.report]
65
+ show_missing = true
66
+ skip_covered = true
67
+ omit = [
68
+ "*/__main__.py",
69
+ "*/_version.py",
70
+ "cli.py",
71
+ "venv/*",
72
+ ]
73
+ exclude_also = [
74
+ "if __name__ == .__main__.:",
75
+ ]
76
+ exclude_lines = [
77
+ "pragma: no cover",
78
+ "if __name__ == .__main__.:",
79
+ "def __repr__",
80
+ "def __str__",
81
+ "raise NotImplementedError",
82
+ ]
83
+ ignore_errors = true
84
+
85
+ [tool.coverage.html]
86
+ directory = "coverage_html_report"
87
+
88
+ [tool.pytest.ini_options]
89
+ minversion = "6.0"
90
+ pythonpath = [
91
+ "src/",
92
+ ]
93
+ testpaths = [
94
+ "tests/unit_tests/",
95
+ "tests/functional_tests/",
96
+ ]
97
+
98
+ [dependency-groups]
99
+ dev = [
100
+ "pytest>=7.4.3",
101
+ "sphinx>=7.2.6",
102
+ "pytest-cov>=7.0.0",
103
+ "sphinx-rtd-theme>=3.0.2",
104
+ ]
@@ -0,0 +1,3 @@
1
+ from .cell import Cell
2
+ from .rule import Rule
3
+ from .system import GnpsSystem
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == '__main__':
4
+ main()
@@ -0,0 +1 @@
1
+ __version__ = '0.0.0'
@@ -0,0 +1,26 @@
1
+ from .parser.ast.variable import Variable
2
+
3
+
4
+ class Cell:
5
+ """
6
+ The class representing a cell.
7
+
8
+ :param id: The id of the cell.
9
+ :type id: int
10
+
11
+ :param contents: The contents of the cell. It is a dictionary of variables.
12
+ :type contents: dict[str, Variable]
13
+ """
14
+ id: int
15
+ contents: dict[str, Variable]
16
+
17
+ def __init__(self, cell_id: int, contents: dict[str, Variable]):
18
+ """
19
+ Initialize a cell.
20
+ :param cell_id: the cell id
21
+ :type cell_id: int
22
+ :param contents: the contents of the cell (a dictionary of variables)
23
+ :type contents: dict[str, Variable]
24
+ """
25
+ self.id = cell_id
26
+ self.contents = contents
@@ -0,0 +1,89 @@
1
+ import argparse
2
+ import csv
3
+ import sys
4
+ from typing import Dict
5
+
6
+ from lark import Tree
7
+
8
+ from gnps import Cell
9
+ from gnps.parser.ast import Variable
10
+ from gnps.parser.ast.value import FloatValue
11
+ from gnps.system import GnpsSystem
12
+ from gnps.parser import parse_condition, parse_expression, parse_rule, parse_variable_assignment
13
+
14
+ from gnps._version import __version__
15
+
16
+ def main():
17
+ parser = argparse.ArgumentParser(description=f"GNPS simulator v{__version__}", prog='gnps')
18
+ parser.add_argument('gnps_file', type=argparse.FileType('r'),
19
+ help='The file containing the description of the GNPS system')
20
+ parser.add_argument('input', type=argparse.FileType('r'), nargs='?', default=sys.stdin,
21
+ help='Input (CSV) file giving stimulus for each step (default: stdin)')
22
+ parser.add_argument('output', type=argparse.FileType('w'), nargs='?', default=sys.stdout,
23
+ help='Output (CSV) file giving the results of each step (default: stdout)')
24
+ parser.add_argument('-c', '--compute_mode', action='store_true',
25
+ help='Run in continuous compute mode (default: False)')
26
+ parser.add_argument('-s', '--steps', type=int, default=1,
27
+ help='Number of steps to run (default: 1)')
28
+ parser.add_argument('--csv', action='store_true',
29
+ help='Output in CSV format when in continuous compute mode')
30
+ args = parser.parse_args()
31
+
32
+ gnps = GnpsSystem.from_yaml(args.gnps_file.name)
33
+
34
+ if args.compute_mode:
35
+ if len(gnps.input_variables) > 0:
36
+ raise ValueError("Cannot run in continuous compute mode with input variables")
37
+ if args.csv:
38
+ # CSV output mode
39
+ args.output.reconfigure(newline='')
40
+ result = {name: str(variable.value) for name, variable in gnps.output_variables.items()}
41
+ fieldnames = ['step'] + list(result.keys())
42
+ writer = csv.DictWriter(args.output, fieldnames=fieldnames)
43
+ writer.writeheader()
44
+ # Write initial state (step 0) with only output variables
45
+ row = {'step': 0}
46
+ row.update(result)
47
+ writer.writerow(row)
48
+ for i in range(args.steps):
49
+ gnps.step()
50
+ result = {name: str(variable.value) for name, variable in gnps.output_variables.items()}
51
+ row = {'step': i+1}
52
+ row.update(result)
53
+ writer.writerow(row)
54
+ else:
55
+ print(f"Running in continuous compute mode for {args.steps} steps")
56
+ result = {name: str(variable.value) for name, variable in gnps.output_variables.items()}
57
+ print(f"Step: 0: {result}")
58
+ for i in range(args.steps):
59
+ gnps.step()
60
+ result = {name: str(variable.value) for name, variable in gnps.output_variables.items()}
61
+ print(f"Step: {i+1}: {result}")
62
+ else: # IO mode
63
+
64
+ args.output.reconfigure(newline='')
65
+ args.input.reconfigure(newline='')
66
+
67
+ reader = csv.DictReader(args.input)
68
+ writer = None
69
+
70
+ for row in reader:
71
+
72
+ for input_var_name, input_var_value in row.items():
73
+ var = gnps.get_variable(input_var_name)
74
+ if var is None or input_var_name not in gnps.input_variables.keys():
75
+ raise ValueError(f"Unknown input variable {input_var_name}")
76
+ var.value = FloatValue(input_var_value)
77
+
78
+ gnps.step()
79
+
80
+ result = {name: variable.value for name, variable in gnps.output_variables.items()}
81
+
82
+ if writer is None:
83
+ writer = csv.DictWriter(args.output, fieldnames=result.keys())
84
+ writer.writeheader()
85
+ writer.writerow(result)
86
+
87
+
88
+ if __name__ == '__main__':
89
+ main()
@@ -0,0 +1,134 @@
1
+ """CLI tool for transforming GNPS systems to various output formats."""
2
+
3
+ import argparse
4
+ import sys
5
+ from pathlib import Path
6
+ from typing import Dict, Type
7
+
8
+ from gnps.system import GnpsSystem
9
+ from gnps.transformers import BaseTransformer, PythonTransformer
10
+ from gnps._version import __version__
11
+
12
+
13
+ # Registry of available transformers
14
+ TRANSFORMERS: Dict[str, Type[BaseTransformer]] = {
15
+ 'python': PythonTransformer,
16
+ }
17
+
18
+
19
+ def get_transformer(transform_type: str) -> BaseTransformer:
20
+ """Get a transformer instance by type name.
21
+
22
+ Args:
23
+ transform_type: The type of transformer to create
24
+
25
+ Returns:
26
+ Transformer instance
27
+
28
+ Raises:
29
+ ValueError: If transform_type is not supported
30
+ """
31
+ if transform_type not in TRANSFORMERS:
32
+ available = ', '.join(TRANSFORMERS.keys())
33
+ raise ValueError(f"Unsupported transformation type '{transform_type}'. Available types: {available}")
34
+
35
+ return TRANSFORMERS[transform_type]()
36
+
37
+
38
+ def main():
39
+ """Main entry point for the gnps-transformer CLI."""
40
+ parser = argparse.ArgumentParser(
41
+ description=f"GNPS Transformer v{__version__} - Convert GNPS systems to various output formats",
42
+ prog='gnps-transformer'
43
+ )
44
+
45
+ parser.add_argument(
46
+ 'gnps_files',
47
+ nargs='+',
48
+ help='GNPS system files (.yaml) to transform'
49
+ )
50
+
51
+ parser.add_argument(
52
+ '-t', '--type',
53
+ dest='transform_type',
54
+ required=True,
55
+ choices=list(TRANSFORMERS.keys()),
56
+ help='Transformation type'
57
+ )
58
+
59
+ parser.add_argument(
60
+ '-o', '--output-dir',
61
+ type=Path,
62
+ default=Path('.'),
63
+ help='Output directory for transformed files (default: current directory)'
64
+ )
65
+
66
+ parser.add_argument(
67
+ '--output-suffix',
68
+ default='',
69
+ help='Suffix to add to output filenames (before extension)'
70
+ )
71
+
72
+ parser.add_argument(
73
+ '-v', '--verbose',
74
+ action='store_true',
75
+ help='Enable verbose output'
76
+ )
77
+
78
+ args = parser.parse_args()
79
+
80
+ # Ensure output directory exists
81
+ args.output_dir.mkdir(parents=True, exist_ok=True)
82
+
83
+ # Get transformer
84
+ try:
85
+ transformer = get_transformer(args.transform_type)
86
+ except ValueError as e:
87
+ print(f"Error: {e}", file=sys.stderr)
88
+ sys.exit(1)
89
+
90
+ # Process each file
91
+ for gnps_file_path in args.gnps_files:
92
+ gnps_file = Path(gnps_file_path)
93
+
94
+ if not gnps_file.exists():
95
+ print(f"Error: File '{gnps_file}' not found", file=sys.stderr)
96
+ continue
97
+
98
+ if args.verbose:
99
+ print(f"Processing: {gnps_file}")
100
+
101
+ try:
102
+ # Load GNPS system
103
+ gnps_system = GnpsSystem.from_yaml(str(gnps_file))
104
+
105
+ # Transform to target format
106
+ transformed_code = transformer.transform(gnps_system)
107
+
108
+ # Generate output filename
109
+ base_name = gnps_file.stem
110
+ if args.output_suffix:
111
+ base_name += args.output_suffix
112
+
113
+ output_file = args.output_dir / (base_name + transformer.get_file_extension())
114
+
115
+ # Write output
116
+ with open(output_file, 'w', encoding='utf-8') as f:
117
+ f.write(transformed_code)
118
+
119
+ if args.verbose:
120
+ print(f" -> {output_file}")
121
+
122
+ except Exception as e:
123
+ print(f"Error processing '{gnps_file}': {e}", file=sys.stderr)
124
+ if args.verbose: # pragma: no cover
125
+ import traceback
126
+ traceback.print_exc()
127
+ continue
128
+
129
+ if args.verbose:
130
+ print("Transformation complete.")
131
+
132
+
133
+ if __name__ == '__main__':
134
+ main()
@@ -0,0 +1,6 @@
1
+ from .parser import (
2
+ parse_expression,
3
+ parse_condition,
4
+ parse_rule,
5
+ parse_variable_assignment
6
+ )
@@ -0,0 +1,31 @@
1
+ from .variable import Variable
2
+
3
+ from .expression import (
4
+ Expression,
5
+ ConstantExpression,
6
+ VariableExpression,
7
+ BinaryExpression,
8
+ SumExpression,
9
+ DifferenceExpression,
10
+ MultiplicationExpression,
11
+ DivisionExpression,
12
+ UnaryMinusExpression,
13
+ IntOperationExpression,
14
+ IntMultiplicationExpression,
15
+ IntDivisionExpression,
16
+ )
17
+
18
+ from .boolean_expression import (
19
+ BooleanExpression,
20
+ BooleanConstantExpression,
21
+ BooleanBinaryExpression,
22
+ BooleanAndExpression,
23
+ BooleanOrExpression,
24
+ BooleanNotExpression,
25
+ BooleanLessTestExpression,
26
+ BooleanLessEqualTestExpression,
27
+ BooleanGreaterTestExpression,
28
+ BooleanGreaterEqualTestExpression,
29
+ BooleanEqualTestExpression,
30
+ BooleanNotEqualTestExpression,
31
+ )
@@ -0,0 +1,151 @@
1
+ from abc import abstractmethod, ABC
2
+
3
+ from .expression import Expression
4
+ from .variable import Variable
5
+
6
+
7
+ class BooleanExpression(Expression):
8
+ @abstractmethod
9
+ def evaluate(self) -> bool:
10
+ pass # pragma: no cover
11
+
12
+
13
+ class BooleanConstantExpression(BooleanExpression):
14
+ value: bool
15
+
16
+ def __init__(self, value: bool):
17
+ self.value = value
18
+
19
+ def evaluate(self):
20
+ return self.value
21
+
22
+ def get_variables(self) -> dict[str, Variable]:
23
+ return {}
24
+
25
+ def __str__(self):
26
+ return self.value.__str__()
27
+
28
+ def __repr__(self):
29
+ return f"BooleanConstantExpression({self.value})"
30
+
31
+
32
+ class BooleanTestExpression(BooleanExpression, ABC):
33
+ def __init__(self, left: Expression, right: Expression, op: str = ''):
34
+ self.left = left
35
+ self.right = right
36
+ self.op = op
37
+
38
+ def __str__(self):
39
+ ll = self.left.__str__()
40
+ r = self.right.__str__()
41
+ return f"({ll} {self.op} {r})"
42
+
43
+ def __repr__(self):
44
+ return f"BooleanTestExpression('{self.op}',{self.left.__repr__()},{self.right.__repr__()})"
45
+
46
+ def get_variables(self) -> dict[str, Variable]:
47
+ variables = self.left.get_variables()
48
+ variables.update(self.right.get_variables())
49
+ return variables
50
+
51
+
52
+ class BooleanGreaterTestExpression(BooleanTestExpression):
53
+ def __init__(self, left: Expression, right: Expression):
54
+ super().__init__(left, right, ">")
55
+
56
+ def evaluate(self):
57
+ return self.left.evaluate() > self.right.evaluate()
58
+
59
+
60
+ class BooleanGreaterEqualTestExpression(BooleanTestExpression):
61
+ def __init__(self, left: Expression, right: Expression):
62
+ super().__init__(left, right, ">=")
63
+
64
+ def evaluate(self):
65
+ return self.left.evaluate() >= self.right.evaluate()
66
+
67
+
68
+ class BooleanEqualTestExpression(BooleanTestExpression):
69
+ def __init__(self, left: Expression, right: Expression):
70
+ super().__init__(left, right, "==")
71
+
72
+ def evaluate(self):
73
+ return self.left.evaluate() == self.right.evaluate()
74
+
75
+
76
+ class BooleanNotEqualTestExpression(BooleanTestExpression):
77
+ def __init__(self, left: Expression, right: Expression):
78
+ super().__init__(left, right, "!=")
79
+
80
+ def evaluate(self):
81
+ return self.left.evaluate() != self.right.evaluate()
82
+
83
+
84
+ class BooleanLessTestExpression(BooleanTestExpression):
85
+ def __init__(self, left: Expression, right: Expression):
86
+ super().__init__(left, right, "<")
87
+
88
+ def evaluate(self):
89
+ return self.left.evaluate() < self.right.evaluate()
90
+
91
+
92
+ class BooleanLessEqualTestExpression(BooleanTestExpression):
93
+ def __init__(self, left: Expression, right: Expression):
94
+ super().__init__(left, right, "<=")
95
+
96
+ def evaluate(self):
97
+ return self.left.evaluate() <= self.right.evaluate()
98
+
99
+
100
+ class BooleanBinaryExpression(BooleanExpression, ABC):
101
+ def __init__(self, left: BooleanExpression, right: BooleanExpression, op: str = ''):
102
+ self.left = left
103
+ self.right = right
104
+ self.op = op
105
+
106
+ def __str__(self):
107
+ ll = self.left.__str__()
108
+ r = self.right.__str__()
109
+ return f"({ll} {self.op} {r})"
110
+
111
+ def __repr__(self):
112
+ return f"BooleanBinaryExpression('{self.op}',{self.left.__repr__()},{self.right.__repr__()})"
113
+
114
+ def get_variables(self) -> dict[str, Variable]:
115
+ variables = self.left.get_variables()
116
+ variables.update(self.right.get_variables())
117
+ return variables
118
+
119
+
120
+ class BooleanOrExpression(BooleanBinaryExpression):
121
+ def __init__(self, left: BooleanExpression, right: BooleanExpression):
122
+ super().__init__(left, right, '||')
123
+
124
+ def evaluate(self):
125
+ return self.left.evaluate() or self.right.evaluate()
126
+
127
+
128
+ class BooleanAndExpression(BooleanBinaryExpression):
129
+ def __init__(self, left: BooleanExpression, right: BooleanExpression):
130
+ super().__init__(left, right, '&&')
131
+
132
+ def evaluate(self):
133
+ return self.left.evaluate() and self.right.evaluate()
134
+
135
+
136
+ class BooleanNotExpression(BooleanExpression):
137
+ def __init__(self, expression: BooleanExpression):
138
+ self.expression = expression
139
+
140
+ def evaluate(self):
141
+ return not self.expression.evaluate()
142
+
143
+ def __str__(self):
144
+ exp = self.expression.__str__()
145
+ return f"!({exp})"
146
+
147
+ def __repr__(self):
148
+ return f"BooleanNotExpression({self.expression.__repr__()})"
149
+
150
+ def get_variables(self) -> dict[str, Variable]:
151
+ return self.expression.get_variables()