tricc-oo 1.6.25__py3-none-any.whl → 1.6.27__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.
- tests/build.py +1 -1
- tests/test_clean_and_list.py +127 -0
- tricc_oo/models/base.py +381 -1
- tricc_oo/strategies/input/drawio.py +1 -0
- tricc_oo/strategies/output/xls_form.py +5 -1
- tricc_oo/visitors/tricc.py +69 -57
- {tricc_oo-1.6.25.dist-info → tricc_oo-1.6.27.dist-info}/METADATA +2 -1
- {tricc_oo-1.6.25.dist-info → tricc_oo-1.6.27.dist-info}/RECORD +11 -10
- {tricc_oo-1.6.25.dist-info → tricc_oo-1.6.27.dist-info}/WHEEL +0 -0
- {tricc_oo-1.6.25.dist-info → tricc_oo-1.6.27.dist-info}/licenses/LICENSE +0 -0
- {tricc_oo-1.6.25.dist-info → tricc_oo-1.6.27.dist-info}/top_level.txt +0 -0
tests/build.py
CHANGED
|
@@ -158,7 +158,7 @@ if __name__ == "__main__":
|
|
|
158
158
|
if debug_level is not None:
|
|
159
159
|
setup_logger("default", debug_file_path, LEVELS[debug_level])
|
|
160
160
|
elif "pydevd" in sys.modules:
|
|
161
|
-
setup_logger("default", debug_file_path, logging.
|
|
161
|
+
setup_logger("default", debug_file_path, logging.INFO)
|
|
162
162
|
else:
|
|
163
163
|
setup_logger("default", debug_file_path, logging.INFO)
|
|
164
164
|
file_content = []
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from tricc_oo.models.base import (
|
|
3
|
+
TriccOperator, TriccOperation, TriccStatic, TriccReference,
|
|
4
|
+
clean_and_list, not_clean
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestCleanAndList(unittest.TestCase):
|
|
9
|
+
|
|
10
|
+
def test_empty_list(self):
|
|
11
|
+
"""Test with empty list"""
|
|
12
|
+
result = clean_and_list([])
|
|
13
|
+
self.assertEqual(result, [])
|
|
14
|
+
|
|
15
|
+
def test_single_true(self):
|
|
16
|
+
"""Test single TRUE is removed"""
|
|
17
|
+
result = clean_and_list([TriccStatic(True)])
|
|
18
|
+
self.assertEqual(result, [])
|
|
19
|
+
|
|
20
|
+
def test_single_false(self):
|
|
21
|
+
"""Test single FALSE returns [FALSE]"""
|
|
22
|
+
result = clean_and_list([TriccStatic(False)])
|
|
23
|
+
self.assertEqual(result, [TriccStatic(False)])
|
|
24
|
+
|
|
25
|
+
def test_mixed_true_false(self):
|
|
26
|
+
"""Test TRUE and FALSE returns [FALSE]"""
|
|
27
|
+
result = clean_and_list([TriccStatic(True), TriccStatic(False)])
|
|
28
|
+
self.assertEqual(result, [TriccStatic(False)])
|
|
29
|
+
|
|
30
|
+
def test_and_flattening(self):
|
|
31
|
+
"""Test AND operations are flattened"""
|
|
32
|
+
a = TriccReference("a")
|
|
33
|
+
b = TriccReference("b")
|
|
34
|
+
c = TriccReference("c")
|
|
35
|
+
and_op = TriccOperation(TriccOperator.AND, [a, b])
|
|
36
|
+
result = clean_and_list([and_op, c])
|
|
37
|
+
expected = sorted([a, b, c], key=str)
|
|
38
|
+
self.assertEqual(result, expected)
|
|
39
|
+
|
|
40
|
+
def test_nested_and_flattening(self):
|
|
41
|
+
"""Test nested AND operations are flattened"""
|
|
42
|
+
a = TriccReference("a")
|
|
43
|
+
b = TriccReference("b")
|
|
44
|
+
c = TriccReference("c")
|
|
45
|
+
d = TriccReference("d")
|
|
46
|
+
inner_and = TriccOperation(TriccOperator.AND, [a, b])
|
|
47
|
+
outer_and = TriccOperation(TriccOperator.AND, [inner_and, c])
|
|
48
|
+
result = clean_and_list([outer_and, d])
|
|
49
|
+
expected = sorted([a, b, c, d], key=str)
|
|
50
|
+
self.assertEqual(result, expected)
|
|
51
|
+
|
|
52
|
+
def test_contradiction_detection_exists(self):
|
|
53
|
+
"""Test EXISTS(a) and NOTEXISTS(a) returns [FALSE]"""
|
|
54
|
+
a = TriccReference("a")
|
|
55
|
+
exists_a = TriccOperation(TriccOperator.EXISTS, [a])
|
|
56
|
+
not_exists_a = TriccOperation(TriccOperator.NOTEXISTS, [a])
|
|
57
|
+
result = clean_and_list([exists_a, not_exists_a])
|
|
58
|
+
self.assertEqual(result, [TriccStatic(False)])
|
|
59
|
+
|
|
60
|
+
def test_contradiction_detection_boolean_ops(self):
|
|
61
|
+
"""Test boolean operation and its negation returns [FALSE]"""
|
|
62
|
+
a = TriccReference("a")
|
|
63
|
+
is_true_a = TriccOperation(TriccOperator.ISTRUE, [a])
|
|
64
|
+
is_false_a = TriccOperation(TriccOperator.ISFALSE, [a])
|
|
65
|
+
result = clean_and_list([is_true_a, is_false_a])
|
|
66
|
+
self.assertEqual(result, [TriccStatic(False)])
|
|
67
|
+
|
|
68
|
+
def test_remove_trues(self):
|
|
69
|
+
"""Test TRUE values are removed"""
|
|
70
|
+
a = TriccReference("a")
|
|
71
|
+
b = TriccReference("b")
|
|
72
|
+
result = clean_and_list([a, TriccStatic(True), b])
|
|
73
|
+
expected = sorted([a, b], key=str)
|
|
74
|
+
self.assertEqual(result, expected)
|
|
75
|
+
|
|
76
|
+
def test_not_and_optimization_simple(self):
|
|
77
|
+
"""Test NOT(AND(a, b)) with a present removes a from AND"""
|
|
78
|
+
a = TriccReference("a")
|
|
79
|
+
b = TriccReference("b")
|
|
80
|
+
not_and = TriccOperation(TriccOperator.NOT, [
|
|
81
|
+
TriccOperation(TriccOperator.AND, [a, b])
|
|
82
|
+
])
|
|
83
|
+
result = clean_and_list([a, not_and])
|
|
84
|
+
# Should simplify NOT(AND(b)) which is equivalent to OR(NOT(b))
|
|
85
|
+
# But let's see what the current logic does
|
|
86
|
+
expected = sorted([a, not_and], key=str)
|
|
87
|
+
self.assertEqual(result, expected)
|
|
88
|
+
|
|
89
|
+
def test_basic_uniqueness(self):
|
|
90
|
+
"""Test duplicate elements are removed"""
|
|
91
|
+
a = TriccReference("a")
|
|
92
|
+
result = clean_and_list([a, a, a])
|
|
93
|
+
self.assertEqual(result, [a])
|
|
94
|
+
|
|
95
|
+
def test_mixed_types(self):
|
|
96
|
+
"""Test with mixed reference and static types"""
|
|
97
|
+
ref = TriccReference("test")
|
|
98
|
+
static = TriccStatic("value")
|
|
99
|
+
result = clean_and_list([ref, static, TriccStatic(True)])
|
|
100
|
+
expected = sorted([ref, static], key=str)
|
|
101
|
+
self.assertEqual(result, expected)
|
|
102
|
+
|
|
103
|
+
def test_false_with_others(self):
|
|
104
|
+
"""Test FALSE with other elements returns [FALSE]"""
|
|
105
|
+
a = TriccReference("a")
|
|
106
|
+
b = TriccReference("b")
|
|
107
|
+
result = clean_and_list([a, TriccStatic(False), b])
|
|
108
|
+
self.assertEqual(result, [TriccStatic(False)])
|
|
109
|
+
|
|
110
|
+
def test_only_trues(self):
|
|
111
|
+
"""Test list of only TRUEs returns empty"""
|
|
112
|
+
result = clean_and_list([TriccStatic(True), TriccStatic(True)])
|
|
113
|
+
self.assertEqual(result, [])
|
|
114
|
+
|
|
115
|
+
def test_complex_and_flattening(self):
|
|
116
|
+
"""Test complex AND flattening with TRUEs and duplicates"""
|
|
117
|
+
a = TriccReference("a")
|
|
118
|
+
b = TriccReference("b")
|
|
119
|
+
c = TriccReference("c")
|
|
120
|
+
and_op = TriccOperation(TriccOperator.AND, [a, TriccStatic(True), b])
|
|
121
|
+
result = clean_and_list([and_op, c, TriccStatic(True)])
|
|
122
|
+
expected = sorted([a, b, c], key=str)
|
|
123
|
+
self.assertEqual(result, expected)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
if __name__ == "__main__":
|
|
127
|
+
unittest.main()
|
tricc_oo/models/base.py
CHANGED
|
@@ -603,7 +603,7 @@ def clean_and_list(argv):
|
|
|
603
603
|
internal = list(set(argv))
|
|
604
604
|
for a in internal:
|
|
605
605
|
for b in internal[internal.index(a) + 1:]:
|
|
606
|
-
if not_clean(b) == a:
|
|
606
|
+
if not_clean(a) == b or not_clean(b) == a:
|
|
607
607
|
return [TriccStatic(False)]
|
|
608
608
|
return sorted(list(set(argv)), key=str)
|
|
609
609
|
|
|
@@ -777,4 +777,384 @@ def nand_join(left, right):
|
|
|
777
777
|
return and_join([left, not_clean(right)])
|
|
778
778
|
|
|
779
779
|
|
|
780
|
+
def simplify_with_sympy(operation):
|
|
781
|
+
"""
|
|
782
|
+
Simplify a TriccOperation using SymPy boolean and algebraic operations.
|
|
783
|
+
|
|
784
|
+
This enhanced version maps Tricc operators to actual SymPy operations/symbols
|
|
785
|
+
instead of treating them as placeholders, enabling sophisticated mixed-domain
|
|
786
|
+
simplifications.
|
|
787
|
+
|
|
788
|
+
Args:
|
|
789
|
+
operation: TriccOperation to simplify
|
|
790
|
+
|
|
791
|
+
Returns:
|
|
792
|
+
Simplified TriccOperation or original if no simplification possible
|
|
793
|
+
"""
|
|
794
|
+
# Step 1: Check if operation contains operations that can be simplified
|
|
795
|
+
if not isinstance(operation, TriccOperation):
|
|
796
|
+
return operation
|
|
797
|
+
|
|
798
|
+
try:
|
|
799
|
+
import sympy as sp
|
|
800
|
+
from sympy.logic.boolalg import simplify_logic
|
|
801
|
+
from sympy import Add, Mul, Pow, Eq, Ne, And, Or, Not, Gt, Ge, Lt, Le
|
|
802
|
+
from sympy.functions import Abs, sign
|
|
803
|
+
except ImportError:
|
|
804
|
+
logger.warning("SymPy not available, skipping algebraic simplification")
|
|
805
|
+
return operation
|
|
806
|
+
|
|
807
|
+
# Step 2: Create comprehensive Tricc-to-SymPy operator mapping
|
|
808
|
+
tricc_to_sympy_map = {
|
|
809
|
+
# Boolean operations - treat as symbols to preserve structure
|
|
810
|
+
TriccOperator.AND: And,
|
|
811
|
+
TriccOperator.OR: Or,
|
|
812
|
+
TriccOperator.NOT: Not,
|
|
813
|
+
TriccOperator.ISTRUE: None, # Will be treated as symbol
|
|
814
|
+
TriccOperator.ISFALSE: None, # Will be treated as symbol
|
|
815
|
+
TriccOperator.EXISTS: None, # Will be treated as symbol
|
|
816
|
+
TriccOperator.NOTEXISTS: None, # Will be treated as symbol
|
|
817
|
+
TriccOperator.ISNOTTRUE: None, # Will be treated as symbol
|
|
818
|
+
TriccOperator.ISNOTFALSE: None, # Will be treated as symbol
|
|
819
|
+
|
|
820
|
+
# Arithmetic operations
|
|
821
|
+
TriccOperator.PLUS: Add,
|
|
822
|
+
TriccOperator.MINUS: lambda *args: Add(args[0], Mul(-1, args[1])) if len(args) == 2 else Mul(-1, args[0]),
|
|
823
|
+
TriccOperator.MULTIPLIED: Mul,
|
|
824
|
+
TriccOperator.DIVIDED: lambda x, y: Mul(x, Pow(y, -1)),
|
|
825
|
+
TriccOperator.MODULO: lambda x, y: x % y, # Modulo
|
|
826
|
+
|
|
827
|
+
# Comparison operations
|
|
828
|
+
TriccOperator.EQUAL: Eq,
|
|
829
|
+
TriccOperator.NOTEQUAL: Ne,
|
|
830
|
+
TriccOperator.MORE: Gt,
|
|
831
|
+
TriccOperator.LESS: Lt,
|
|
832
|
+
TriccOperator.MORE_OR_EQUAL: Ge,
|
|
833
|
+
TriccOperator.LESS_OR_EQUAL: Le,
|
|
834
|
+
|
|
835
|
+
# Numeric operations
|
|
836
|
+
TriccOperator.ROUND: lambda x: sp.round(x),
|
|
837
|
+
TriccOperator.CAST_NUMBER: lambda x: x, # Identity for numbers
|
|
838
|
+
TriccOperator.CAST_INTEGER: lambda x: sp.floor(x),
|
|
839
|
+
|
|
840
|
+
# Special operations (placeholders for now)
|
|
841
|
+
TriccOperator.COALESCE: None, # Will use placeholder
|
|
842
|
+
TriccOperator.CONCATENATE: None, # Will use placeholder
|
|
843
|
+
TriccOperator.CASE: None, # Will use placeholder
|
|
844
|
+
TriccOperator.IFS: None, # Will use placeholder
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
# Step 3: Create reference mapping with structural keys
|
|
848
|
+
ref_counter = 0
|
|
849
|
+
ref_map = {} # SymPy symbol -> actual reference
|
|
850
|
+
reverse_map = {} # structural key -> SymPy symbol
|
|
851
|
+
|
|
852
|
+
def get_structural_key(ref):
|
|
853
|
+
"""Generate a canonical key based on structural equality"""
|
|
854
|
+
if isinstance(ref, TriccOperation):
|
|
855
|
+
ref_keys = [get_structural_key(r) for r in ref.reference]
|
|
856
|
+
return f"op_{ref.operator}_{'_'.join(ref_keys)}"
|
|
857
|
+
elif isinstance(ref, TriccReference):
|
|
858
|
+
return f"ref_{ref.value}"
|
|
859
|
+
elif isinstance(ref, TriccStatic):
|
|
860
|
+
return f"static_{ref.value}"
|
|
861
|
+
elif hasattr(ref, 'id'):
|
|
862
|
+
return f"{ref.__class__.__name__}_{ref.id}"
|
|
863
|
+
else:
|
|
864
|
+
return str(ref)
|
|
865
|
+
|
|
866
|
+
def get_sympy_symbol(ref):
|
|
867
|
+
"""Get or create SymPy symbol for a reference"""
|
|
868
|
+
nonlocal ref_counter
|
|
869
|
+
ref_key = get_structural_key(ref)
|
|
870
|
+
if ref_key in reverse_map:
|
|
871
|
+
return reverse_map[ref_key]
|
|
872
|
+
|
|
873
|
+
# Create unique symbol name
|
|
874
|
+
if hasattr(ref, 'reference') and isinstance(ref.reference, (list, OrderedSet)):
|
|
875
|
+
# For operations, create path-based name
|
|
876
|
+
path_parts = []
|
|
877
|
+
current = ref
|
|
878
|
+
depth = 0
|
|
879
|
+
while hasattr(current, 'reference') and depth < 3:
|
|
880
|
+
if isinstance(current.reference, (list, OrderedSet)) and len(current.reference) > 0:
|
|
881
|
+
path_parts.insert(0, str(len(current.reference)))
|
|
882
|
+
current = current.reference[0]
|
|
883
|
+
depth += 1
|
|
884
|
+
else:
|
|
885
|
+
break
|
|
886
|
+
if path_parts:
|
|
887
|
+
symbol_name = f"r_{'_'.join(path_parts)}"
|
|
888
|
+
else:
|
|
889
|
+
symbol_name = f"r_{ref_counter}"
|
|
890
|
+
else:
|
|
891
|
+
symbol_name = f"r_{ref_counter}"
|
|
892
|
+
|
|
893
|
+
ref_counter += 1
|
|
894
|
+
symbol = sp.Symbol(symbol_name)
|
|
895
|
+
ref_map[symbol] = ref
|
|
896
|
+
reverse_map[ref_key] = symbol
|
|
897
|
+
return symbol
|
|
898
|
+
|
|
899
|
+
def tricc_to_sympy_expr(op):
|
|
900
|
+
"""Convert TriccOperation to SymPy expression"""
|
|
901
|
+
if isinstance(op, TriccOperation):
|
|
902
|
+
# Special handling for boolean operations
|
|
903
|
+
if op.operator == TriccOperator.ISTRUE:
|
|
904
|
+
# istrue(x) becomes a symbol for the entire operation
|
|
905
|
+
return get_sympy_symbol(op)
|
|
906
|
+
elif op.operator == TriccOperator.ISNOTTRUE:
|
|
907
|
+
# isnottrue(x) becomes not(istrue(x))
|
|
908
|
+
if len(op.reference) == 1:
|
|
909
|
+
istrue_op = TriccOperation(TriccOperator.ISTRUE, op.reference)
|
|
910
|
+
istrue_symbol = get_sympy_symbol(istrue_op)
|
|
911
|
+
return Not(istrue_symbol)
|
|
912
|
+
else:
|
|
913
|
+
return get_sympy_symbol(op)
|
|
914
|
+
elif op.operator == TriccOperator.NOT and len(op.reference) == 1:
|
|
915
|
+
# Handle NOT(boolean_operation) by applying SymPy to inner and wrapping
|
|
916
|
+
inner = op.reference[0]
|
|
917
|
+
if isinstance(inner, TriccOperation) and inner.get_datatype() == "boolean":
|
|
918
|
+
# Apply SymPy to the inner boolean expression
|
|
919
|
+
inner_sympy = tricc_to_sympy_expr(inner)
|
|
920
|
+
if inner_sympy != get_sympy_symbol(inner):
|
|
921
|
+
# Inner was simplified, wrap with NOT
|
|
922
|
+
return Not(inner_sympy)
|
|
923
|
+
else:
|
|
924
|
+
# Inner wasn't simplified, return as symbol
|
|
925
|
+
return get_sympy_symbol(op)
|
|
926
|
+
else:
|
|
927
|
+
# Not a boolean operation, handle normally
|
|
928
|
+
sympy_op = tricc_to_sympy_map.get(op.operator)
|
|
929
|
+
if sympy_op is None:
|
|
930
|
+
return get_sympy_symbol(op)
|
|
931
|
+
|
|
932
|
+
sympy_refs = [tricc_to_sympy_expr(ref) for ref in op.reference]
|
|
933
|
+
if callable(sympy_op):
|
|
934
|
+
try:
|
|
935
|
+
if len(sympy_refs) == 1:
|
|
936
|
+
return sympy_op(sympy_refs[0])
|
|
937
|
+
elif len(sympy_refs) == 2:
|
|
938
|
+
return sympy_op(sympy_refs[0], sympy_refs[1])
|
|
939
|
+
else:
|
|
940
|
+
result = sympy_refs[0]
|
|
941
|
+
for ref in sympy_refs[1:]:
|
|
942
|
+
result = sympy_op(result, ref)
|
|
943
|
+
return result
|
|
944
|
+
except Exception as e:
|
|
945
|
+
logger.debug(f"Failed to apply {sympy_op} to {sympy_refs}: {e}")
|
|
946
|
+
return get_sympy_symbol(op)
|
|
947
|
+
else:
|
|
948
|
+
try:
|
|
949
|
+
return sympy_op(*sympy_refs)
|
|
950
|
+
except Exception as e:
|
|
951
|
+
logger.debug(f"Failed to create {sympy_op} with {sympy_refs}: {e}")
|
|
952
|
+
return get_sympy_symbol(op)
|
|
953
|
+
else:
|
|
954
|
+
# Normal operation handling
|
|
955
|
+
sympy_op = tricc_to_sympy_map.get(op.operator)
|
|
956
|
+
|
|
957
|
+
if sympy_op is None:
|
|
958
|
+
# Use placeholder for unmapped operations
|
|
959
|
+
return get_sympy_symbol(op)
|
|
960
|
+
|
|
961
|
+
# Convert references to SymPy expressions
|
|
962
|
+
sympy_refs = [tricc_to_sympy_expr(ref) for ref in op.reference]
|
|
963
|
+
|
|
964
|
+
# Apply the SymPy operation
|
|
965
|
+
if callable(sympy_op):
|
|
966
|
+
try:
|
|
967
|
+
if len(sympy_refs) == 1:
|
|
968
|
+
return sympy_op(sympy_refs[0])
|
|
969
|
+
elif len(sympy_refs) == 2:
|
|
970
|
+
return sympy_op(sympy_refs[0], sympy_refs[1])
|
|
971
|
+
else:
|
|
972
|
+
# For operations with multiple args, apply sequentially
|
|
973
|
+
result = sympy_refs[0]
|
|
974
|
+
for ref in sympy_refs[1:]:
|
|
975
|
+
result = sympy_op(result, ref)
|
|
976
|
+
return result
|
|
977
|
+
except Exception as e:
|
|
978
|
+
logger.debug(f"Failed to apply {sympy_op} to {sympy_refs}: {e}")
|
|
979
|
+
return get_sympy_symbol(op)
|
|
980
|
+
else:
|
|
981
|
+
# Direct SymPy operation class
|
|
982
|
+
try:
|
|
983
|
+
return sympy_op(*sympy_refs)
|
|
984
|
+
except Exception as e:
|
|
985
|
+
logger.debug(f"Failed to create {sympy_op} with {sympy_refs}: {e}")
|
|
986
|
+
return get_sympy_symbol(op)
|
|
987
|
+
|
|
988
|
+
elif isinstance(op, TriccStatic):
|
|
989
|
+
if isinstance(op.value, bool):
|
|
990
|
+
return sp.true if op.value else sp.false
|
|
991
|
+
elif isinstance(op.value, (int, float)):
|
|
992
|
+
return sp.S(op.value)
|
|
993
|
+
else:
|
|
994
|
+
return get_sympy_symbol(op)
|
|
995
|
+
else:
|
|
996
|
+
# References and other objects
|
|
997
|
+
return get_sympy_symbol(op)
|
|
998
|
+
|
|
999
|
+
def sympy_expr_to_tricc(expr):
|
|
1000
|
+
"""Convert SymPy expression back to TriccOperation using expression tree"""
|
|
1001
|
+
if isinstance(expr, sp.Symbol):
|
|
1002
|
+
# Direct symbol lookup
|
|
1003
|
+
if expr in ref_map:
|
|
1004
|
+
return ref_map[expr]
|
|
1005
|
+
else:
|
|
1006
|
+
# This shouldn't happen, but handle gracefully
|
|
1007
|
+
return TriccReference(str(expr))
|
|
1008
|
+
|
|
1009
|
+
elif expr is sp.true:
|
|
1010
|
+
return TriccStatic(True)
|
|
1011
|
+
elif expr is sp.false:
|
|
1012
|
+
return TriccStatic(False)
|
|
1013
|
+
|
|
1014
|
+
elif isinstance(expr, (sp.Integer, sp.Float)):
|
|
1015
|
+
return TriccStatic(float(expr))
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
elif isinstance(expr, And):
|
|
1020
|
+
args = [sympy_expr_to_tricc(arg) for arg in expr.args]
|
|
1021
|
+
return and_join(args)
|
|
1022
|
+
|
|
1023
|
+
elif isinstance(expr, Or):
|
|
1024
|
+
args = [sympy_expr_to_tricc(arg) for arg in expr.args]
|
|
1025
|
+
return or_join(args)
|
|
1026
|
+
|
|
1027
|
+
elif isinstance(expr, Not):
|
|
1028
|
+
inner = sympy_expr_to_tricc(expr.args[0])
|
|
1029
|
+
return TriccOperation(TriccOperator.NOT, [inner])
|
|
1030
|
+
|
|
1031
|
+
elif isinstance(expr, Add):
|
|
1032
|
+
if len(expr.args) == 2:
|
|
1033
|
+
left, right = [sympy_expr_to_tricc(arg) for arg in expr.args]
|
|
1034
|
+
# Check if right is negative (indicating subtraction)
|
|
1035
|
+
if isinstance(right, TriccOperation) and right.operator == TriccOperator.MINUS and len(right.reference) == 1:
|
|
1036
|
+
return TriccOperation(TriccOperator.MINUS, [left, right.reference[0]])
|
|
1037
|
+
else:
|
|
1038
|
+
return TriccOperation(TriccOperator.PLUS, [left, right])
|
|
1039
|
+
else:
|
|
1040
|
+
# Multiple addition
|
|
1041
|
+
args = [sympy_expr_to_tricc(arg) for arg in expr.args]
|
|
1042
|
+
return TriccOperation(TriccOperator.PLUS, args)
|
|
1043
|
+
|
|
1044
|
+
elif isinstance(expr, Mul):
|
|
1045
|
+
if len(expr.args) == 2:
|
|
1046
|
+
left, right = [sympy_expr_to_tricc(arg) for arg in expr.args]
|
|
1047
|
+
# Check for division (multiplication by reciprocal)
|
|
1048
|
+
if isinstance(right, TriccOperation) and right.operator == TriccOperator.DIVIDED:
|
|
1049
|
+
if len(right.reference) == 1:
|
|
1050
|
+
return TriccOperation(TriccOperator.DIVIDED, [left, right.reference[0]])
|
|
1051
|
+
else:
|
|
1052
|
+
return TriccOperation(TriccOperator.MULTIPLIED, [left, right])
|
|
1053
|
+
else:
|
|
1054
|
+
# Multiple multiplication
|
|
1055
|
+
args = [sympy_expr_to_tricc(arg) for arg in expr.args]
|
|
1056
|
+
return TriccOperation(TriccOperator.MULTIPLIED, args)
|
|
1057
|
+
|
|
1058
|
+
elif isinstance(expr, Pow):
|
|
1059
|
+
# Handle division (x^(-1) = 1/x)
|
|
1060
|
+
if len(expr.args) == 2 and expr.args[1] == -1:
|
|
1061
|
+
numerator = sympy_expr_to_tricc(expr.args[0])
|
|
1062
|
+
denominator = TriccStatic(1)
|
|
1063
|
+
return TriccOperation(TriccOperator.DIVIDED, [numerator, denominator])
|
|
1064
|
+
else:
|
|
1065
|
+
# Other powers - fallback to placeholder
|
|
1066
|
+
return TriccReference(str(expr))
|
|
1067
|
+
|
|
1068
|
+
elif isinstance(expr, (Eq, Ne, Lt, Le, Gt, Ge)):
|
|
1069
|
+
left, right = [sympy_expr_to_tricc(arg) for arg in expr.args]
|
|
1070
|
+
op_map = {
|
|
1071
|
+
Eq: TriccOperator.EQUAL,
|
|
1072
|
+
Ne: TriccOperator.NOTEQUAL,
|
|
1073
|
+
Lt: TriccOperator.LESS,
|
|
1074
|
+
Le: TriccOperator.LESS_OR_EQUAL,
|
|
1075
|
+
Gt: TriccOperator.MORE,
|
|
1076
|
+
Ge: TriccOperator.MORE_OR_EQUAL,
|
|
1077
|
+
}
|
|
1078
|
+
operator = op_map.get(type(expr), TriccOperator.EQUAL)
|
|
1079
|
+
return TriccOperation(operator, [left, right])
|
|
1080
|
+
|
|
1081
|
+
else:
|
|
1082
|
+
# Unknown SymPy expression type - fallback to string representation
|
|
1083
|
+
logger.debug(f"Unknown SymPy expression type: {type(expr)}, falling back to placeholder")
|
|
1084
|
+
return TriccReference(str(expr))
|
|
1085
|
+
|
|
1086
|
+
# Step 4: Apply custom boolean simplifications first
|
|
1087
|
+
if operation.get_datatype() == "boolean":
|
|
1088
|
+
# Apply our custom boolean simplifications
|
|
1089
|
+
custom_simplified = apply_boolean_simplifications(operation)
|
|
1090
|
+
if custom_simplified != operation:
|
|
1091
|
+
logger.debug(f"Custom boolean simplification: {operation} -> {custom_simplified}")
|
|
1092
|
+
return custom_simplified
|
|
1093
|
+
|
|
1094
|
+
# Step 5: Convert to SymPy and simplify
|
|
1095
|
+
try:
|
|
1096
|
+
sympy_expr = tricc_to_sympy_expr(operation)
|
|
1097
|
+
logger.debug(f"Original SymPy expression: {sympy_expr}")
|
|
1098
|
+
|
|
1099
|
+
# Apply appropriate simplification based on expression type
|
|
1100
|
+
if operation.get_datatype() == "boolean":
|
|
1101
|
+
# Use boolean algebra simplification
|
|
1102
|
+
simplified_expr = simplify_logic(sympy_expr)
|
|
1103
|
+
else:
|
|
1104
|
+
# Use general algebraic simplification
|
|
1105
|
+
simplified_expr = sp.simplify(sympy_expr)
|
|
1106
|
+
|
|
1107
|
+
logger.debug(f"Simplified SymPy expression: {simplified_expr}")
|
|
1108
|
+
|
|
1109
|
+
# Step 6: Convert back to TriccOperation if different
|
|
1110
|
+
if simplified_expr != sympy_expr:
|
|
1111
|
+
reconstructed = sympy_expr_to_tricc(simplified_expr)
|
|
1112
|
+
logger.debug(f"SymPy simplified {operation} to {reconstructed}")
|
|
1113
|
+
return reconstructed
|
|
1114
|
+
|
|
1115
|
+
except Exception as e:
|
|
1116
|
+
logger.warning(f"SymPy simplification failed for {operation}: {e}")
|
|
1117
|
+
|
|
1118
|
+
return operation
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
def apply_boolean_simplifications(operation):
|
|
1122
|
+
"""Apply custom boolean simplifications that SymPy might miss"""
|
|
1123
|
+
if not isinstance(operation, TriccOperation):
|
|
1124
|
+
return operation
|
|
1125
|
+
|
|
1126
|
+
if operation.operator == TriccOperator.OR:
|
|
1127
|
+
# Apply clean_or_list which includes our pattern recognition
|
|
1128
|
+
cleaned_list = clean_or_list(set(operation.reference))
|
|
1129
|
+
if len(cleaned_list) == 1:
|
|
1130
|
+
return cleaned_list[0]
|
|
1131
|
+
elif len(cleaned_list) != len(operation.reference):
|
|
1132
|
+
return TriccOperation(TriccOperator.OR, cleaned_list)
|
|
1133
|
+
|
|
1134
|
+
elif operation.operator == TriccOperator.AND:
|
|
1135
|
+
# Apply clean_and_list
|
|
1136
|
+
cleaned_list = clean_and_list(operation.reference)
|
|
1137
|
+
if len(cleaned_list) == 1:
|
|
1138
|
+
return cleaned_list[0]
|
|
1139
|
+
elif len(cleaned_list) != len(operation.reference):
|
|
1140
|
+
return TriccOperation(TriccOperator.AND, cleaned_list)
|
|
1141
|
+
|
|
1142
|
+
# Recursively apply to sub-operations
|
|
1143
|
+
simplified_refs = []
|
|
1144
|
+
changed = False
|
|
1145
|
+
for ref in operation.reference:
|
|
1146
|
+
if isinstance(ref, TriccOperation):
|
|
1147
|
+
simplified_ref = apply_boolean_simplifications(ref)
|
|
1148
|
+
if simplified_ref != ref:
|
|
1149
|
+
changed = True
|
|
1150
|
+
simplified_refs.append(simplified_ref)
|
|
1151
|
+
else:
|
|
1152
|
+
simplified_refs.append(ref)
|
|
1153
|
+
|
|
1154
|
+
if changed:
|
|
1155
|
+
return TriccOperation(operation.operator, simplified_refs)
|
|
1156
|
+
|
|
1157
|
+
return operation
|
|
1158
|
+
|
|
1159
|
+
|
|
780
1160
|
TriccGroup.update_forward_refs()
|
|
@@ -13,7 +13,8 @@ from pyxform import create_survey_from_xls
|
|
|
13
13
|
from tricc_oo.converters.utils import clean_name
|
|
14
14
|
from tricc_oo.models.base import (
|
|
15
15
|
TriccOperator,
|
|
16
|
-
TriccOperation, TriccStatic, TriccReference
|
|
16
|
+
TriccOperation, TriccStatic, TriccReference,
|
|
17
|
+
simplify_with_sympy
|
|
17
18
|
)
|
|
18
19
|
from tricc_oo.models.ordered_set import OrderedSet
|
|
19
20
|
from tricc_oo.models.calculate import (
|
|
@@ -379,6 +380,9 @@ class XLSFormStrategy(BaseOutPutStrategy):
|
|
|
379
380
|
return processed_nodes
|
|
380
381
|
|
|
381
382
|
def get_tricc_operation_expression(self, operation):
|
|
383
|
+
# Apply SymPy boolean simplification for boolean operations
|
|
384
|
+
#operation = simplify_with_sympy(operation)
|
|
385
|
+
|
|
382
386
|
ref_expressions = []
|
|
383
387
|
original_references = []
|
|
384
388
|
if not hasattr(operation, "reference"):
|
tricc_oo/visitors/tricc.py
CHANGED
|
@@ -126,7 +126,7 @@ def get_last_version(name, processed_nodes, _list=None):
|
|
|
126
126
|
def get_node_expressions(node, processed_nodes, process=None):
|
|
127
127
|
get_overall_exp = issubclass(
|
|
128
128
|
node.__class__,
|
|
129
|
-
(TriccNodeDisplayCalculateBase, TriccNodeProposedDiagnosis, TriccNodeDiagnosis)
|
|
129
|
+
(TriccNodeDisplayCalculateBase, TriccNodeProposedDiagnosis, TriccNodeDiagnosis, TriccNodeActivity)
|
|
130
130
|
) and not isinstance(node, (TriccNodeDisplayBridge))
|
|
131
131
|
expression = None
|
|
132
132
|
# in case of recursive call processed_nodes will be None
|
|
@@ -176,7 +176,7 @@ def get_version_inheritance(node, all_prev_versions, processed_nodes):
|
|
|
176
176
|
expression = node.expression or node.expression_reference or getattr(node, "relevance", None)
|
|
177
177
|
# Merge with ALL previous versions, not just the last one
|
|
178
178
|
if all_prev_versions:
|
|
179
|
-
expression =
|
|
179
|
+
expression = merge_expressions(expression, *all_prev_versions)
|
|
180
180
|
if node.expression:
|
|
181
181
|
node.expression = expression
|
|
182
182
|
elif node.expression_reference:
|
|
@@ -216,39 +216,15 @@ def get_version_inheritance(node, all_prev_versions, processed_nodes):
|
|
|
216
216
|
node.expression = TriccOperation(TriccOperator.COALESCE, coalesce_operands)
|
|
217
217
|
|
|
218
218
|
|
|
219
|
-
def
|
|
219
|
+
def merge_expressions(expression, last_version, *argv):
|
|
220
220
|
datatype = expression.get_datatype()
|
|
221
221
|
if datatype == "boolean":
|
|
222
|
-
expression = or_join([TriccOperation(TriccOperator.ISTRUE, [last_version]), expression])
|
|
222
|
+
expression = or_join([TriccOperation(TriccOperator.ISTRUE, [last_version, *argv]), expression])
|
|
223
223
|
|
|
224
224
|
elif datatype == "number":
|
|
225
|
-
expression = TriccOperation(TriccOperator.PLUS, [last_version, expression])
|
|
225
|
+
expression = TriccOperation(TriccOperator.PLUS, [last_version, *argv, expression])
|
|
226
226
|
else:
|
|
227
|
-
expression = TriccOperation(TriccOperator.COALESCE, [last_version,
|
|
228
|
-
return expression
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def merge_all_expressions(expression, all_versions):
|
|
232
|
-
"""
|
|
233
|
-
Merge an expression with ALL previous versions, not just the last one.
|
|
234
|
-
This ensures inheritance works even when intermediate versions weren't evaluated
|
|
235
|
-
due to activity relevance conditions.
|
|
236
|
-
"""
|
|
237
|
-
if not all_versions:
|
|
238
|
-
return expression
|
|
239
|
-
|
|
240
|
-
datatype = expression.get_datatype() if expression else "unknown"
|
|
241
|
-
|
|
242
|
-
if datatype == "boolean":
|
|
243
|
-
expression = or_join([expression, *all_versions])
|
|
244
|
-
|
|
245
|
-
else:
|
|
246
|
-
# COALESCE through all previous versions, then the current expression
|
|
247
|
-
coalesce_operands = list(all_versions)
|
|
248
|
-
if expression:
|
|
249
|
-
coalesce_operands.append(expression)
|
|
250
|
-
expression = TriccOperation(TriccOperator.COALESCE, coalesce_operands)
|
|
251
|
-
|
|
227
|
+
expression = TriccOperation(TriccOperator.COALESCE, [expression, last_version, *argv])
|
|
252
228
|
return expression
|
|
253
229
|
|
|
254
230
|
|
|
@@ -315,14 +291,23 @@ def load_calculate(
|
|
|
315
291
|
add_used_calculate(node, r, calculates, used_calculates, processed_nodes)
|
|
316
292
|
|
|
317
293
|
if last_version and hasattr(node, "relevance"):
|
|
294
|
+
last_expressions_other_activity = [
|
|
295
|
+
and_join([TriccOperation(TriccOperator.ISTRUE,[l]),l.activity.root]) for l in all_prev_versions if (
|
|
296
|
+
node.is_sequence_defined and
|
|
297
|
+
node.activity.base_instance != l.activity.base_instance
|
|
298
|
+
)
|
|
299
|
+
]
|
|
300
|
+
last_expression_same_activity = [
|
|
301
|
+
TriccOperation(TriccOperator.ISTRUE,l) for l in all_prev_versions if (
|
|
302
|
+
node.is_sequence_defined and
|
|
303
|
+
node.activity == l.activity
|
|
304
|
+
)
|
|
305
|
+
]
|
|
306
|
+
last_version_relevance = [*last_expressions_other_activity, *last_expression_same_activity]
|
|
318
307
|
if isinstance(node, TriccNodeInputModel):
|
|
319
308
|
version_relevance = TriccOperation(TriccOperator.ISNULL, [last_version])
|
|
320
|
-
elif
|
|
321
|
-
version_relevance = not_clean(
|
|
322
|
-
elif last_version.activity.relevance:
|
|
323
|
-
version_relevance = not_clean(
|
|
324
|
-
last_version.activity.relevance,
|
|
325
|
-
)
|
|
309
|
+
elif last_version_relevance:
|
|
310
|
+
version_relevance = not_clean(or_join(last_version_relevance))
|
|
326
311
|
else:
|
|
327
312
|
version_relevance = None
|
|
328
313
|
|
|
@@ -582,7 +567,7 @@ def generate_calculates(node, calculates, used_calculates, processed_nodes, proc
|
|
|
582
567
|
node.activity.calculates.append(calc_node)
|
|
583
568
|
last_version = set_last_version_false(calc_node, processed_nodes)
|
|
584
569
|
if last_version:
|
|
585
|
-
calc_node.expression =
|
|
570
|
+
calc_node.expression = merge_expressions(calc_node.expression, last_version)
|
|
586
571
|
processed_nodes.add(calc_node)
|
|
587
572
|
logger.debug(
|
|
588
573
|
"generate_save_calculate:{}:{} as {}".format(
|
|
@@ -615,7 +600,7 @@ def generate_calculates(node, calculates, used_calculates, processed_nodes, proc
|
|
|
615
600
|
node.activity.calculates.append(calc_node)
|
|
616
601
|
last_version = set_last_version_false(calc_node, processed_nodes)
|
|
617
602
|
if last_version:
|
|
618
|
-
calc_node.expression =
|
|
603
|
+
calc_node.expression = merge_expressions(calc_node.expression, last_version)
|
|
619
604
|
processed_nodes.add(calc_node)
|
|
620
605
|
list_calc.append(calc_node)
|
|
621
606
|
node.activity.nodes[calc_node.id] = calc_node
|
|
@@ -1988,14 +1973,25 @@ def get_node_expression(in_node, processed_nodes, get_overall_exp=False, is_prev
|
|
|
1988
1973
|
(not is_prev or not ONE_QUESTION_AT_A_TIME)
|
|
1989
1974
|
and hasattr(node, "relevance")
|
|
1990
1975
|
and isinstance(node.relevance, (TriccOperation, TriccStatic))
|
|
1976
|
+
and getattr(node, 'is_sequence_defined', False)
|
|
1977
|
+
and not get_overall_exp
|
|
1991
1978
|
):
|
|
1992
1979
|
expression = node.relevance
|
|
1993
|
-
elif
|
|
1980
|
+
elif (
|
|
1981
|
+
ONE_QUESTION_AT_A_TIME
|
|
1982
|
+
and is_prev and not get_overall_exp
|
|
1983
|
+
and hasattr(node, "required")
|
|
1984
|
+
and node.required
|
|
1985
|
+
and getattr(node, 'is_sequence_defined', False)
|
|
1986
|
+
):
|
|
1994
1987
|
expression = get_required_node_expression(node)
|
|
1995
|
-
|
|
1996
1988
|
if expression is None:
|
|
1997
1989
|
expression = get_prev_node_expression(
|
|
1998
|
-
node,
|
|
1990
|
+
node,
|
|
1991
|
+
activity=node.activity,
|
|
1992
|
+
processed_nodes=processed_nodes,
|
|
1993
|
+
get_overall_exp=get_overall_exp,
|
|
1994
|
+
process=process
|
|
1999
1995
|
)
|
|
2000
1996
|
# in_node not in processed_nodes is need for calculates that can but run after the end of the activity
|
|
2001
1997
|
# if isinstance(node, TriccNodeActivitiy) and not prev:
|
|
@@ -2218,8 +2214,9 @@ def create_determine_diagnosis_activity(diags):
|
|
|
2218
2214
|
return activity
|
|
2219
2215
|
|
|
2220
2216
|
|
|
2221
|
-
def get_prev_node_expression(node, processed_nodes, get_overall_exp=False, excluded_name=None, process=None):
|
|
2217
|
+
def get_prev_node_expression(node, activity, processed_nodes, get_overall_exp=False, excluded_name=None, process=None):
|
|
2222
2218
|
expression = None
|
|
2219
|
+
sub = None
|
|
2223
2220
|
if node is None:
|
|
2224
2221
|
pass
|
|
2225
2222
|
# when getting the prev node, we calculate the
|
|
@@ -2228,12 +2225,19 @@ def get_prev_node_expression(node, processed_nodes, get_overall_exp=False, exclu
|
|
|
2228
2225
|
expression_inputs = clean_or_list(expression_inputs)
|
|
2229
2226
|
else:
|
|
2230
2227
|
expression_inputs = []
|
|
2231
|
-
prev_activities = {}
|
|
2228
|
+
prev_activities = {node.activity.id: []}
|
|
2229
|
+
# sorting prev_nodes per activity
|
|
2230
|
+
|
|
2232
2231
|
for prev_node in node.prev_nodes:
|
|
2233
2232
|
if prev_node.activity.id not in prev_activities:
|
|
2234
2233
|
prev_activities[prev_node.activity.id] = []
|
|
2234
|
+
if isinstance(prev_node, TriccNodeActivity):
|
|
2235
|
+
for a_prev_node in prev_node.prev_nodes:
|
|
2236
|
+
# if we share the calling contect of the activity
|
|
2237
|
+
if a_prev_node.activity == node.activity:
|
|
2238
|
+
prev_activities[node.activity.id].append(a_prev_node)
|
|
2235
2239
|
prev_activities[prev_node.activity.id].append(prev_node)
|
|
2236
|
-
|
|
2240
|
+
# get the or_list expression of all the node per activity
|
|
2237
2241
|
for act_id in prev_activities:
|
|
2238
2242
|
act_expression_inputs = []
|
|
2239
2243
|
none_sequence_defined_prev_node = False
|
|
@@ -2250,29 +2254,36 @@ def get_prev_node_expression(node, processed_nodes, get_overall_exp=False, exclu
|
|
|
2250
2254
|
)
|
|
2251
2255
|
):
|
|
2252
2256
|
# the rhombus should calculate only reference
|
|
2257
|
+
# expression from one prev node
|
|
2253
2258
|
sub = get_node_expression(
|
|
2254
2259
|
prev_node,
|
|
2255
2260
|
processed_nodes=processed_nodes,
|
|
2256
2261
|
get_overall_exp=get_overall_exp,
|
|
2257
2262
|
is_prev=True,
|
|
2258
|
-
process=
|
|
2259
|
-
)
|
|
2260
|
-
if
|
|
2263
|
+
process=process,
|
|
2264
|
+
) or TriccStatic(True)
|
|
2265
|
+
# if it is an activity or overall then we add the sub to act expression
|
|
2266
|
+
# else we update directly the node releavance subs
|
|
2267
|
+
if node.activity.id != act_id or get_overall_exp:
|
|
2261
2268
|
add_sub_expression(act_expression_inputs, sub)
|
|
2262
2269
|
else:
|
|
2263
2270
|
add_sub_expression(expression_inputs, sub)
|
|
2264
|
-
|
|
2271
|
+
# if cur prev node part of prev act elvaluated have some relevance we make an AND with prev act relevance
|
|
2265
2272
|
if act_expression_inputs:
|
|
2266
2273
|
act_sub = or_join(act_expression_inputs)
|
|
2267
2274
|
# if there is condition fallback on the calling activity condition
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2275
|
+
if prev_node.activity.relevance and prev_node.activity.relevance != TriccStatic(True):
|
|
2276
|
+
act_relevance = TriccOperation(TriccOperator.ISTRUE, [prev_node.activity.root])
|
|
2277
|
+
else:
|
|
2278
|
+
act_relevance = TriccStatic(True)
|
|
2279
|
+
# get_node_expression(
|
|
2280
|
+
# prev_node.activity,
|
|
2281
|
+
# processed_nodes=processed_nodes,
|
|
2282
|
+
# get_overall_exp=get_overall_exp,
|
|
2283
|
+
# is_prev=True,
|
|
2284
|
+
# negate=False,
|
|
2285
|
+
# process=process,
|
|
2286
|
+
# )
|
|
2276
2287
|
if act_sub == TriccStatic(True):
|
|
2277
2288
|
act_sub = act_relevance
|
|
2278
2289
|
elif act_relevance != TriccStatic(True) and none_sequence_defined_prev_node:
|
|
@@ -2557,6 +2568,7 @@ def get_calculation_terms(node, processed_nodes, get_overall_exp=False, negate=F
|
|
|
2557
2568
|
# because calculate are not the the activity group
|
|
2558
2569
|
elif isinstance(node, (TriccNodeActivityStart)) and get_overall_exp:
|
|
2559
2570
|
expression = get_prev_node_expression(
|
|
2571
|
+
node.activity,
|
|
2560
2572
|
node.activity,
|
|
2561
2573
|
processed_nodes=processed_nodes,
|
|
2562
2574
|
get_overall_exp=get_overall_exp,
|
|
@@ -2605,7 +2617,7 @@ def get_calculation_terms(node, processed_nodes, get_overall_exp=False, negate=F
|
|
|
2605
2617
|
expression = node.expression_reference
|
|
2606
2618
|
elif expression is None:
|
|
2607
2619
|
expression = get_prev_node_expression(
|
|
2608
|
-
node, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
|
|
2620
|
+
node, node.activity, processed_nodes=processed_nodes, get_overall_exp=get_overall_exp, process=process
|
|
2609
2621
|
)
|
|
2610
2622
|
|
|
2611
2623
|
# manage the generic negation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tricc-oo
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.27
|
|
4
4
|
Summary: Python library that converts CDSS L2 in L3
|
|
5
5
|
Project-URL: Homepage, https://github.com/SwissTPH/tricc
|
|
6
6
|
Project-URL: Issues, https://github.com/SwissTPH/tricc/issues
|
|
@@ -25,6 +25,7 @@ Requires-Dist: antlr4-tools==0.2.1
|
|
|
25
25
|
Requires-Dist: beautifulsoup4
|
|
26
26
|
Requires-Dist: ocldev
|
|
27
27
|
Requires-Dist: pyxform
|
|
28
|
+
Requires-Dist: Sympy
|
|
28
29
|
Dynamic: license-file
|
|
29
30
|
|
|
30
31
|
# TRICC-OO
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
tests/build.py,sha256=
|
|
1
|
+
tests/build.py,sha256=d_8QDUem7e77u_1BRE96xn9VXbG8N4L9pgpgG9fVWRw,6747
|
|
2
|
+
tests/test_clean_and_list.py,sha256=S8CcYHbnttToZy1COkN4PWtIiHuOFCD3dY9gFiVuxSI,4892
|
|
2
3
|
tests/test_cql.py,sha256=IRfjrmcxMn60XlAQLUur-7OUELs1NioqxRXWcOf8QcQ,5678
|
|
3
4
|
tests/to_ocl.py,sha256=4e-i65K3UM6wHgdVcrZcM9AyL1bahIsXJiZTXhhHgQk,2048
|
|
4
5
|
tricc_oo/__init__.py,sha256=oWCE1ubmC_6iqaWOMgTei4eXVQgV202Ia-tXS1NnW_4,139
|
|
@@ -15,7 +16,7 @@ tricc_oo/converters/cql/cqlListener.py,sha256=fA7-8DcS2Q69ckwjdg57-OfFHBxjTZFdoS
|
|
|
15
16
|
tricc_oo/converters/cql/cqlParser.py,sha256=x3KdrwX9nwENSEJ5Ex7_l5NMnu3kWBO0uLdYu4moTq0,414745
|
|
16
17
|
tricc_oo/converters/cql/cqlVisitor.py,sha256=iHuup2S7OGSVWLEcI4H3oecRqgXztC1sKnew_1P2iGY,33880
|
|
17
18
|
tricc_oo/models/__init__.py,sha256=CgS52LLqdDIaXHvZy08hhu_VaYw80OEdfL_llM9ICBA,108
|
|
18
|
-
tricc_oo/models/base.py,sha256=
|
|
19
|
+
tricc_oo/models/base.py,sha256=N2gPlAwCQxIiGJQjfu_49c9DkO3EjgJ1LirFgPNkSfQ,42422
|
|
19
20
|
tricc_oo/models/calculate.py,sha256=uNP0IDUqPQcJq9Co05H8eX5wbR_DikSxuOHxfVE5Dxg,8018
|
|
20
21
|
tricc_oo/models/lang.py,sha256=ZMRwdoPWe01wEDhOM0uRk-6rt3BkoAAZM8mZ61--s3A,2265
|
|
21
22
|
tricc_oo/models/ocl.py,sha256=MybSeB6fgCOUVJ4aektff0vrrTZsyfwZ2Gt_pPBu_FY,8728
|
|
@@ -29,23 +30,23 @@ tricc_oo/serializers/xls_form.py,sha256=SZPvZK6y4l_2v3HuGWITHmKd5rTClhHWvbUU3Ren
|
|
|
29
30
|
tricc_oo/strategies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
31
|
tricc_oo/strategies/input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
32
|
tricc_oo/strategies/input/base_input_strategy.py,sha256=BEODXS74na1QRRcJVQ4cxiD8F7uRqaLyhE3QzKpGVvk,3891
|
|
32
|
-
tricc_oo/strategies/input/drawio.py,sha256=
|
|
33
|
+
tricc_oo/strategies/input/drawio.py,sha256=VCKAr_r-jJ_xJlyCMCH2-qSE2KIvc7fmR2y4X9QMv3k,12768
|
|
33
34
|
tricc_oo/strategies/output/base_output_strategy.py,sha256=i9L5CVUqkEAMNyBsdHJ4xA7Nptr3myHr_fHHveDX1cU,8928
|
|
34
35
|
tricc_oo/strategies/output/dhis2_form.py,sha256=jW9NW72_61ch1bHm8ShIH4xsJH-HMlZGPTT5txJxMUk,38278
|
|
35
36
|
tricc_oo/strategies/output/fhir_form.py,sha256=hbL921pe1Doun4IQrJuZ_Sq2fCh98G3grYie5olC4uc,15740
|
|
36
37
|
tricc_oo/strategies/output/html_form.py,sha256=qSleEZOMV_-Z04y-i-ucyd5rgAYWAyjPwMrw0IHtCRM,8604
|
|
37
38
|
tricc_oo/strategies/output/openmrs_form.py,sha256=ne6TwAyhafR-WDs27QTKKFl85VD5sij_VEJtK6ZjOIE,28996
|
|
38
39
|
tricc_oo/strategies/output/spice.py,sha256=QMeoismVC3PdbvwTK0PtUjWX9jl9780fbQIXn76fMXw,10761
|
|
39
|
-
tricc_oo/strategies/output/xls_form.py,sha256=
|
|
40
|
+
tricc_oo/strategies/output/xls_form.py,sha256=n_C9J1_FGcwtnXePBbPUd1OTuCpdbNEzt_o6sBGqsCg,34038
|
|
40
41
|
tricc_oo/strategies/output/xlsform_cdss.py,sha256=X00Lt5MzV8TX14dR4dFI1MqllI5S1e13bKbeysWM9uA,17435
|
|
41
42
|
tricc_oo/strategies/output/xlsform_cht.py,sha256=66sTRqVL9ZUL8NpX2f0xCRQ-siUKcKphosR9y7wsbuM,28326
|
|
42
43
|
tricc_oo/strategies/output/xlsform_cht_hf.py,sha256=xm6SKirV3nMZvM2w54_zJcXAeAgAkq-EEqGEjnOWv6c,988
|
|
43
44
|
tricc_oo/visitors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
-
tricc_oo/visitors/tricc.py,sha256=
|
|
45
|
+
tricc_oo/visitors/tricc.py,sha256=vZebJR4gF-VJxNv1qZeTU08VrzAMjMsTX58artHtZKI,115411
|
|
45
46
|
tricc_oo/visitors/utils.py,sha256=j83aAq5s5atXi3OC0jc_uJd54a8XrHHmizeeEbWZQJg,421
|
|
46
47
|
tricc_oo/visitors/xform_pd.py,sha256=ryAnI3V9x3eTmJ2LNsUZfvl0_yfCqo6oBgeSu-WPqaE,9613
|
|
47
|
-
tricc_oo-1.6.
|
|
48
|
-
tricc_oo-1.6.
|
|
49
|
-
tricc_oo-1.6.
|
|
50
|
-
tricc_oo-1.6.
|
|
51
|
-
tricc_oo-1.6.
|
|
48
|
+
tricc_oo-1.6.27.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
|
|
49
|
+
tricc_oo-1.6.27.dist-info/METADATA,sha256=JXCMTGTqMLUAzxIHCZ5JoXThXxyJCOzYJLC7qQAewlM,8621
|
|
50
|
+
tricc_oo-1.6.27.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
51
|
+
tricc_oo-1.6.27.dist-info/top_level.txt,sha256=NvbfMNAiy9m4b1unBsqpeOQWh4IgA1Xa33BtKA4abxk,15
|
|
52
|
+
tricc_oo-1.6.27.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|