relationalai 0.12.4__py3-none-any.whl → 0.12.7__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 (116) hide show
  1. relationalai/__init__.py +4 -0
  2. relationalai/clients/snowflake.py +34 -13
  3. relationalai/early_access/lqp/constructors/__init__.py +2 -2
  4. relationalai/early_access/metamodel/rewrite/__init__.py +2 -2
  5. relationalai/{semantics/reasoners/graph → experimental}/paths/README.md +2 -2
  6. relationalai/experimental/paths/__init__.py +14 -309
  7. relationalai/{semantics/reasoners/graph → experimental}/paths/examples/basic_example.py +2 -2
  8. relationalai/{semantics/reasoners/graph → experimental}/paths/examples/paths_benchmark.py +2 -2
  9. relationalai/{semantics/reasoners/graph → experimental}/paths/examples/paths_example.py +2 -2
  10. relationalai/{semantics/reasoners/graph → experimental}/paths/examples/pattern_to_automaton.py +1 -1
  11. relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/one_sided_ball_repetition.py +1 -1
  12. relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/single.py +3 -3
  13. relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/two_sided_balls_repetition.py +1 -1
  14. relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/two_sided_balls_upto.py +2 -2
  15. relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/usp-old.py +3 -3
  16. relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/usp-tuple.py +3 -3
  17. relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/usp.py +3 -3
  18. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_limit_sp_max_length.py +2 -2
  19. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_limit_sp_multiple.py +2 -2
  20. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_limit_sp_single.py +2 -2
  21. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_limit_walks_multiple.py +2 -2
  22. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_limit_walks_single.py +2 -2
  23. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_one_sided_ball_repetition_multiple.py +2 -2
  24. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_one_sided_ball_repetition_single.py +2 -2
  25. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_one_sided_ball_upto_multiple.py +2 -2
  26. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_one_sided_ball_upto_single.py +2 -2
  27. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_single_paths.py +2 -2
  28. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_single_walks.py +2 -2
  29. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_single_walks_undirected.py +2 -2
  30. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_two_sided_balls_repetition_multiple.py +2 -2
  31. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_two_sided_balls_repetition_single.py +2 -2
  32. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_two_sided_balls_upto_multiple.py +2 -2
  33. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_two_sided_balls_upto_single.py +2 -2
  34. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_usp_nsp_multiple.py +2 -2
  35. relationalai/{semantics/reasoners/graph → experimental}/paths/tests/tests_usp_nsp_single.py +2 -2
  36. relationalai/semantics/__init__.py +4 -0
  37. relationalai/semantics/internal/annotations.py +1 -0
  38. relationalai/semantics/internal/internal.py +3 -4
  39. relationalai/semantics/internal/snowflake.py +14 -1
  40. relationalai/semantics/lqp/builtins.py +1 -0
  41. relationalai/semantics/lqp/constructors.py +0 -5
  42. relationalai/semantics/lqp/executor.py +34 -10
  43. relationalai/semantics/lqp/intrinsics.py +2 -2
  44. relationalai/semantics/lqp/model2lqp.py +105 -9
  45. relationalai/semantics/lqp/passes.py +27 -8
  46. relationalai/semantics/lqp/primitives.py +18 -15
  47. relationalai/semantics/lqp/rewrite/__init__.py +2 -2
  48. relationalai/semantics/lqp/rewrite/{fd_constraints.py → function_annotations.py} +4 -4
  49. relationalai/semantics/lqp/utils.py +17 -13
  50. relationalai/semantics/metamodel/builtins.py +50 -1
  51. relationalai/semantics/metamodel/typer/typer.py +3 -0
  52. relationalai/semantics/reasoners/__init__.py +4 -0
  53. relationalai/semantics/reasoners/experimental/__init__.py +7 -0
  54. relationalai/semantics/reasoners/graph/core.py +1154 -122
  55. relationalai/semantics/rel/builtins.py +3 -1
  56. relationalai/semantics/rel/compiler.py +2 -2
  57. relationalai/semantics/rel/executor.py +30 -8
  58. relationalai/semantics/rel/rel_utils.py +5 -0
  59. relationalai/semantics/snowflake/__init__.py +2 -2
  60. relationalai/semantics/sql/compiler.py +6 -0
  61. relationalai/semantics/sql/executor/snowflake.py +6 -2
  62. relationalai/semantics/tests/test_snapshot_abstract.py +5 -4
  63. {relationalai-0.12.4.dist-info → relationalai-0.12.7.dist-info}/METADATA +2 -2
  64. {relationalai-0.12.4.dist-info → relationalai-0.12.7.dist-info}/RECORD +99 -115
  65. {relationalai-0.12.4.dist-info → relationalai-0.12.7.dist-info}/WHEEL +1 -1
  66. relationalai/early_access/paths/__init__.py +0 -22
  67. relationalai/early_access/paths/api/__init__.py +0 -12
  68. relationalai/early_access/paths/benchmarks/__init__.py +0 -13
  69. relationalai/early_access/paths/graph/__init__.py +0 -12
  70. relationalai/early_access/paths/path_algorithms/find_paths/__init__.py +0 -12
  71. relationalai/early_access/paths/path_algorithms/one_sided_ball_repetition/__init__.py +0 -12
  72. relationalai/early_access/paths/path_algorithms/one_sided_ball_upto/__init__.py +0 -12
  73. relationalai/early_access/paths/path_algorithms/single/__init__.py +0 -12
  74. relationalai/early_access/paths/path_algorithms/two_sided_balls_repetition/__init__.py +0 -12
  75. relationalai/early_access/paths/path_algorithms/two_sided_balls_upto/__init__.py +0 -12
  76. relationalai/early_access/paths/path_algorithms/usp/__init__.py +0 -12
  77. relationalai/early_access/paths/rpq/__init__.py +0 -13
  78. relationalai/early_access/paths/utilities/iterators/__init__.py +0 -12
  79. relationalai/experimental/paths/pathfinder.rel +0 -2560
  80. relationalai/semantics/reasoners/graph/paths/__init__.py +0 -16
  81. relationalai/semantics/reasoners/graph/paths/path_algorithms/__init__.py +0 -3
  82. relationalai/semantics/reasoners/graph/paths/utilities/__init__.py +0 -3
  83. /relationalai/{semantics/reasoners/graph → experimental}/paths/api.py +0 -0
  84. /relationalai/{semantics/reasoners/graph → experimental}/paths/benchmarks/__init__.py +0 -0
  85. /relationalai/{semantics/reasoners/graph → experimental}/paths/benchmarks/grid_graph.py +0 -0
  86. /relationalai/{semantics/reasoners/graph → experimental}/paths/code_organization.md +0 -0
  87. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/Movies.ipynb +0 -0
  88. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/minimal_engine_warmup.py +0 -0
  89. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movie_example.py +0 -0
  90. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/actedin.csv +0 -0
  91. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/directed.csv +0 -0
  92. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/follows.csv +0 -0
  93. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/movies.csv +0 -0
  94. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/person.csv +0 -0
  95. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/produced.csv +0 -0
  96. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/ratings.csv +0 -0
  97. /relationalai/{semantics/reasoners/graph → experimental}/paths/examples/movies_data/wrote.csv +0 -0
  98. /relationalai/{semantics/reasoners/graph → experimental}/paths/find_paths_via_automaton.py +0 -0
  99. /relationalai/{semantics/reasoners/graph → experimental}/paths/graph.py +0 -0
  100. /relationalai/{early_access → experimental}/paths/path_algorithms/__init__.py +0 -0
  101. /relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/find_paths.py +0 -0
  102. /relationalai/{semantics/reasoners/graph → experimental}/paths/path_algorithms/one_sided_ball_upto.py +0 -0
  103. /relationalai/{semantics/reasoners/graph → experimental}/paths/product_graph.py +0 -0
  104. /relationalai/{semantics/reasoners/graph → experimental}/paths/rpq/__init__.py +0 -0
  105. /relationalai/{semantics/reasoners/graph → experimental}/paths/rpq/automaton.py +0 -0
  106. /relationalai/{semantics/reasoners/graph → experimental}/paths/rpq/diagnostics.py +0 -0
  107. /relationalai/{semantics/reasoners/graph → experimental}/paths/rpq/filter.py +0 -0
  108. /relationalai/{semantics/reasoners/graph → experimental}/paths/rpq/glushkov.py +0 -0
  109. /relationalai/{semantics/reasoners/graph → experimental}/paths/rpq/rpq.py +0 -0
  110. /relationalai/{semantics/reasoners/graph → experimental}/paths/rpq/transition.py +0 -0
  111. /relationalai/{early_access → experimental}/paths/utilities/__init__.py +0 -0
  112. /relationalai/{semantics/reasoners/graph → experimental}/paths/utilities/iterators.py +0 -0
  113. /relationalai/{semantics/reasoners/graph → experimental}/paths/utilities/prefix_sum.py +0 -0
  114. /relationalai/{semantics/reasoners/graph → experimental}/paths/utilities/utilities.py +0 -0
  115. {relationalai-0.12.4.dist-info → relationalai-0.12.7.dist-info}/entry_points.txt +0 -0
  116. {relationalai-0.12.4.dist-info → relationalai-0.12.7.dist-info}/licenses/LICENSE +0 -0
relationalai/__init__.py CHANGED
@@ -1,3 +1,7 @@
1
+ """
2
+ The RelationalAI Python SDK.
3
+ """
4
+
1
5
  from __future__ import annotations
2
6
  import importlib.metadata
3
7
 
@@ -834,19 +834,25 @@ Otherwise, remove it from your '{profile}' configuration profile.
834
834
  program_span_id: str | None = None,
835
835
  headers: Dict | None = None,
836
836
  ):
837
- """Only call _poll_use_index if there are sources to process."""
837
+ """Only call poll() if there are sources to process and cache is not valid."""
838
838
  sources_list = list(sources)
839
839
  self.database = model
840
840
  if sources_list:
841
- return self._poll_use_index(
842
- app_name=app_name,
843
- sources=sources_list,
844
- model=model,
845
- engine_name=engine_name,
846
- engine_size=engine_size,
847
- program_span_id=program_span_id,
848
- headers=headers,
841
+ poller = UseIndexPoller(
842
+ self,
843
+ app_name,
844
+ sources_list,
845
+ model,
846
+ engine_name,
847
+ engine_size,
848
+ self.language,
849
+ program_span_id,
850
+ headers,
851
+ self.generation
849
852
  )
853
+ # If cache is valid (data freshness has not expired), skip polling
854
+ if not poller.cache.is_valid():
855
+ return poller.poll()
850
856
 
851
857
  #--------------------------------------------------
852
858
  # Models
@@ -2836,6 +2842,15 @@ class SnowflakeTable(dsl.Type):
2836
2842
  else:
2837
2843
  self(snowflake_id=id).set(**{prop_ident: val})
2838
2844
 
2845
+ # Because we're bypassing a bunch of the normal Type.add machinery here,
2846
+ # we need to manually account for the case where people are using value types.
2847
+ def wrapped(x):
2848
+ if not model._config.get("compiler.use_value_types", False):
2849
+ return x
2850
+ other_id = dsl.create_var()
2851
+ model._action(dsl.build.construct(self._type, [x, other_id]))
2852
+ return other_id
2853
+
2839
2854
  # new UInt128 schema mapping rules
2840
2855
  with model.rule(dynamic=True, globalize=True, source=self._source):
2841
2856
  id = dsl.create_var()
@@ -2845,7 +2860,7 @@ class SnowflakeTable(dsl.Type):
2845
2860
  # for avoiding a non-blocking warning
2846
2861
  edb(dsl.Symbol("METADATA$KEY"), id)
2847
2862
  std.rel.UInt128(id)
2848
- self.add(id, snowflake_id=id)
2863
+ self.add(wrapped(id), snowflake_id=id)
2849
2864
 
2850
2865
  for prop, prop_type in self._schema["columns"].items():
2851
2866
  _prop = prop
@@ -2867,7 +2882,7 @@ class SnowflakeTable(dsl.Type):
2867
2882
  model._check_property(_prop._prop)
2868
2883
  raw_relation = getattr(std.rel, prop_ident)
2869
2884
  dsl.tag(raw_relation, dsl.Builtins.FunctionAnnotation)
2870
- raw_relation.add(id, val)
2885
+ raw_relation.add(wrapped(id), val)
2871
2886
 
2872
2887
  def namespace(self):
2873
2888
  return f"{self._parent._parent._name}.{self._parent._name}"
@@ -3450,19 +3465,25 @@ class DirectAccessResources(Resources):
3450
3465
  program_span_id: str | None = None,
3451
3466
  headers: Dict | None = None,
3452
3467
  ):
3453
- """Only call _poll_use_index if there are sources to process."""
3468
+ """Only call poll() if there are sources to process and cache is not valid."""
3454
3469
  sources_list = list(sources)
3455
3470
  self.database = model
3456
3471
  if sources_list:
3457
- return self._poll_use_index(
3472
+ poller = DirectUseIndexPoller(
3473
+ self,
3458
3474
  app_name=app_name,
3459
3475
  sources=sources_list,
3460
3476
  model=model,
3461
3477
  engine_name=engine_name,
3462
3478
  engine_size=engine_size,
3479
+ language=self.language,
3463
3480
  program_span_id=program_span_id,
3464
3481
  headers=headers,
3482
+ generation=self.generation,
3465
3483
  )
3484
+ # If cache is valid (data freshness has not expired), skip polling
3485
+ if not poller.cache.is_valid():
3486
+ return poller.poll()
3466
3487
 
3467
3488
  def _check_exec_async_status(self, txn_id: str, headers: Dict[str, str] | None = None) -> bool:
3468
3489
  """Check whether the given transaction has completed."""
@@ -2,12 +2,12 @@ import warnings
2
2
 
3
3
  from relationalai.semantics.lqp.constructors import (
4
4
  mk_abstraction, mk_and, mk_exists, mk_or, mk_pragma, mk_primitive,
5
- mk_specialized_value, mk_type, mk_value, mk_var
5
+ mk_specialized_value, mk_type, mk_value
6
6
  )
7
7
 
8
8
  __all__ = [
9
9
  "mk_abstraction", "mk_and", "mk_exists", "mk_or", "mk_pragma", "mk_primitive", "mk_specialized_value", "mk_type",
10
- "mk_value", "mk_var"
10
+ "mk_value"
11
11
  ]
12
12
 
13
13
  warnings.warn(
@@ -1,7 +1,7 @@
1
1
  from relationalai.semantics.metamodel.rewrite import Flatten, \
2
2
  DNFUnionSplitter, ExtractNestedLogicals, flatten
3
3
  from relationalai.semantics.lqp.rewrite import Splinter, \
4
- ExtractKeys, FDConstraints
4
+ ExtractKeys, FunctionAnnotations
5
5
 
6
6
  __all__ = ["Splinter", "Flatten", "DNFUnionSplitter", "ExtractKeys",
7
- "ExtractNestedLogicals", "FDConstraints", "flatten"]
7
+ "ExtractNestedLogicals", "FunctionAnnotations", "flatten"]
@@ -12,8 +12,8 @@ The following is a minimal working example:
12
12
  from relationalai.semantics import Model, Integer, select, String, where, define
13
13
  from relationalai.semantics.std import strings
14
14
 
15
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
16
- from relationalai.semantics.reasoners.graph.paths.api import node, edge, path, star, match
15
+ from relationalai.experimental.paths.graph import Graph
16
+ from relationalai.experimental.paths.api import node, edge, path, star, match
17
17
 
18
18
  model = Model("my_paths")
19
19
 
@@ -1,309 +1,14 @@
1
- import os
2
- from typing import List, Set, Tuple, Union
3
- import zipfile
4
- from enum import Enum
5
-
6
- from relationalai import dsl
7
- from relationalai.dsl import Graph, Instance, Type, Property, create_vars, get_graph, next_id
8
- from relationalai.metamodel import ActionType, Builtins
9
- from relationalai.std import rel
10
-
11
- class VarLength:
12
- def __init__(self, type: Type):
13
- self.type = type
14
- self.min = 1
15
- self.max = 1
16
-
17
- def __getitem__(self, key):
18
- if isinstance(key, slice):
19
- self.min = key.start
20
- self.max = key.stop
21
- else:
22
- raise ValueError("VarLength only supports slicing")
23
- return self
24
-
25
- class PathSelection(Enum):
26
- ALL = "all" # return all paths between source and target
27
- SINGLE = "single" # return a single path between source and target
28
- LIMIT = "limit" # return a specified number paths between source and target, as given by parameter k.
29
- RANDOM = "random" # return a single randomly-chosen path between source and target, seeded with parameter seed.
30
- UNIFORM_RANDOM = "uniform_random" # return a single uniform randomly-chosen path between source and target, seeded with parameter seed.
31
-
32
- class PathGroup(Enum):
33
- ANY = "any"
34
- FOREACH = "for_each"
35
-
36
- class Strategy(Enum):
37
- FROM_SOURCE = "from_source"
38
- TWO_SIDED = "two_sided"
39
-
40
- class PathQuery:
41
-
42
- def __init__(
43
- self,
44
- model: Graph,
45
- segments: List[Union[Instance,VarLength]],
46
- backwards_edge: str,
47
- group: PathGroup = PathGroup.FOREACH,
48
- selection: PathSelection = PathSelection.ALL,
49
- strategy: Strategy = Strategy.FROM_SOURCE,
50
- ):
51
- # create types and instance
52
- self._path_id = next_id()
53
- self._conn_relation_name = f"conn_{self._path_id}"
54
- self._model = model
55
-
56
- # create types
57
- self._Path = dsl.Type(model, f"Path{self._path_id}", omit_intrinsic_type_in_hash=True)
58
- self._PathNode = dsl.Type(model, f"PathNode{self._path_id}", omit_intrinsic_type_in_hash=True)
59
- self._PathEdge = dsl.Type(model, f"PathEdge{self._path_id}", omit_intrinsic_type_in_hash=True)
60
-
61
- # declare multivalued attributes
62
- self._Path.nodes.has_many()
63
- self._Path.edges.has_many()
64
-
65
- # mark these types and their attributes as @no_inline
66
- self._add_noinline(self._Path, [])
67
- self._add_noinline(self._PathNode, ["path", "index", "node_id"])
68
- self._add_noinline(self._PathEdge, ["path", "index", "label"])
69
-
70
- # create instance
71
- self._instance = self._Path()
72
- self._match_called = False
73
-
74
- # store path query attributes
75
- self._segments = segments
76
- self._backwards_edge = backwards_edge
77
- self._group = group
78
- self._selection = selection
79
- self._strategy = strategy
80
-
81
- def _add_noinline(self, typ, props):
82
- typ._type.parents.append(Builtins.NoInlineAnnotation)
83
- for prop in props:
84
- getattr(typ, prop)._prop.parents.append(Builtins.NoInlineAnnotation)
85
-
86
- def _match(self):
87
- # avoid emitting the Rel multiple times, which throws off Pathfinder
88
- if not self._match_called:
89
- self._match_called = True
90
-
91
- begin_var, end_var = self._match_inner()
92
-
93
- self._begin_var = begin_var
94
- self._end_var = end_var
95
-
96
- return self._conn_relation_name
97
-
98
- def _match_inner(self):
99
- begin_var = None
100
- cur_end = None
101
-
102
- for idx, segment in enumerate(self._segments):
103
- if isinstance(segment, VarLength):
104
- var_length_rel_name = self._var_length(idx, segment)
105
- seg_begin, seg_end = create_vars(2)
106
- getattr(rel, var_length_rel_name)(seg_begin, seg_end)
107
-
108
- if begin_var is None:
109
- begin_var = seg_begin
110
- cur_end = seg_end
111
- else:
112
- getattr(seg_begin, self._backwards_edge) == cur_end
113
- cur_end = seg_end
114
- else:
115
- next_var = segment
116
- if begin_var is None:
117
- begin_var = next_var
118
- cur_end = begin_var
119
- else:
120
- getattr(next_var, self._backwards_edge) == cur_end
121
- cur_end = next_var
122
-
123
- conn_relation = getattr(rel, self._conn_relation_name)
124
- conn_relation._rel.parents.append(Builtins.NoInlineAnnotation)
125
- conn_relation.add(begin_var, cur_end)
126
-
127
- return begin_var, cur_end
128
-
129
- def _var_length(self, segment_idx: int, segment: VarLength):
130
- # relations for each length
131
- prefix = f"conn_{self._path_id}_segment_{segment_idx}"
132
-
133
- lines = []
134
-
135
- for length in range(1, segment.max+1):
136
- length_rel_name = f"{prefix}_length_{length}"
137
-
138
- if length == 1:
139
- lines.extend([
140
- f"def {length_rel_name}(a, a1):",
141
- f" {segment.type._type.name}(a) and",
142
- " a = a1"
143
- ])
144
- # would just project `(a, a)`, but that gives a
145
- # bunch of Rel warnings`
146
-
147
- else:
148
- prev_length_relation_name = f"{prefix}_length_{length-1}"
149
- lines.extend([
150
- f"def {length_rel_name}(a, c):",
151
- " exists((b) |",
152
- f" {prev_length_relation_name}(a, b) and",
153
- f" {segment.type._type.name}(c) and",
154
- f" {self._backwards_edge}(c, b)",
155
- " )"
156
- ])
157
-
158
- # union them all together in overall segment relation
159
- lines.extend([
160
- f"def {prefix}(start, finish):",
161
- " " + " or\n ".join([
162
- f"{prefix}_length_{length}(start, finish)"
163
- for length in range(1, segment.max+1)
164
- ]),
165
- ])
166
-
167
- self._model.install_raw(
168
- '\n'.join(lines),
169
- name=f"path_{self._path_id}_segment_{segment_idx}",
170
- )
171
-
172
- return prefix
173
-
174
-
175
- class PathInstance(Instance):
176
-
177
- def __init__(
178
- self,
179
- path_query: PathQuery,
180
- ):
181
- self._path_query = path_query
182
-
183
- self._already_called = False
184
- super().__init__(
185
- self._path_query._model,
186
- ActionType.Get, [self._path_query._instance],
187
- named={},
188
- )
189
-
190
- # implements producer API
191
- def _to_var(self):
192
- self._invoke_pathfinder()
193
- return super()._to_var()
194
-
195
- def _invoke_pathfinder(self):
196
- if self._already_called:
197
- return
198
- self._already_called = True
199
-
200
- # ensure that the pathfinder Rel library is installed
201
- _install_pathfinder(self._path_query._model)
202
-
203
- source_rel = f"source_{self._path_query._path_id}"
204
- target_rel = f"target_{self._path_query._path_id}"
205
- getattr(rel, source_rel).add(self._path_query._begin_var)
206
- getattr(rel, target_rel).add(self._path_query._end_var)
207
-
208
- shortest_paths_rel = f"shortest_paths_{self._path_query._path_id}"
209
- path_edge_rel = f"path_edge_{self._path_query._path_id}"
210
- path_node_rel = f"path_node_{self._path_query._path_id}"
211
-
212
- invocation = f"""
213
- @no_inline
214
- def {shortest_paths_rel} {{
215
- ::pathfinder::shortest_paths[
216
- :{self._path_query._group.value},
217
- :{self._path_query._selection.value},
218
- :{self._path_query._strategy.value},
219
- {self._path_query._conn_relation_name},
220
- {source_rel},
221
- {target_rel}
222
- ]
223
- }}
224
-
225
- @no_inline
226
- def {path_node_rel}(path, index, id):
227
- {shortest_paths_rel}(path, :node, index, id)
228
-
229
- @no_inline
230
- def {path_edge_rel}(path, index, label):
231
- {shortest_paths_rel}(path, :edge_label, index, label)
232
- """
233
-
234
- self._path_query._model.install_raw(invocation)
235
-
236
- # select out nodes
237
- with self._path_query._model.rule():
238
- path_id, index, node_label = create_vars(3)
239
- getattr(rel, path_node_rel)(path_id, index, node_label)
240
- path = self._path_query._Path.add(id=path_id)
241
- # TODO: avoid perf hit of going in both directions (path<->node)
242
- node = self._path_query._PathNode.add(path=path, index=index, value=node_label)
243
- path.nodes.add(node)
244
-
245
- # select out edges
246
- with self._path_query._model.rule():
247
- path_id, index, label = create_vars(3)
248
- getattr(rel, path_edge_rel)(path_id, index, label)
249
- path = self._path_query._Path.add(id=path_id)
250
- # TODO: avoid perf hit of going in both directions (path<->edge)
251
- edge = self._path_query._PathEdge.add(path=path, index=index, label=label)
252
- path.edges.add(edge)
253
-
254
- # TODO: automatically infer this from the path query itself
255
- def enable_on(edge: Property, filter_attrs: List[Tuple[Type, Set[str]]]): # noqa: F821
256
- edge._prop.parents.append(Builtins.PQEdgeAnnotation)
257
- edge._prop.parents.append(Builtins.NoInlineAnnotation)
258
- for type, attrs in filter_attrs:
259
- type._type.parents.append(Builtins.PQFilterAnnotation)
260
- type._type.parents.append(Builtins.NoInlineAnnotation)
261
- for attr_name in attrs:
262
- prop = getattr(type, attr_name)
263
- prop._prop.parents.append(Builtins.PQFilterAnnotation)
264
- prop._prop.parents.append(Builtins.NoInlineAnnotation)
265
-
266
- # main entry point
267
- def path(
268
- segments: List[Union[Instance,VarLength]],
269
- backwards_edge: str,
270
- group: PathGroup = PathGroup.FOREACH,
271
- selection: PathSelection = PathSelection.ALL,
272
- strategy: Strategy = Strategy.FROM_SOURCE,
273
- ):
274
- """
275
- Find a path consisting of the provided segments, linked by
276
- the provided `backwards_edge` property.
277
- """
278
-
279
- model = get_graph()
280
-
281
- query = PathQuery(model, segments, backwards_edge, group, selection, strategy)
282
-
283
- # declare filter relations
284
- conn_relation_name = query._match()
285
-
286
- # invoke filter
287
- a, b = create_vars(2)
288
- getattr(rel, conn_relation_name)(a, b)
289
-
290
- # return a special Producer representing the path itself, which
291
- # lazily invokes Pathfinder
292
- return PathInstance(query)
293
-
294
- def _get_pathfinder_source():
295
- # check if the current dir is in a zip file
296
- current_dir = os.path.dirname(__file__)
297
- pathfinder_path = os.path.join(current_dir, "pathfinder.rel")
298
- if os.path.exists(pathfinder_path):
299
- return open(pathfinder_path).read()
300
- # if we're in a zip file, read it within that
301
- zip_split = current_dir.split(".zip")
302
- zip_path = zip_split[0] + ".zip"
303
- with zipfile.ZipFile(zip_path, 'r') as zip_ref:
304
- with zip_ref.open('relationalai/experimental/paths/pathfinder.rel') as file:
305
- return file.read().decode("utf-8")
306
-
307
- def _install_pathfinder(model: Graph):
308
- source = _get_pathfinder_source()
309
- model.install_raw(source, name="pathfinder", overwrite=True)
1
+ ## pathfinder module
2
+
3
+ from .api import node, edge, path, optional, plus, star, union, match
4
+
5
+ __all__ = [
6
+ 'node',
7
+ 'edge',
8
+ 'path',
9
+ 'optional',
10
+ 'plus',
11
+ 'star',
12
+ 'union',
13
+ 'match',
14
+ ]
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, select, String, define
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.api import path, star, match
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.api import path, star, match
4
4
 
5
5
  # Create an automaton that matches paths with pattern: A(A*)B:
6
6
  pattern = path("A", star("A"), "B")
@@ -4,8 +4,8 @@ Example usage of automaton-based pathfinding.
4
4
 
5
5
  import time
6
6
  from relationalai.semantics import Model, Integer, select, String, define
7
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
8
- from relationalai.semantics.reasoners.graph.paths.api import node, path, match
7
+ from relationalai.experimental.paths.graph import Graph
8
+ from relationalai.experimental.paths.api import node, path, match
9
9
 
10
10
  import argparse
11
11
 
@@ -4,8 +4,8 @@ Example usage of automaton-based pathfinding.
4
4
 
5
5
  import time
6
6
  from relationalai.semantics import Model, Integer, select, String, define
7
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
8
- from relationalai.semantics.reasoners.graph.paths.api import node, path, match
7
+ from relationalai.experimental.paths.graph import Graph
8
+ from relationalai.experimental.paths.api import node, path, match
9
9
 
10
10
  import argparse
11
11
 
@@ -1,4 +1,4 @@
1
- from relationalai.semantics.reasoners.graph.paths.api import path, union
1
+ from relationalai.experimental.paths.api import path, union
2
2
  from relationalai.semantics import Concept
3
3
 
4
4
  Node = Concept('Node')
@@ -1,6 +1,6 @@
1
1
  # For builder components.
2
2
  from relationalai.semantics import Integer, define
3
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
+ from relationalai.experimental.paths.graph import Graph
4
4
 
5
5
 
6
6
  def ball_with_repetition(g:Graph, Source, max_length):
@@ -1,8 +1,8 @@
1
1
  # For builder components.
2
2
  from relationalai.semantics import Integer, where, define, select, min
3
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
4
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
5
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_upto import ball_upto
3
+ from relationalai.experimental.paths.graph import Graph
4
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
5
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_upto import ball_upto
6
6
 
7
7
  # find a (deterministic) path from src to dst inside the given ball
8
8
  # where dst is at distance radius from src
@@ -1,6 +1,6 @@
1
1
  # For builder components.
2
2
  from relationalai.semantics import Integer, define
3
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
+ from relationalai.experimental.paths.graph import Graph
4
4
 
5
5
 
6
6
  def two_balls_repetition(g:Graph, Source, Target, max_length):
@@ -1,7 +1,7 @@
1
1
  # For builder components.
2
2
  from relationalai.semantics import Integer, define, not_, count
3
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
4
- from relationalai.semantics.reasoners.graph.paths.utilities.iterators import setup_iteration
3
+ from relationalai.experimental.paths.graph import Graph
4
+ from relationalai.experimental.paths.utilities.iterators import setup_iteration
5
5
 
6
6
 
7
7
  def two_balls_upto(g:Graph, Source, Target, max_length=None):
@@ -1,8 +1,8 @@
1
1
  # For builder components.
2
2
  from relationalai.semantics import Integer, define, max, sum, not_
3
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
4
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_upto import ball_upto
5
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
3
+ from relationalai.experimental.paths.graph import Graph
4
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_upto import ball_upto
5
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
6
6
 
7
7
 
8
8
  def compute_usp(g: Graph, Source, Target, max_length = None):
@@ -1,8 +1,8 @@
1
1
  # For builder components.
2
2
  from relationalai.semantics import Model, Integer, define, max, sum, select, not_
3
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
4
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_upto import ball_upto
5
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
3
+ from relationalai.experimental.paths.graph import Graph
4
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_upto import ball_upto
5
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
6
6
 
7
7
 
8
8
  def compute_usp(g: Graph, Source, Target, max_length = None):
@@ -1,8 +1,8 @@
1
1
  # For builder components.
2
2
  from relationalai.semantics import Integer, define, sum, not_
3
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
4
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_upto import ball_upto
5
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
3
+ from relationalai.experimental.paths.graph import Graph
4
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_upto import ball_upto
5
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
6
6
 
7
7
 
8
8
  def compute_usp(g: Graph, Source, Target, max_length=None):
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, define, select, count
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.find_paths import find_shortest_paths
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.path_algorithms.find_paths import find_shortest_paths
4
4
 
5
5
 
6
6
  # First test with grid graph
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, define, select, count
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.find_paths import find_shortest_paths
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.path_algorithms.find_paths import find_shortest_paths
4
4
 
5
5
 
6
6
  # First test with grid graph
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, define, select, count
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.find_paths import find_shortest_paths
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.path_algorithms.find_paths import find_shortest_paths
4
4
 
5
5
 
6
6
  # First test with grid graph
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, define, select, count
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.find_paths import find_walks
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.path_algorithms.find_paths import find_walks
4
4
 
5
5
 
6
6
  # First test with grid graph
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, define, select, count
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.find_paths import find_walks
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.path_algorithms.find_paths import find_walks
4
4
 
5
5
 
6
6
  # First test with grid graph
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, define, select
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
4
4
 
5
5
 
6
6
  # Test with grid graph
@@ -1,6 +1,6 @@
1
1
  from relationalai.semantics import Model, Integer, define, select
2
- from relationalai.semantics.reasoners.graph.paths.graph import Graph
3
- from relationalai.semantics.reasoners.graph.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
2
+ from relationalai.experimental.paths.graph import Graph
3
+ from relationalai.experimental.paths.path_algorithms.one_sided_ball_repetition import ball_with_repetition
4
4
 
5
5
 
6
6
  # Test with grid graph