relationalai 1.0.0a3__py3-none-any.whl → 1.0.0a5__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 (118) hide show
  1. relationalai/config/config.py +47 -21
  2. relationalai/config/connections/__init__.py +5 -2
  3. relationalai/config/connections/duckdb.py +2 -2
  4. relationalai/config/connections/local.py +31 -0
  5. relationalai/config/connections/snowflake.py +0 -1
  6. relationalai/config/external/raiconfig_converter.py +235 -0
  7. relationalai/config/external/raiconfig_models.py +202 -0
  8. relationalai/config/external/utils.py +31 -0
  9. relationalai/config/shims.py +1 -0
  10. relationalai/semantics/__init__.py +10 -8
  11. relationalai/semantics/backends/sql/sql_compiler.py +1 -4
  12. relationalai/semantics/experimental/__init__.py +0 -0
  13. relationalai/semantics/experimental/builder.py +295 -0
  14. relationalai/semantics/experimental/builtins.py +154 -0
  15. relationalai/semantics/frontend/base.py +67 -42
  16. relationalai/semantics/frontend/core.py +34 -6
  17. relationalai/semantics/frontend/front_compiler.py +209 -37
  18. relationalai/semantics/frontend/pprint.py +6 -2
  19. relationalai/semantics/metamodel/__init__.py +7 -0
  20. relationalai/semantics/metamodel/metamodel.py +2 -0
  21. relationalai/semantics/metamodel/metamodel_analyzer.py +58 -16
  22. relationalai/semantics/metamodel/pprint.py +6 -1
  23. relationalai/semantics/metamodel/rewriter.py +11 -7
  24. relationalai/semantics/metamodel/typer.py +116 -41
  25. relationalai/semantics/reasoners/__init__.py +11 -0
  26. relationalai/semantics/reasoners/graph/__init__.py +35 -0
  27. relationalai/semantics/reasoners/graph/core.py +9028 -0
  28. relationalai/semantics/std/__init__.py +30 -10
  29. relationalai/semantics/std/aggregates.py +641 -12
  30. relationalai/semantics/std/common.py +146 -13
  31. relationalai/semantics/std/constraints.py +71 -1
  32. relationalai/semantics/std/datetime.py +904 -21
  33. relationalai/semantics/std/decimals.py +143 -2
  34. relationalai/semantics/std/floats.py +57 -4
  35. relationalai/semantics/std/integers.py +98 -4
  36. relationalai/semantics/std/math.py +857 -35
  37. relationalai/semantics/std/numbers.py +216 -20
  38. relationalai/semantics/std/re.py +213 -5
  39. relationalai/semantics/std/strings.py +437 -44
  40. relationalai/shims/executor.py +60 -52
  41. relationalai/shims/fixtures.py +85 -0
  42. relationalai/shims/helpers.py +26 -2
  43. relationalai/shims/hoister.py +28 -9
  44. relationalai/shims/mm2v0.py +204 -173
  45. relationalai/tools/cli/cli.py +192 -10
  46. relationalai/tools/cli/components/progress_reader.py +1 -1
  47. relationalai/tools/cli/docs.py +394 -0
  48. relationalai/tools/debugger.py +11 -4
  49. relationalai/tools/qb_debugger.py +435 -0
  50. relationalai/tools/typer_debugger.py +1 -2
  51. relationalai/util/dataclasses.py +3 -5
  52. relationalai/util/docutils.py +1 -2
  53. relationalai/util/error.py +2 -5
  54. relationalai/util/python.py +23 -0
  55. relationalai/util/runtime.py +1 -2
  56. relationalai/util/schema.py +2 -4
  57. relationalai/util/structures.py +4 -2
  58. relationalai/util/tracing.py +8 -2
  59. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/METADATA +8 -5
  60. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/RECORD +118 -95
  61. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/WHEEL +1 -1
  62. v0/relationalai/__init__.py +1 -1
  63. v0/relationalai/clients/client.py +52 -18
  64. v0/relationalai/clients/exec_txn_poller.py +122 -0
  65. v0/relationalai/clients/local.py +23 -8
  66. v0/relationalai/clients/resources/azure/azure.py +36 -11
  67. v0/relationalai/clients/resources/snowflake/__init__.py +4 -4
  68. v0/relationalai/clients/resources/snowflake/cli_resources.py +12 -1
  69. v0/relationalai/clients/resources/snowflake/direct_access_resources.py +124 -100
  70. v0/relationalai/clients/resources/snowflake/engine_service.py +381 -0
  71. v0/relationalai/clients/resources/snowflake/engine_state_handlers.py +35 -29
  72. v0/relationalai/clients/resources/snowflake/error_handlers.py +43 -2
  73. v0/relationalai/clients/resources/snowflake/snowflake.py +277 -179
  74. v0/relationalai/clients/resources/snowflake/use_index_poller.py +8 -0
  75. v0/relationalai/clients/types.py +5 -0
  76. v0/relationalai/errors.py +19 -1
  77. v0/relationalai/semantics/lqp/algorithms.py +173 -0
  78. v0/relationalai/semantics/lqp/builtins.py +199 -2
  79. v0/relationalai/semantics/lqp/executor.py +68 -37
  80. v0/relationalai/semantics/lqp/ir.py +28 -2
  81. v0/relationalai/semantics/lqp/model2lqp.py +215 -45
  82. v0/relationalai/semantics/lqp/passes.py +13 -658
  83. v0/relationalai/semantics/lqp/rewrite/__init__.py +12 -0
  84. v0/relationalai/semantics/lqp/rewrite/algorithm.py +385 -0
  85. v0/relationalai/semantics/lqp/rewrite/constants_to_vars.py +70 -0
  86. v0/relationalai/semantics/lqp/rewrite/deduplicate_vars.py +104 -0
  87. v0/relationalai/semantics/lqp/rewrite/eliminate_data.py +108 -0
  88. v0/relationalai/semantics/lqp/rewrite/extract_keys.py +25 -3
  89. v0/relationalai/semantics/lqp/rewrite/period_math.py +77 -0
  90. v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +65 -31
  91. v0/relationalai/semantics/lqp/rewrite/unify_definitions.py +317 -0
  92. v0/relationalai/semantics/lqp/utils.py +11 -1
  93. v0/relationalai/semantics/lqp/validators.py +14 -1
  94. v0/relationalai/semantics/metamodel/builtins.py +2 -1
  95. v0/relationalai/semantics/metamodel/compiler.py +2 -1
  96. v0/relationalai/semantics/metamodel/dependency.py +12 -3
  97. v0/relationalai/semantics/metamodel/executor.py +11 -1
  98. v0/relationalai/semantics/metamodel/factory.py +2 -2
  99. v0/relationalai/semantics/metamodel/helpers.py +7 -0
  100. v0/relationalai/semantics/metamodel/ir.py +3 -2
  101. v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +30 -20
  102. v0/relationalai/semantics/metamodel/rewrite/flatten.py +50 -13
  103. v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +9 -3
  104. v0/relationalai/semantics/metamodel/typer/checker.py +6 -4
  105. v0/relationalai/semantics/metamodel/typer/typer.py +4 -3
  106. v0/relationalai/semantics/metamodel/visitor.py +4 -3
  107. v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +1 -1
  108. v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +336 -86
  109. v0/relationalai/semantics/rel/compiler.py +2 -1
  110. v0/relationalai/semantics/rel/executor.py +3 -2
  111. v0/relationalai/semantics/tests/lqp/__init__.py +0 -0
  112. v0/relationalai/semantics/tests/lqp/algorithms.py +345 -0
  113. v0/relationalai/tools/cli.py +339 -186
  114. v0/relationalai/tools/cli_controls.py +216 -67
  115. v0/relationalai/tools/cli_helpers.py +410 -6
  116. v0/relationalai/util/format.py +5 -2
  117. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/entry_points.txt +0 -0
  118. {relationalai-1.0.0a3.dist-info → relationalai-1.0.0a5.dist-info}/top_level.txt +0 -0
@@ -13,7 +13,8 @@ class Flatten(Pass):
13
13
  """
14
14
  Traverses the model's root to flatten it as much as possible. The result of this pass is
15
15
  a Logical root where all nested tasks that represent a rule in Rel are extracted to the
16
- top level.
16
+ top level. Additionally, any Sequence is promoted to the top level Logical (but
17
+ encapsulated by a Logical).
17
18
 
18
19
  - nested logical with updates becomes a top-level logical (a rule)
19
20
 
@@ -122,6 +123,35 @@ class Flatten(Pass):
122
123
  Logical
123
124
  lookup tmp2
124
125
  output
126
+
127
+ - a Sequence is promoted to the top level Logical, encapsulated by a Logical:
128
+ From:
129
+ Logical
130
+ Logical
131
+ lookup
132
+ derive foo
133
+ Sequence
134
+ Logical
135
+ ...
136
+ Loop
137
+ Sequence
138
+ ...
139
+ Logical
140
+ ...
141
+ To:
142
+ Logical
143
+ Logical
144
+ lookup
145
+ derive foo
146
+ Logical
147
+ Sequence
148
+ Logical
149
+ ...
150
+ Loop
151
+ Sequence
152
+ ...
153
+ Logical
154
+ ...
125
155
  """
126
156
 
127
157
  def __init__(self, use_sql: bool=False):
@@ -181,11 +211,8 @@ class Flatten(Pass):
181
211
  def handle(self, task: ir.Task, ctx: Context) -> Flatten.HandleResult:
182
212
  if isinstance(task, ir.Logical):
183
213
  return self.handle_logical(task, ctx)
184
- elif isinstance(task, ir.Union) and (task.hoisted or self._use_sql):
185
- # Only flatten Unions which hoist variables. If there are no hoisted variables,
186
- # then the Union acts as a filter, and it can be inefficient to flatten it.
187
- #
188
- # However, for the SQL backend, we always need to flatten Unions for correct SQL
214
+ elif isinstance(task, ir.Union) and self._use_sql:
215
+ # The SQL backend needs to flatten Unions for correct SQL
189
216
  # generation.
190
217
  return self.handle_union(task, ctx)
191
218
  elif isinstance(task, ir.Match):
@@ -194,6 +221,8 @@ class Flatten(Pass):
194
221
  return self.handle_require(task, ctx)
195
222
  elif isinstance(task, ir.Not):
196
223
  return self.handle_not(task, ctx)
224
+ elif isinstance(task, ir.Sequence):
225
+ return self.handle_sequence(task, ctx)
197
226
  else:
198
227
  return Flatten.HandleResult(task)
199
228
 
@@ -253,9 +282,9 @@ class Flatten(Pass):
253
282
 
254
283
  for output in groups["outputs"]:
255
284
  assert(isinstance(output, ir.Output))
256
- new_body = info.task_dependencies(output)
257
- new_body.update(ctx.extra_tasks)
258
- new_body.add(output)
285
+ new_body = OrderedSet.from_iterable(t.clone() for t in info.task_dependencies(output))
286
+ new_body.update(t.clone() for t in ctx.extra_tasks)
287
+ new_body.add(output.clone())
259
288
  ctx.rewrite_ctx.top_level.append(ir.Logical(task.engine, task.hoisted, tuple(new_body), task.annotations))
260
289
 
261
290
  return Flatten.HandleResult(None)
@@ -263,9 +292,9 @@ class Flatten(Pass):
263
292
  # if there are updates, extract as a new top level rule
264
293
  if groups["updates"]:
265
294
  # add task dependencies to the body
266
- body.prefix(ctx.info.task_dependencies(task))
295
+ body.prefix(t.clone() for t in ctx.info.task_dependencies(task))
267
296
  # potentially add context extra tasks
268
- body.update(ctx.extra_tasks)
297
+ body.update(t.clone() for t in ctx.extra_tasks)
269
298
  ctx.rewrite_ctx.top_level.append(ir.Logical(task.engine, task.hoisted, tuple(body), task.annotations))
270
299
  return Flatten.HandleResult(None)
271
300
 
@@ -278,7 +307,7 @@ class Flatten(Pass):
278
307
  agg = cast(ir.Aggregate, groups["aggregates"].some())
279
308
 
280
309
  # add agg dependencies to the body
281
- body.prefix(ctx.info.task_dependencies(agg))
310
+ body.prefix(t.clone() for t in ctx.info.task_dependencies(agg))
282
311
 
283
312
  # extract a new logical for the aggregate, exposing aggregate group-by and results
284
313
  exposed_vars = OrderedSet.from_iterable(list(agg.group) + helpers.aggregate_outputs(agg))
@@ -298,7 +327,7 @@ class Flatten(Pass):
298
327
  rank = cast(ir.Rank, groups["ranks"].some())
299
328
 
300
329
  # add rank dependencies to the body
301
- body.prefix(ctx.info.task_dependencies(rank))
330
+ body.prefix(t.clone() for t in ctx.info.task_dependencies(rank))
302
331
  # for rank, we sort by the args, but the result includes the keys to preserve bag semantics.
303
332
  exposed_vars_raw = list(rank.projection) + list(rank.group) + list(rank.args) +[rank.result]
304
333
  # deduplicate vars
@@ -487,6 +516,14 @@ class Flatten(Pass):
487
516
  task.annotations
488
517
  ))
489
518
 
519
+ def handle_sequence(self, task: ir.Sequence, ctx: Context):
520
+ new_logical = f.logical(
521
+ body = [task],
522
+ engine = task.engine
523
+ )
524
+ ctx.rewrite_ctx.top_level.append(new_logical)
525
+ return Flatten.HandleResult(None)
526
+
490
527
  #--------------------------------------------------
491
528
  # Helpers
492
529
  #--------------------------------------------------
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from typing import Tuple
3
3
 
4
- from v0.relationalai.semantics.metamodel import builtins, ir, factory as f, types, visitor
4
+ from v0.relationalai.semantics.metamodel import builtins, ir, factory as f, types, visitor, helpers
5
5
  from v0.relationalai.semantics.metamodel.compiler import Pass, group_tasks
6
6
  from v0.relationalai.semantics.metamodel.util import OrderedSet
7
7
  from v0.relationalai.semantics.metamodel.util import FrozenOrderedSet
@@ -63,7 +63,7 @@ def adjust_outputs(task: ir.Logical, outputs: OrderedSet[ir.Task], wide_outputs:
63
63
  # Remove the original output. This is replaced by per-column outputs below
64
64
  body.remove(output)
65
65
 
66
- is_export = builtins.export_annotation in output.annotations
66
+ is_export = helpers.is_export(output)
67
67
 
68
68
  # Generate an output for each "column"
69
69
  # output looks like def output(:cols, :col000, key0, key1, value):
@@ -100,7 +100,13 @@ def _generate_output_column(output: ir.Output, idx: int, alias: tuple[str, ir.Va
100
100
  (not is_primitive(alias[1].type) or alias[1].type == types.Hash)):
101
101
 
102
102
  uuid = f.var(f"{alias[0]}_{idx}_uuid", types.String)
103
- aliases.append((uuid.name, uuid))
103
+
104
+ if not is_primitive(alias[1].type):
105
+ # For non-primitive types, we keep the original alias
106
+ aliases.append((alias[0], uuid))
107
+ else:
108
+ # For Hash types, we use the uuid name as alias
109
+ aliases.append((uuid.name, uuid))
104
110
 
105
111
  return [
106
112
  ir.Lookup(None, builtins.uuid_to_string, (alias[1], uuid)),
@@ -5,7 +5,7 @@ from dataclasses import dataclass, field
5
5
  from typing import Optional, List, Union as PyUnion, Tuple, cast
6
6
 
7
7
  from v0.relationalai.semantics.metamodel.util import OrderedSet, ordered_set
8
- from v0.relationalai.semantics.metamodel import ir, types, visitor, compiler
8
+ from v0.relationalai.semantics.metamodel import ir, types, visitor, compiler, executor
9
9
  import rich
10
10
 
11
11
 
@@ -39,7 +39,8 @@ class CheckEnv:
39
39
 
40
40
  def _complain(self, node: ir.Node, msg: str):
41
41
  """Report an error."""
42
- self.diags.append(CheckError(msg, node))
42
+ if not executor.SUPPRESS_TYPE_ERRORS:
43
+ self.diags.append(CheckError(msg, node))
43
44
 
44
45
 
45
46
  @dataclass
@@ -306,8 +307,9 @@ class CheckModel(visitor.DAGVisitor):
306
307
  for x in node.hoisted:
307
308
  if not CheckModel._variable_occurs_in(x, node.body):
308
309
  self.env._complain(node, f"Variable {ir.node_to_string(x).strip()} is hoisted but not used in the body of {ir.node_to_string(node).strip()}.")
309
- if not CheckModel._variable_occurs_in(node.iter, node.body):
310
- self.env._complain(node, f"Variable {node.iter} is the loop iterator but is not used in the body of {ir.node_to_string(node).strip()}.")
310
+ for iter_var in node.iter:
311
+ if not CheckModel._variable_occurs_in(iter_var, node.body):
312
+ self.env._complain(node, f"Variable {iter_var} is the loop iterator but is not used in the body of {ir.node_to_string(node).strip()}.")
311
313
  return super().visit_loop(node, parent)
312
314
 
313
315
  def visit_update(self, node: ir.Update, parent: Optional[ir.Node]=None):
@@ -6,7 +6,7 @@ import datetime
6
6
  from decimal import Decimal as PyDecimal
7
7
  from typing import Optional, Union, Tuple
8
8
  from v0.relationalai import debugging
9
- from v0.relationalai.semantics.metamodel import builtins, helpers, ir, types, visitor, compiler, factory as f
9
+ from v0.relationalai.semantics.metamodel import builtins, helpers, ir, types, visitor, compiler, factory as f, executor
10
10
  from v0.relationalai.semantics.metamodel.util import OrderedSet, ordered_set
11
11
  import rich
12
12
  import sys
@@ -1389,7 +1389,8 @@ class InferTypes(compiler.Pass):
1389
1389
  with debugging.span("type.replace"):
1390
1390
  final = Replacer(w.net).walk(model)
1391
1391
 
1392
- for err in w.net.errors:
1393
- rich.print(str(err), file=sys.stderr)
1392
+ if not executor.SUPPRESS_TYPE_ERRORS:
1393
+ for err in w.net.errors:
1394
+ rich.print(str(err), file=sys.stderr)
1394
1395
 
1395
1396
  return final
@@ -466,7 +466,8 @@ class Visitor(GenericVisitor[None]):
466
466
  self._walk_engine(node.engine, node)
467
467
  for h in node.hoisted:
468
468
  self._walk_var_or_default(h, node)
469
- self._walk_var(node.iter, node)
469
+ for iter in node.iter:
470
+ self._walk_var(iter, node)
470
471
  self._walk_node(node.body, node)
471
472
  for a in node.annotations:
472
473
  self._walk_node(a, node)
@@ -935,9 +936,9 @@ class Rewriter():
935
936
  #
936
937
  def handle_loop(self, node: ir.Loop, parent: ir.Node):
937
938
  hoisted = rewrite_list(ir.VarOrDefault, lambda n: self.walk(n, node), node.hoisted)
938
- iter_val = self.walk(node.iter, node)
939
+ iter = rewrite_list(ir.Var, lambda n: self.walk(n, node), node.iter)
939
940
  body = self.walk(node.body, node)
940
- return node.reconstruct(node.engine, hoisted, iter_val, body, node.annotations)
941
+ return node.reconstruct(node.engine, hoisted, iter, body, node.concurrency, node.annotations)
941
942
 
942
943
  def handle_break(self, node: ir.Break, parent: ir.Node):
943
944
  check = self.walk(node.check, node)
@@ -333,7 +333,7 @@ class SolverModelDev:
333
333
  executor.execute_raw(textwrap.dedent(f"""
334
334
  def delete[:{self.point._name}]: {self.point._name}
335
335
  def insert(:{self.point._name}, var, val): {self.points._name}(int128[{i}], var, val)
336
- """), readonly=False)
336
+ """))
337
337
  return None
338
338
 
339
339
  # print summary of the solver result