implica 0.3.3__py3-none-any.whl → 0.3.4__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.

Potentially problematic release.


This version of implica might be problematic. Click here for more details.

implica/__init__.py CHANGED
@@ -41,4 +41,4 @@ __all__ = [
41
41
  "mutations",
42
42
  ]
43
43
 
44
- __version__ = "0.3.3"
44
+ __version__ = "0.3.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: implica
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: A package for working with graphs representing minimal implicational logic models
5
5
  Author: Carlos Fernandez
6
6
  Author-email: carlos.ferlo@outlook.com
@@ -24,6 +24,7 @@ A Python package for working with graphs representing minimal implicational logi
24
24
  ## Features
25
25
 
26
26
  - 🎯 **Type System**: Build complex type expressions using variables and applications (function types)
27
+ - 🔍 **Variable Extraction**: Recursively extract all variables from any type expression
27
28
  - 🧩 **Combinators**: Work with S and K combinators from combinatory logic
28
29
  - 📊 **Graph Structure**: Represent type transformations as nodes and edges in a directed graph
29
30
  - 🔄 **Transactional Operations**: Safely modify graphs with automatic rollback on failure
@@ -106,6 +107,43 @@ print(complex_function) # Output: (A -> B) -> C
106
107
  print(nested_function) # Output: A -> B -> C
107
108
  ```
108
109
 
110
+ #### Extracting Variables from Types
111
+
112
+ Every type has a `variables` property that returns a list of all variables contained in that type. This is computed recursively and may include duplicate variables if they appear multiple times:
113
+
114
+ ```python
115
+ import implica as imp
116
+
117
+ # Simple variable returns itself
118
+ A = imp.var("A")
119
+ print(A.variables) # Output: [Variable(name='A')]
120
+
121
+ # Application returns all variables from both input and output
122
+ B = imp.var("B")
123
+ func = imp.app(A, B)
124
+ print([v.name for v in func.variables]) # Output: ['A', 'B']
125
+
126
+ # Nested types return all variables recursively
127
+ C = imp.var("C")
128
+ nested = imp.app(imp.app(A, B), C) # (A -> B) -> C
129
+ print([v.name for v in nested.variables]) # Output: ['A', 'B', 'C']
130
+
131
+ # Duplicates are included
132
+ same_var = imp.app(A, A) # A -> A
133
+ print([v.name for v in same_var.variables]) # Output: ['A', 'A']
134
+
135
+ # Complex example with duplicates
136
+ complex = imp.app(imp.app(A, B), A) # (A -> B) -> A
137
+ print([v.name for v in complex.variables]) # Output: ['A', 'B', 'A']
138
+ ```
139
+
140
+ **Use cases:**
141
+
142
+ - Analyze which variables are used in a complex type expression
143
+ - Count occurrences of specific variables in a type
144
+ - Validate that certain variables are present or absent
145
+ - Generate variable lists for quantification or substitution operations
146
+
109
147
  ### Combinators
110
148
 
111
149
  Combinators represent transformations between types. The library includes the S and K combinators from combinatory logic:
@@ -800,6 +838,96 @@ ensure_graph_state(
800
838
  print(f"Final state: {graph.node_count()} nodes") # Output: 2 (X and Y)
801
839
  ```
802
840
 
841
+ ### Example 10: Analyzing Type Variables
842
+
843
+ Extract and analyze variables from complex type expressions:
844
+
845
+ ```python
846
+ import implica as imp
847
+
848
+ # Create a complex type expression
849
+ A = imp.var("A")
850
+ B = imp.var("B")
851
+ C = imp.var("C")
852
+
853
+ # ((A -> B) -> C) -> (A -> B)
854
+ inner = imp.app(A, B)
855
+ middle = imp.app(inner, C)
856
+ complex_type = imp.app(middle, inner)
857
+
858
+ print(f"Type: {complex_type}")
859
+ # Output: ((A -> B) -> C) -> A -> B
860
+
861
+ # Get all variables (including duplicates)
862
+ variables = complex_type.variables
863
+ print(f"All variables: {[v.name for v in variables]}")
864
+ # Output: ['A', 'B', 'C', 'A', 'B']
865
+
866
+ # Count unique variables
867
+ unique_vars = {v.name for v in variables}
868
+ print(f"Unique variables: {unique_vars}")
869
+ # Output: {'A', 'B', 'C'}
870
+
871
+ # Count occurrences
872
+ from collections import Counter
873
+ var_counts = Counter(v.name for v in variables)
874
+ print(f"Variable counts: {dict(var_counts)}")
875
+ # Output: {'A': 2, 'B': 2, 'C': 1}
876
+
877
+ # Check if a specific variable is used
878
+ def uses_variable(type_expr, var_name):
879
+ """Check if a type expression uses a specific variable."""
880
+ return any(v.name == var_name for v in type_expr.variables)
881
+
882
+ print(f"Uses A: {uses_variable(complex_type, 'A')}") # Output: True
883
+ print(f"Uses D: {uses_variable(complex_type, 'D')}") # Output: False
884
+
885
+ # Find all types in a graph that use a specific variable
886
+ graph = imp.Graph()
887
+
888
+ # Create various types
889
+ types_to_add = [
890
+ imp.var("X"),
891
+ imp.var("Y"),
892
+ imp.app(A, B),
893
+ imp.app(B, C),
894
+ imp.app(A, imp.app(B, C)),
895
+ ]
896
+
897
+ with graph.connect() as conn:
898
+ for t in types_to_add:
899
+ conn.add_node(imp.node(t))
900
+
901
+ # Find all nodes containing variable "B"
902
+ nodes_with_B = [
903
+ n for n in graph.nodes()
904
+ if any(v.name == "B" for v in n.type.variables)
905
+ ]
906
+
907
+ print(f"\nNodes containing variable B:")
908
+ for n in nodes_with_B:
909
+ print(f" - {n.type}")
910
+ # Output:
911
+ # - A -> B
912
+ # - B -> C
913
+ # - A -> B -> C
914
+
915
+ # Calculate the "complexity" of a type by counting its variables
916
+ def type_complexity(type_expr):
917
+ """Calculate complexity as the total number of variables."""
918
+ return len(type_expr.variables)
919
+
920
+ print(f"\nType complexities:")
921
+ for n in graph.nodes():
922
+ print(f" {n.type}: {type_complexity(n.type)}")
923
+ # Output:
924
+ # X: 1
925
+ # Y: 1
926
+ # A -> B: 2
927
+ # B -> C: 2
928
+ # A -> B -> C: 3
929
+ ```
930
+
803
931
  ## API Reference
804
932
 
805
933
  ### Core Module (`implica.core`)
@@ -809,7 +937,14 @@ print(f"Final state: {graph.node_count()} nodes") # Output: 2 (X and Y)
809
937
  - `var(name: str) -> Variable`: Create a type variable
810
938
  - `app(input_type: BaseType, output_type: BaseType) -> Application`: Create a function type
811
939
  - `Variable`: Atomic type variable
940
+ - `name: str`: The name of the variable
941
+ - `uid: str`: Unique identifier (SHA256 hash)
942
+ - `variables: list[Variable]`: Returns `[self]`
812
943
  - `Application`: Function application type
944
+ - `input_type: BaseType`: Input type of the function
945
+ - `output_type: BaseType`: Output type of the function
946
+ - `uid: str`: Unique identifier (SHA256 hash)
947
+ - `variables: list[Variable]`: Returns all variables from input and output types (may include duplicates)
813
948
 
814
949
  **Combinators:**
815
950
 
@@ -1,4 +1,4 @@
1
- implica/__init__.py,sha256=0mZ2GjzddOh36dHFon3fW8RIykgyO5KNwYQ5_9RR-Yc,886
1
+ implica/__init__.py,sha256=JR7cwJGh-_dtyoakg60HHJDR1609uEKm1TGUfZvij2M,886
2
2
  implica/core/__init__.py,sha256=opdPtga0OU0d8CEf5DL4Xl4AriBaOHdVW4mbwdD2A0Y,191
3
3
  implica/core/combinator.py,sha256=VOeIj_FRMI7fmuMjjbgRBP-FvExnQ6vOjCD-egt96lI,4324
4
4
  implica/core/types.py,sha256=AtzQAY9rJ4lIcjqdVZHLDOO-YXSudez4NOzaw6EPjRc,5230
@@ -24,7 +24,7 @@ implica/mutations/try_remove_edge.py,sha256=2aeg6f6nR49MViyZk15-ys7I5Xt0a2wXycBI
24
24
  implica/mutations/try_remove_many_edges.py,sha256=pgZdqFltMaycNBfdjejYVXQZw3i2K1AJYYcsaKk7n74,1596
25
25
  implica/mutations/try_remove_many_nodes.py,sha256=DK_BtKuEh_7zm5bzryOi1BVfmuCiQ-SVA9yIdgN-imE,1817
26
26
  implica/mutations/try_remove_node.py,sha256=igTEnGUCd0U2_3Rr5SIOSIs4FZmYi2Y6bLk0Ae64Bsg,1837
27
- implica-0.3.3.dist-info/LICENSE,sha256=jDn9mmsCvjx_av9marP7DBqjfmK1gsQmgycgBRC2Eck,1073
28
- implica-0.3.3.dist-info/METADATA,sha256=d6yVeAJq0yVrKVdMcBxgEu8-SUkcpH0f2GnePDPE4sU,25200
29
- implica-0.3.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
30
- implica-0.3.3.dist-info/RECORD,,
27
+ implica-0.3.4.dist-info/LICENSE,sha256=jDn9mmsCvjx_av9marP7DBqjfmK1gsQmgycgBRC2Eck,1073
28
+ implica-0.3.4.dist-info/METADATA,sha256=V7CQS-JUebHQ2Td0QWZ2xyRk_TcZK7xvVvXD0r6x2hQ,29208
29
+ implica-0.3.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
30
+ implica-0.3.4.dist-info/RECORD,,