relationalai 0.13.0.dev0__py3-none-any.whl → 0.13.2__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.
- frontend/debugger/dist/.gitignore +2 -0
- frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
- frontend/debugger/dist/assets/index-Cssla-O7.js +208 -0
- frontend/debugger/dist/assets/index-DlHsYx1V.css +9 -0
- frontend/debugger/dist/index.html +17 -0
- relationalai/__init__.py +256 -1
- relationalai/clients/__init__.py +18 -0
- relationalai/clients/client.py +947 -0
- relationalai/clients/config.py +673 -0
- relationalai/clients/direct_access_client.py +118 -0
- relationalai/clients/exec_txn_poller.py +91 -0
- relationalai/clients/hash_util.py +31 -0
- relationalai/clients/local.py +586 -0
- relationalai/clients/profile_polling.py +73 -0
- relationalai/clients/resources/__init__.py +8 -0
- relationalai/clients/resources/azure/azure.py +502 -0
- relationalai/clients/resources/snowflake/__init__.py +20 -0
- relationalai/clients/resources/snowflake/cli_resources.py +98 -0
- relationalai/clients/resources/snowflake/direct_access_resources.py +734 -0
- relationalai/clients/resources/snowflake/engine_service.py +381 -0
- relationalai/clients/resources/snowflake/engine_state_handlers.py +315 -0
- relationalai/clients/resources/snowflake/error_handlers.py +240 -0
- relationalai/clients/resources/snowflake/export_procedure.py.jinja +249 -0
- relationalai/clients/resources/snowflake/resources_factory.py +99 -0
- relationalai/clients/resources/snowflake/snowflake.py +3185 -0
- relationalai/clients/resources/snowflake/use_index_poller.py +1019 -0
- relationalai/clients/resources/snowflake/use_index_resources.py +188 -0
- relationalai/clients/resources/snowflake/util.py +387 -0
- relationalai/clients/result_helpers.py +420 -0
- relationalai/clients/types.py +118 -0
- relationalai/clients/util.py +356 -0
- relationalai/debugging.py +389 -0
- relationalai/dsl.py +1749 -0
- relationalai/early_access/builder/__init__.py +30 -0
- relationalai/early_access/builder/builder/__init__.py +35 -0
- relationalai/early_access/builder/snowflake/__init__.py +12 -0
- relationalai/early_access/builder/std/__init__.py +25 -0
- relationalai/early_access/builder/std/decimals/__init__.py +12 -0
- relationalai/early_access/builder/std/integers/__init__.py +12 -0
- relationalai/early_access/builder/std/math/__init__.py +12 -0
- relationalai/early_access/builder/std/strings/__init__.py +14 -0
- relationalai/early_access/devtools/__init__.py +12 -0
- relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
- relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
- relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
- relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
- relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
- relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
- relationalai/early_access/dsl/bindings/common.py +402 -0
- relationalai/early_access/dsl/bindings/csv.py +170 -0
- relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
- relationalai/early_access/dsl/bindings/snowflake.py +64 -0
- relationalai/early_access/dsl/codegen/binder.py +411 -0
- relationalai/early_access/dsl/codegen/common.py +79 -0
- relationalai/early_access/dsl/codegen/helpers.py +23 -0
- relationalai/early_access/dsl/codegen/relations.py +700 -0
- relationalai/early_access/dsl/codegen/weaver.py +417 -0
- relationalai/early_access/dsl/core/builders/__init__.py +47 -0
- relationalai/early_access/dsl/core/builders/logic.py +19 -0
- relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
- relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
- relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
- relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
- relationalai/early_access/dsl/core/context.py +13 -0
- relationalai/early_access/dsl/core/cset.py +132 -0
- relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
- relationalai/early_access/dsl/core/exprs/relational.py +18 -0
- relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
- relationalai/early_access/dsl/core/instances.py +44 -0
- relationalai/early_access/dsl/core/logic/__init__.py +193 -0
- relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
- relationalai/early_access/dsl/core/logic/exists.py +223 -0
- relationalai/early_access/dsl/core/logic/helper.py +163 -0
- relationalai/early_access/dsl/core/namespaces.py +32 -0
- relationalai/early_access/dsl/core/relations.py +276 -0
- relationalai/early_access/dsl/core/rules.py +112 -0
- relationalai/early_access/dsl/core/std/__init__.py +45 -0
- relationalai/early_access/dsl/core/temporal/recall.py +6 -0
- relationalai/early_access/dsl/core/types/__init__.py +270 -0
- relationalai/early_access/dsl/core/types/concepts.py +128 -0
- relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
- relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
- relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
- relationalai/early_access/dsl/core/types/standard.py +92 -0
- relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
- relationalai/early_access/dsl/core/types/variables.py +203 -0
- relationalai/early_access/dsl/ir/compiler.py +318 -0
- relationalai/early_access/dsl/ir/executor.py +260 -0
- relationalai/early_access/dsl/ontologies/constraints.py +88 -0
- relationalai/early_access/dsl/ontologies/export.py +30 -0
- relationalai/early_access/dsl/ontologies/models.py +453 -0
- relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
- relationalai/early_access/dsl/ontologies/readings.py +60 -0
- relationalai/early_access/dsl/ontologies/relationships.py +322 -0
- relationalai/early_access/dsl/ontologies/roles.py +87 -0
- relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
- relationalai/early_access/dsl/orm/constraints.py +438 -0
- relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
- relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
- relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
- relationalai/early_access/dsl/orm/measures/measures.py +299 -0
- relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
- relationalai/early_access/dsl/orm/models.py +256 -0
- relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
- relationalai/early_access/dsl/orm/printer.py +469 -0
- relationalai/early_access/dsl/orm/reasoners.py +480 -0
- relationalai/early_access/dsl/orm/relations.py +19 -0
- relationalai/early_access/dsl/orm/relationships.py +251 -0
- relationalai/early_access/dsl/orm/types.py +42 -0
- relationalai/early_access/dsl/orm/utils.py +79 -0
- relationalai/early_access/dsl/orm/verb.py +204 -0
- relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
- relationalai/early_access/dsl/relations.py +170 -0
- relationalai/early_access/dsl/rulesets.py +69 -0
- relationalai/early_access/dsl/schemas/__init__.py +450 -0
- relationalai/early_access/dsl/schemas/builder.py +48 -0
- relationalai/early_access/dsl/schemas/comp_names.py +51 -0
- relationalai/early_access/dsl/schemas/components.py +203 -0
- relationalai/early_access/dsl/schemas/contexts.py +156 -0
- relationalai/early_access/dsl/schemas/exprs.py +89 -0
- relationalai/early_access/dsl/schemas/fragments.py +464 -0
- relationalai/early_access/dsl/serialization.py +79 -0
- relationalai/early_access/dsl/serialize/exporter.py +163 -0
- relationalai/early_access/dsl/snow/api.py +105 -0
- relationalai/early_access/dsl/snow/common.py +76 -0
- relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
- relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
- relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
- relationalai/early_access/dsl/types/__init__.py +40 -0
- relationalai/early_access/dsl/types/concepts.py +12 -0
- relationalai/early_access/dsl/types/entities.py +135 -0
- relationalai/early_access/dsl/types/values.py +17 -0
- relationalai/early_access/dsl/utils.py +102 -0
- relationalai/early_access/graphs/__init__.py +13 -0
- relationalai/early_access/lqp/__init__.py +12 -0
- relationalai/early_access/lqp/compiler/__init__.py +12 -0
- relationalai/early_access/lqp/constructors/__init__.py +18 -0
- relationalai/early_access/lqp/executor/__init__.py +12 -0
- relationalai/early_access/lqp/ir/__init__.py +12 -0
- relationalai/early_access/lqp/passes/__init__.py +12 -0
- relationalai/early_access/lqp/pragmas/__init__.py +12 -0
- relationalai/early_access/lqp/primitives/__init__.py +12 -0
- relationalai/early_access/lqp/types/__init__.py +12 -0
- relationalai/early_access/lqp/utils/__init__.py +12 -0
- relationalai/early_access/lqp/validators/__init__.py +12 -0
- relationalai/early_access/metamodel/__init__.py +58 -0
- relationalai/early_access/metamodel/builtins/__init__.py +12 -0
- relationalai/early_access/metamodel/compiler/__init__.py +12 -0
- relationalai/early_access/metamodel/dependency/__init__.py +12 -0
- relationalai/early_access/metamodel/factory/__init__.py +17 -0
- relationalai/early_access/metamodel/helpers/__init__.py +12 -0
- relationalai/early_access/metamodel/ir/__init__.py +14 -0
- relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
- relationalai/early_access/metamodel/typer/__init__.py +3 -0
- relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
- relationalai/early_access/metamodel/types/__init__.py +15 -0
- relationalai/early_access/metamodel/util/__init__.py +15 -0
- relationalai/early_access/metamodel/visitor/__init__.py +12 -0
- relationalai/early_access/rel/__init__.py +12 -0
- relationalai/early_access/rel/executor/__init__.py +12 -0
- relationalai/early_access/rel/rel_utils/__init__.py +12 -0
- relationalai/early_access/rel/rewrite/__init__.py +7 -0
- relationalai/early_access/solvers/__init__.py +19 -0
- relationalai/early_access/sql/__init__.py +11 -0
- relationalai/early_access/sql/executor/__init__.py +3 -0
- relationalai/early_access/sql/rewrite/__init__.py +3 -0
- relationalai/early_access/tests/logging/__init__.py +12 -0
- relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
- relationalai/early_access/tests/utils/__init__.py +12 -0
- relationalai/environments/__init__.py +35 -0
- relationalai/environments/base.py +381 -0
- relationalai/environments/colab.py +14 -0
- relationalai/environments/generic.py +71 -0
- relationalai/environments/ipython.py +68 -0
- relationalai/environments/jupyter.py +9 -0
- relationalai/environments/snowbook.py +169 -0
- relationalai/errors.py +2496 -0
- relationalai/experimental/SF.py +38 -0
- relationalai/experimental/inspect.py +47 -0
- relationalai/experimental/pathfinder/__init__.py +158 -0
- relationalai/experimental/pathfinder/api.py +160 -0
- relationalai/experimental/pathfinder/automaton.py +584 -0
- relationalai/experimental/pathfinder/bridge.py +226 -0
- relationalai/experimental/pathfinder/compiler.py +416 -0
- relationalai/experimental/pathfinder/datalog.py +214 -0
- relationalai/experimental/pathfinder/diagnostics.py +56 -0
- relationalai/experimental/pathfinder/filter.py +236 -0
- relationalai/experimental/pathfinder/glushkov.py +439 -0
- relationalai/experimental/pathfinder/options.py +265 -0
- relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +1951 -0
- relationalai/experimental/pathfinder/rpq.py +344 -0
- relationalai/experimental/pathfinder/transition.py +200 -0
- relationalai/experimental/pathfinder/utils.py +26 -0
- relationalai/experimental/paths/README.md +107 -0
- relationalai/experimental/paths/api.py +143 -0
- relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
- relationalai/experimental/paths/code_organization.md +2 -0
- relationalai/experimental/paths/examples/Movies.ipynb +16328 -0
- relationalai/experimental/paths/examples/basic_example.py +40 -0
- relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
- relationalai/experimental/paths/examples/movie_example.py +77 -0
- relationalai/experimental/paths/examples/movies_data/actedin.csv +193 -0
- relationalai/experimental/paths/examples/movies_data/directed.csv +45 -0
- relationalai/experimental/paths/examples/movies_data/follows.csv +7 -0
- relationalai/experimental/paths/examples/movies_data/movies.csv +39 -0
- relationalai/experimental/paths/examples/movies_data/person.csv +134 -0
- relationalai/experimental/paths/examples/movies_data/produced.csv +16 -0
- relationalai/experimental/paths/examples/movies_data/ratings.csv +10 -0
- relationalai/experimental/paths/examples/movies_data/wrote.csv +11 -0
- relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
- relationalai/experimental/paths/examples/paths_example.py +116 -0
- relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
- relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
- relationalai/experimental/paths/graph.py +185 -0
- relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
- relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
- relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
- relationalai/experimental/paths/path_algorithms/single.py +59 -0
- relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
- relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
- relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
- relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
- relationalai/experimental/paths/path_algorithms/usp.py +150 -0
- relationalai/experimental/paths/product_graph.py +93 -0
- relationalai/experimental/paths/rpq/automaton.py +584 -0
- relationalai/experimental/paths/rpq/diagnostics.py +56 -0
- relationalai/experimental/paths/rpq/rpq.py +378 -0
- relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
- relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
- relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
- relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
- relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
- relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
- relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
- relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
- relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
- relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
- relationalai/experimental/paths/tree_agg.py +168 -0
- relationalai/experimental/paths/utilities/iterators.py +27 -0
- relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
- relationalai/experimental/solvers.py +1087 -0
- relationalai/loaders/csv.py +195 -0
- relationalai/loaders/loader.py +177 -0
- relationalai/loaders/types.py +23 -0
- relationalai/rel_emitter.py +373 -0
- relationalai/rel_utils.py +185 -0
- relationalai/semantics/__init__.py +22 -146
- relationalai/semantics/designs/query_builder/identify_by.md +106 -0
- relationalai/semantics/devtools/benchmark_lqp.py +535 -0
- relationalai/semantics/devtools/compilation_manager.py +294 -0
- relationalai/semantics/devtools/extract_lqp.py +110 -0
- relationalai/semantics/internal/internal.py +3785 -0
- relationalai/semantics/internal/snowflake.py +325 -0
- relationalai/semantics/lqp/README.md +34 -0
- relationalai/semantics/lqp/builtins.py +16 -0
- relationalai/semantics/lqp/compiler.py +22 -0
- relationalai/semantics/lqp/constructors.py +68 -0
- relationalai/semantics/lqp/executor.py +469 -0
- relationalai/semantics/lqp/intrinsics.py +24 -0
- relationalai/semantics/lqp/model2lqp.py +877 -0
- relationalai/semantics/lqp/passes.py +680 -0
- relationalai/semantics/lqp/primitives.py +252 -0
- relationalai/semantics/lqp/result_helpers.py +202 -0
- relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
- relationalai/semantics/lqp/rewrite/cdc.py +216 -0
- relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
- relationalai/semantics/lqp/rewrite/extract_keys.py +512 -0
- relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
- relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
- relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
- relationalai/semantics/lqp/rewrite/splinter.py +76 -0
- relationalai/semantics/lqp/types.py +101 -0
- relationalai/semantics/lqp/utils.py +160 -0
- relationalai/semantics/lqp/validators.py +57 -0
- relationalai/semantics/metamodel/__init__.py +40 -6
- relationalai/semantics/metamodel/builtins.py +771 -205
- relationalai/semantics/metamodel/compiler.py +133 -0
- relationalai/semantics/metamodel/dependency.py +862 -0
- relationalai/semantics/metamodel/executor.py +61 -0
- relationalai/semantics/metamodel/factory.py +287 -0
- relationalai/semantics/metamodel/helpers.py +361 -0
- relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
- relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
- relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
- relationalai/semantics/metamodel/rewrite/flatten.py +554 -0
- relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
- relationalai/semantics/metamodel/typer/checker.py +353 -0
- relationalai/semantics/metamodel/typer/typer.py +1399 -0
- relationalai/semantics/metamodel/util.py +506 -0
- relationalai/semantics/reasoners/__init__.py +10 -0
- relationalai/semantics/reasoners/graph/README.md +620 -0
- relationalai/semantics/reasoners/graph/__init__.py +37 -0
- relationalai/semantics/reasoners/graph/core.py +9019 -0
- relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +797 -0
- relationalai/semantics/reasoners/graph/tests/README.md +21 -0
- relationalai/semantics/reasoners/optimization/__init__.py +68 -0
- relationalai/semantics/reasoners/optimization/common.py +88 -0
- relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
- relationalai/semantics/reasoners/optimization/solvers_pb.py +1414 -0
- relationalai/semantics/rel/builtins.py +40 -0
- relationalai/semantics/rel/compiler.py +989 -0
- relationalai/semantics/rel/executor.py +362 -0
- relationalai/semantics/rel/rel.py +482 -0
- relationalai/semantics/rel/rel_utils.py +276 -0
- relationalai/semantics/snowflake/__init__.py +3 -0
- relationalai/semantics/sql/compiler.py +2503 -0
- relationalai/semantics/sql/executor/duck_db.py +52 -0
- relationalai/semantics/sql/executor/result_helpers.py +64 -0
- relationalai/semantics/sql/executor/snowflake.py +149 -0
- relationalai/semantics/sql/rewrite/denormalize.py +222 -0
- relationalai/semantics/sql/rewrite/double_negation.py +49 -0
- relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
- relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
- relationalai/semantics/sql/sql.py +504 -0
- relationalai/semantics/std/__init__.py +40 -60
- relationalai/semantics/std/constraints.py +43 -37
- relationalai/semantics/std/datetime.py +135 -246
- relationalai/semantics/std/decimals.py +52 -45
- relationalai/semantics/std/floats.py +5 -13
- relationalai/semantics/std/integers.py +11 -26
- relationalai/semantics/std/math.py +112 -183
- relationalai/semantics/std/pragmas.py +11 -0
- relationalai/semantics/std/re.py +62 -80
- relationalai/semantics/std/std.py +14 -0
- relationalai/semantics/std/strings.py +60 -117
- relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
- relationalai/semantics/tests/test_snapshot_base.py +9 -0
- relationalai/semantics/tests/utils.py +46 -0
- relationalai/std/__init__.py +70 -0
- relationalai/tools/cli.py +2089 -0
- relationalai/tools/cli_controls.py +1826 -0
- relationalai/tools/cli_helpers.py +802 -0
- relationalai/tools/debugger.py +183 -289
- relationalai/tools/debugger_client.py +109 -0
- relationalai/tools/debugger_server.py +302 -0
- relationalai/tools/dev.py +685 -0
- relationalai/tools/notes +7 -0
- relationalai/tools/qb_debugger.py +425 -0
- relationalai/util/clean_up_databases.py +95 -0
- relationalai/util/format.py +106 -48
- relationalai/util/list_databases.py +9 -0
- relationalai/util/otel_configuration.py +26 -0
- relationalai/util/otel_handler.py +484 -0
- relationalai/util/snowflake_handler.py +88 -0
- relationalai/util/span_format_test.py +43 -0
- relationalai/util/span_tracker.py +207 -0
- relationalai/util/spans_file_handler.py +72 -0
- relationalai/util/tracing_handler.py +34 -0
- relationalai-0.13.2.dist-info/METADATA +74 -0
- relationalai-0.13.2.dist-info/RECORD +460 -0
- relationalai-0.13.2.dist-info/WHEEL +4 -0
- relationalai-0.13.2.dist-info/entry_points.txt +3 -0
- relationalai-0.13.2.dist-info/licenses/LICENSE +202 -0
- relationalai_test_util/__init__.py +4 -0
- relationalai_test_util/fixtures.py +233 -0
- relationalai_test_util/snapshot.py +252 -0
- relationalai_test_util/traceback.py +118 -0
- relationalai/config/__init__.py +0 -56
- relationalai/config/config.py +0 -289
- relationalai/config/config_fields.py +0 -86
- relationalai/config/connections/__init__.py +0 -46
- relationalai/config/connections/base.py +0 -23
- relationalai/config/connections/duckdb.py +0 -29
- relationalai/config/connections/snowflake.py +0 -243
- relationalai/config/external/__init__.py +0 -17
- relationalai/config/external/dbt_converter.py +0 -101
- relationalai/config/external/dbt_models.py +0 -93
- relationalai/config/external/snowflake_converter.py +0 -41
- relationalai/config/external/snowflake_models.py +0 -85
- relationalai/config/external/utils.py +0 -19
- relationalai/semantics/backends/lqp/annotations.py +0 -11
- relationalai/semantics/backends/sql/sql_compiler.py +0 -327
- relationalai/semantics/frontend/base.py +0 -1707
- relationalai/semantics/frontend/core.py +0 -179
- relationalai/semantics/frontend/front_compiler.py +0 -1313
- relationalai/semantics/frontend/pprint.py +0 -408
- relationalai/semantics/metamodel/metamodel.py +0 -437
- relationalai/semantics/metamodel/metamodel_analyzer.py +0 -519
- relationalai/semantics/metamodel/metamodel_compiler.py +0 -0
- relationalai/semantics/metamodel/pprint.py +0 -412
- relationalai/semantics/metamodel/rewriter.py +0 -266
- relationalai/semantics/metamodel/typer.py +0 -1378
- relationalai/semantics/std/aggregates.py +0 -149
- relationalai/semantics/std/common.py +0 -44
- relationalai/semantics/std/numbers.py +0 -86
- relationalai/shims/executor.py +0 -147
- relationalai/shims/helpers.py +0 -126
- relationalai/shims/hoister.py +0 -221
- relationalai/shims/mm2v0.py +0 -1290
- relationalai/tools/cli/__init__.py +0 -6
- relationalai/tools/cli/cli.py +0 -90
- relationalai/tools/cli/components/__init__.py +0 -5
- relationalai/tools/cli/components/progress_reader.py +0 -1524
- relationalai/tools/cli/components/utils.py +0 -58
- relationalai/tools/cli/config_template.py +0 -45
- relationalai/tools/cli/dev.py +0 -19
- relationalai/tools/typer_debugger.py +0 -93
- relationalai/util/dataclasses.py +0 -43
- relationalai/util/docutils.py +0 -40
- relationalai/util/error.py +0 -199
- relationalai/util/naming.py +0 -145
- relationalai/util/python.py +0 -35
- relationalai/util/runtime.py +0 -156
- relationalai/util/schema.py +0 -197
- relationalai/util/source.py +0 -185
- relationalai/util/structures.py +0 -163
- relationalai/util/tracing.py +0 -261
- relationalai-0.13.0.dev0.dist-info/METADATA +0 -46
- relationalai-0.13.0.dev0.dist-info/RECORD +0 -488
- relationalai-0.13.0.dev0.dist-info/WHEEL +0 -5
- relationalai-0.13.0.dev0.dist-info/entry_points.txt +0 -3
- relationalai-0.13.0.dev0.dist-info/top_level.txt +0 -2
- v0/relationalai/__init__.py +0 -216
- v0/relationalai/clients/__init__.py +0 -5
- v0/relationalai/clients/azure.py +0 -477
- v0/relationalai/clients/client.py +0 -912
- v0/relationalai/clients/config.py +0 -673
- v0/relationalai/clients/direct_access_client.py +0 -118
- v0/relationalai/clients/hash_util.py +0 -31
- v0/relationalai/clients/local.py +0 -571
- v0/relationalai/clients/profile_polling.py +0 -73
- v0/relationalai/clients/result_helpers.py +0 -420
- v0/relationalai/clients/snowflake.py +0 -3869
- v0/relationalai/clients/types.py +0 -113
- v0/relationalai/clients/use_index_poller.py +0 -980
- v0/relationalai/clients/util.py +0 -356
- v0/relationalai/debugging.py +0 -389
- v0/relationalai/dsl.py +0 -1749
- v0/relationalai/early_access/builder/__init__.py +0 -30
- v0/relationalai/early_access/builder/builder/__init__.py +0 -35
- v0/relationalai/early_access/builder/snowflake/__init__.py +0 -12
- v0/relationalai/early_access/builder/std/__init__.py +0 -25
- v0/relationalai/early_access/builder/std/decimals/__init__.py +0 -12
- v0/relationalai/early_access/builder/std/integers/__init__.py +0 -12
- v0/relationalai/early_access/builder/std/math/__init__.py +0 -12
- v0/relationalai/early_access/builder/std/strings/__init__.py +0 -14
- v0/relationalai/early_access/devtools/__init__.py +0 -12
- v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
- v0/relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
- v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
- v0/relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
- v0/relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
- v0/relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
- v0/relationalai/early_access/dsl/bindings/common.py +0 -402
- v0/relationalai/early_access/dsl/bindings/csv.py +0 -170
- v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
- v0/relationalai/early_access/dsl/bindings/snowflake.py +0 -64
- v0/relationalai/early_access/dsl/codegen/binder.py +0 -411
- v0/relationalai/early_access/dsl/codegen/common.py +0 -79
- v0/relationalai/early_access/dsl/codegen/helpers.py +0 -23
- v0/relationalai/early_access/dsl/codegen/relations.py +0 -700
- v0/relationalai/early_access/dsl/codegen/weaver.py +0 -417
- v0/relationalai/early_access/dsl/core/builders/__init__.py +0 -47
- v0/relationalai/early_access/dsl/core/builders/logic.py +0 -19
- v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
- v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
- v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
- v0/relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
- v0/relationalai/early_access/dsl/core/context.py +0 -13
- v0/relationalai/early_access/dsl/core/cset.py +0 -132
- v0/relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
- v0/relationalai/early_access/dsl/core/exprs/relational.py +0 -18
- v0/relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
- v0/relationalai/early_access/dsl/core/instances.py +0 -44
- v0/relationalai/early_access/dsl/core/logic/__init__.py +0 -193
- v0/relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
- v0/relationalai/early_access/dsl/core/logic/exists.py +0 -223
- v0/relationalai/early_access/dsl/core/logic/helper.py +0 -163
- v0/relationalai/early_access/dsl/core/namespaces.py +0 -32
- v0/relationalai/early_access/dsl/core/relations.py +0 -276
- v0/relationalai/early_access/dsl/core/rules.py +0 -112
- v0/relationalai/early_access/dsl/core/std/__init__.py +0 -45
- v0/relationalai/early_access/dsl/core/temporal/recall.py +0 -6
- v0/relationalai/early_access/dsl/core/types/__init__.py +0 -270
- v0/relationalai/early_access/dsl/core/types/concepts.py +0 -128
- v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
- v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
- v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
- v0/relationalai/early_access/dsl/core/types/standard.py +0 -92
- v0/relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
- v0/relationalai/early_access/dsl/core/types/variables.py +0 -203
- v0/relationalai/early_access/dsl/ir/compiler.py +0 -318
- v0/relationalai/early_access/dsl/ir/executor.py +0 -260
- v0/relationalai/early_access/dsl/ontologies/constraints.py +0 -88
- v0/relationalai/early_access/dsl/ontologies/export.py +0 -30
- v0/relationalai/early_access/dsl/ontologies/models.py +0 -453
- v0/relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
- v0/relationalai/early_access/dsl/ontologies/readings.py +0 -60
- v0/relationalai/early_access/dsl/ontologies/relationships.py +0 -322
- v0/relationalai/early_access/dsl/ontologies/roles.py +0 -87
- v0/relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
- v0/relationalai/early_access/dsl/orm/constraints.py +0 -438
- v0/relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
- v0/relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
- v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
- v0/relationalai/early_access/dsl/orm/measures/measures.py +0 -299
- v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
- v0/relationalai/early_access/dsl/orm/models.py +0 -256
- v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
- v0/relationalai/early_access/dsl/orm/printer.py +0 -469
- v0/relationalai/early_access/dsl/orm/reasoners.py +0 -480
- v0/relationalai/early_access/dsl/orm/relations.py +0 -19
- v0/relationalai/early_access/dsl/orm/relationships.py +0 -251
- v0/relationalai/early_access/dsl/orm/types.py +0 -42
- v0/relationalai/early_access/dsl/orm/utils.py +0 -79
- v0/relationalai/early_access/dsl/orm/verb.py +0 -204
- v0/relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
- v0/relationalai/early_access/dsl/relations.py +0 -170
- v0/relationalai/early_access/dsl/rulesets.py +0 -69
- v0/relationalai/early_access/dsl/schemas/__init__.py +0 -450
- v0/relationalai/early_access/dsl/schemas/builder.py +0 -48
- v0/relationalai/early_access/dsl/schemas/comp_names.py +0 -51
- v0/relationalai/early_access/dsl/schemas/components.py +0 -203
- v0/relationalai/early_access/dsl/schemas/contexts.py +0 -156
- v0/relationalai/early_access/dsl/schemas/exprs.py +0 -89
- v0/relationalai/early_access/dsl/schemas/fragments.py +0 -464
- v0/relationalai/early_access/dsl/serialization.py +0 -79
- v0/relationalai/early_access/dsl/serialize/exporter.py +0 -163
- v0/relationalai/early_access/dsl/snow/api.py +0 -104
- v0/relationalai/early_access/dsl/snow/common.py +0 -76
- v0/relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
- v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
- v0/relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
- v0/relationalai/early_access/dsl/types/__init__.py +0 -40
- v0/relationalai/early_access/dsl/types/concepts.py +0 -12
- v0/relationalai/early_access/dsl/types/entities.py +0 -135
- v0/relationalai/early_access/dsl/types/values.py +0 -17
- v0/relationalai/early_access/dsl/utils.py +0 -102
- v0/relationalai/early_access/graphs/__init__.py +0 -13
- v0/relationalai/early_access/lqp/__init__.py +0 -12
- v0/relationalai/early_access/lqp/compiler/__init__.py +0 -12
- v0/relationalai/early_access/lqp/constructors/__init__.py +0 -18
- v0/relationalai/early_access/lqp/executor/__init__.py +0 -12
- v0/relationalai/early_access/lqp/ir/__init__.py +0 -12
- v0/relationalai/early_access/lqp/passes/__init__.py +0 -12
- v0/relationalai/early_access/lqp/pragmas/__init__.py +0 -12
- v0/relationalai/early_access/lqp/primitives/__init__.py +0 -12
- v0/relationalai/early_access/lqp/types/__init__.py +0 -12
- v0/relationalai/early_access/lqp/utils/__init__.py +0 -12
- v0/relationalai/early_access/lqp/validators/__init__.py +0 -12
- v0/relationalai/early_access/metamodel/__init__.py +0 -58
- v0/relationalai/early_access/metamodel/builtins/__init__.py +0 -12
- v0/relationalai/early_access/metamodel/compiler/__init__.py +0 -12
- v0/relationalai/early_access/metamodel/dependency/__init__.py +0 -12
- v0/relationalai/early_access/metamodel/factory/__init__.py +0 -17
- v0/relationalai/early_access/metamodel/helpers/__init__.py +0 -12
- v0/relationalai/early_access/metamodel/ir/__init__.py +0 -14
- v0/relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
- v0/relationalai/early_access/metamodel/typer/__init__.py +0 -3
- v0/relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
- v0/relationalai/early_access/metamodel/types/__init__.py +0 -15
- v0/relationalai/early_access/metamodel/util/__init__.py +0 -15
- v0/relationalai/early_access/metamodel/visitor/__init__.py +0 -12
- v0/relationalai/early_access/rel/__init__.py +0 -12
- v0/relationalai/early_access/rel/executor/__init__.py +0 -12
- v0/relationalai/early_access/rel/rel_utils/__init__.py +0 -12
- v0/relationalai/early_access/rel/rewrite/__init__.py +0 -7
- v0/relationalai/early_access/solvers/__init__.py +0 -19
- v0/relationalai/early_access/sql/__init__.py +0 -11
- v0/relationalai/early_access/sql/executor/__init__.py +0 -3
- v0/relationalai/early_access/sql/rewrite/__init__.py +0 -3
- v0/relationalai/early_access/tests/logging/__init__.py +0 -12
- v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
- v0/relationalai/early_access/tests/utils/__init__.py +0 -12
- v0/relationalai/environments/__init__.py +0 -35
- v0/relationalai/environments/base.py +0 -381
- v0/relationalai/environments/colab.py +0 -14
- v0/relationalai/environments/generic.py +0 -71
- v0/relationalai/environments/ipython.py +0 -68
- v0/relationalai/environments/jupyter.py +0 -9
- v0/relationalai/environments/snowbook.py +0 -169
- v0/relationalai/errors.py +0 -2455
- v0/relationalai/experimental/SF.py +0 -38
- v0/relationalai/experimental/inspect.py +0 -47
- v0/relationalai/experimental/pathfinder/__init__.py +0 -158
- v0/relationalai/experimental/pathfinder/api.py +0 -160
- v0/relationalai/experimental/pathfinder/automaton.py +0 -584
- v0/relationalai/experimental/pathfinder/bridge.py +0 -226
- v0/relationalai/experimental/pathfinder/compiler.py +0 -416
- v0/relationalai/experimental/pathfinder/datalog.py +0 -214
- v0/relationalai/experimental/pathfinder/diagnostics.py +0 -56
- v0/relationalai/experimental/pathfinder/filter.py +0 -236
- v0/relationalai/experimental/pathfinder/glushkov.py +0 -439
- v0/relationalai/experimental/pathfinder/options.py +0 -265
- v0/relationalai/experimental/pathfinder/rpq.py +0 -344
- v0/relationalai/experimental/pathfinder/transition.py +0 -200
- v0/relationalai/experimental/pathfinder/utils.py +0 -26
- v0/relationalai/experimental/paths/api.py +0 -143
- v0/relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
- v0/relationalai/experimental/paths/examples/basic_example.py +0 -40
- v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
- v0/relationalai/experimental/paths/examples/movie_example.py +0 -77
- v0/relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
- v0/relationalai/experimental/paths/examples/paths_example.py +0 -116
- v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
- v0/relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
- v0/relationalai/experimental/paths/graph.py +0 -185
- v0/relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
- v0/relationalai/experimental/paths/path_algorithms/single.py +0 -59
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
- v0/relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
- v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
- v0/relationalai/experimental/paths/path_algorithms/usp.py +0 -150
- v0/relationalai/experimental/paths/product_graph.py +0 -93
- v0/relationalai/experimental/paths/rpq/automaton.py +0 -584
- v0/relationalai/experimental/paths/rpq/diagnostics.py +0 -56
- v0/relationalai/experimental/paths/rpq/rpq.py +0 -378
- v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
- v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
- v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
- v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
- v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
- v0/relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
- v0/relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
- v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
- v0/relationalai/experimental/paths/tree_agg.py +0 -168
- v0/relationalai/experimental/paths/utilities/iterators.py +0 -27
- v0/relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
- v0/relationalai/experimental/solvers.py +0 -1087
- v0/relationalai/loaders/csv.py +0 -195
- v0/relationalai/loaders/loader.py +0 -177
- v0/relationalai/loaders/types.py +0 -23
- v0/relationalai/rel_emitter.py +0 -373
- v0/relationalai/rel_utils.py +0 -185
- v0/relationalai/semantics/__init__.py +0 -29
- v0/relationalai/semantics/devtools/benchmark_lqp.py +0 -536
- v0/relationalai/semantics/devtools/compilation_manager.py +0 -294
- v0/relationalai/semantics/devtools/extract_lqp.py +0 -110
- v0/relationalai/semantics/internal/internal.py +0 -3785
- v0/relationalai/semantics/internal/snowflake.py +0 -324
- v0/relationalai/semantics/lqp/builtins.py +0 -16
- v0/relationalai/semantics/lqp/compiler.py +0 -22
- v0/relationalai/semantics/lqp/constructors.py +0 -68
- v0/relationalai/semantics/lqp/executor.py +0 -469
- v0/relationalai/semantics/lqp/intrinsics.py +0 -24
- v0/relationalai/semantics/lqp/model2lqp.py +0 -839
- v0/relationalai/semantics/lqp/passes.py +0 -680
- v0/relationalai/semantics/lqp/primitives.py +0 -252
- v0/relationalai/semantics/lqp/result_helpers.py +0 -202
- v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -57
- v0/relationalai/semantics/lqp/rewrite/cdc.py +0 -216
- v0/relationalai/semantics/lqp/rewrite/extract_common.py +0 -338
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +0 -449
- v0/relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
- v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -314
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -296
- v0/relationalai/semantics/lqp/rewrite/splinter.py +0 -76
- v0/relationalai/semantics/lqp/types.py +0 -101
- v0/relationalai/semantics/lqp/utils.py +0 -160
- v0/relationalai/semantics/lqp/validators.py +0 -57
- v0/relationalai/semantics/metamodel/__init__.py +0 -40
- v0/relationalai/semantics/metamodel/builtins.py +0 -774
- v0/relationalai/semantics/metamodel/compiler.py +0 -133
- v0/relationalai/semantics/metamodel/dependency.py +0 -862
- v0/relationalai/semantics/metamodel/executor.py +0 -61
- v0/relationalai/semantics/metamodel/factory.py +0 -287
- v0/relationalai/semantics/metamodel/helpers.py +0 -361
- v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -210
- v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +0 -549
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -165
- v0/relationalai/semantics/metamodel/typer/checker.py +0 -353
- v0/relationalai/semantics/metamodel/typer/typer.py +0 -1395
- v0/relationalai/semantics/metamodel/util.py +0 -505
- v0/relationalai/semantics/reasoners/__init__.py +0 -10
- v0/relationalai/semantics/reasoners/graph/__init__.py +0 -37
- v0/relationalai/semantics/reasoners/graph/core.py +0 -9020
- v0/relationalai/semantics/reasoners/optimization/__init__.py +0 -68
- v0/relationalai/semantics/reasoners/optimization/common.py +0 -88
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1163
- v0/relationalai/semantics/rel/builtins.py +0 -40
- v0/relationalai/semantics/rel/compiler.py +0 -989
- v0/relationalai/semantics/rel/executor.py +0 -359
- v0/relationalai/semantics/rel/rel.py +0 -482
- v0/relationalai/semantics/rel/rel_utils.py +0 -276
- v0/relationalai/semantics/snowflake/__init__.py +0 -3
- v0/relationalai/semantics/sql/compiler.py +0 -2503
- v0/relationalai/semantics/sql/executor/duck_db.py +0 -52
- v0/relationalai/semantics/sql/executor/result_helpers.py +0 -64
- v0/relationalai/semantics/sql/executor/snowflake.py +0 -145
- v0/relationalai/semantics/sql/rewrite/denormalize.py +0 -222
- v0/relationalai/semantics/sql/rewrite/double_negation.py +0 -49
- v0/relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
- v0/relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
- v0/relationalai/semantics/sql/sql.py +0 -504
- v0/relationalai/semantics/std/__init__.py +0 -54
- v0/relationalai/semantics/std/constraints.py +0 -43
- v0/relationalai/semantics/std/datetime.py +0 -363
- v0/relationalai/semantics/std/decimals.py +0 -62
- v0/relationalai/semantics/std/floats.py +0 -7
- v0/relationalai/semantics/std/integers.py +0 -22
- v0/relationalai/semantics/std/math.py +0 -141
- v0/relationalai/semantics/std/pragmas.py +0 -11
- v0/relationalai/semantics/std/re.py +0 -83
- v0/relationalai/semantics/std/std.py +0 -14
- v0/relationalai/semantics/std/strings.py +0 -63
- v0/relationalai/semantics/tests/__init__.py +0 -0
- v0/relationalai/semantics/tests/test_snapshot_abstract.py +0 -143
- v0/relationalai/semantics/tests/test_snapshot_base.py +0 -9
- v0/relationalai/semantics/tests/utils.py +0 -46
- v0/relationalai/std/__init__.py +0 -70
- v0/relationalai/tools/__init__.py +0 -0
- v0/relationalai/tools/cli.py +0 -1940
- v0/relationalai/tools/cli_controls.py +0 -1826
- v0/relationalai/tools/cli_helpers.py +0 -390
- v0/relationalai/tools/debugger.py +0 -183
- v0/relationalai/tools/debugger_client.py +0 -109
- v0/relationalai/tools/debugger_server.py +0 -302
- v0/relationalai/tools/dev.py +0 -685
- v0/relationalai/tools/qb_debugger.py +0 -425
- v0/relationalai/util/clean_up_databases.py +0 -95
- v0/relationalai/util/format.py +0 -123
- v0/relationalai/util/list_databases.py +0 -9
- v0/relationalai/util/otel_configuration.py +0 -25
- v0/relationalai/util/otel_handler.py +0 -484
- v0/relationalai/util/snowflake_handler.py +0 -88
- v0/relationalai/util/span_format_test.py +0 -43
- v0/relationalai/util/span_tracker.py +0 -207
- v0/relationalai/util/spans_file_handler.py +0 -72
- v0/relationalai/util/tracing_handler.py +0 -34
- /relationalai/{semantics/frontend → analysis}/__init__.py +0 -0
- {v0/relationalai → relationalai}/analysis/mechanistic.py +0 -0
- {v0/relationalai → relationalai}/analysis/whynot.py +0 -0
- /relationalai/{shims → auth}/__init__.py +0 -0
- {v0/relationalai → relationalai}/auth/jwt_generator.py +0 -0
- {v0/relationalai → relationalai}/auth/oauth_callback_server.py +0 -0
- {v0/relationalai → relationalai}/auth/token_handler.py +0 -0
- {v0/relationalai → relationalai}/auth/util.py +0 -0
- {v0/relationalai/clients → relationalai/clients/resources/snowflake}/cache_store.py +0 -0
- {v0/relationalai → relationalai}/compiler.py +0 -0
- {v0/relationalai → relationalai}/dependencies.py +0 -0
- {v0/relationalai → relationalai}/docutils.py +0 -0
- {v0/relationalai/analysis → relationalai/early_access}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/__init__.py +0 -0
- {v0/relationalai/auth → relationalai/early_access/dsl/adapters}/__init__.py +0 -0
- {v0/relationalai/early_access → relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
- {v0/relationalai/early_access/dsl/adapters → relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
- {v0/relationalai/early_access/dsl/adapters/orm → relationalai/early_access/dsl/bindings}/__init__.py +0 -0
- {v0/relationalai/early_access/dsl/adapters/owl → relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
- {v0/relationalai/early_access/dsl/bindings → relationalai/early_access/dsl/codegen}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/constants.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/core/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/core/stack.py +0 -0
- {v0/relationalai/early_access/dsl/bindings/legacy → relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/core/utils.py +0 -0
- {v0/relationalai/early_access/dsl/codegen → relationalai/early_access/dsl/ir}/__init__.py +0 -0
- {v0/relationalai/early_access/dsl/core/temporal → relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
- {v0/relationalai/early_access/dsl/ir → relationalai/early_access/dsl/orm}/__init__.py +0 -0
- {v0/relationalai/early_access/dsl/ontologies → relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
- {v0/relationalai/early_access/dsl/orm → relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
- {v0/relationalai/early_access/dsl/orm/measures → relationalai/early_access/dsl/serialize}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
- {v0/relationalai → relationalai}/early_access/dsl/serialize/model.py +0 -0
- {v0/relationalai/early_access/dsl/physical_metadata → relationalai/early_access/dsl/snow}/__init__.py +0 -0
- {v0/relationalai → relationalai}/early_access/tests/__init__.py +0 -0
- {v0/relationalai → relationalai}/environments/ci.py +0 -0
- {v0/relationalai → relationalai}/environments/hex.py +0 -0
- {v0/relationalai → relationalai}/environments/terminal.py +0 -0
- {v0/relationalai → relationalai}/experimental/__init__.py +0 -0
- {v0/relationalai → relationalai}/experimental/graphs.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/__init__.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/rpq/__init__.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/rpq/filter.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/rpq/glushkov.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/rpq/transition.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/utilities/__init__.py +0 -0
- {v0/relationalai → relationalai}/experimental/paths/utilities/utilities.py +0 -0
- {v0/relationalai/early_access/dsl/serialize → relationalai/loaders}/__init__.py +0 -0
- {v0/relationalai → relationalai}/metagen.py +0 -0
- {v0/relationalai → relationalai}/metamodel.py +0 -0
- {v0/relationalai → relationalai}/rel.py +0 -0
- {v0/relationalai → relationalai}/semantics/devtools/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/internal/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/internal/annotations.py +0 -0
- {v0/relationalai → relationalai}/semantics/lqp/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/lqp/ir.py +0 -0
- {v0/relationalai → relationalai}/semantics/lqp/pragmas.py +0 -0
- {v0/relationalai → relationalai}/semantics/lqp/rewrite/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/metamodel/dataflow.py +0 -0
- {v0/relationalai → relationalai}/semantics/metamodel/ir.py +0 -0
- {v0/relationalai → relationalai}/semantics/metamodel/rewrite/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/metamodel/typer/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/metamodel/types.py +0 -0
- {v0/relationalai → relationalai}/semantics/metamodel/visitor.py +0 -0
- {v0/relationalai → relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/rel/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/sql/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/sql/executor/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/sql/rewrite/__init__.py +0 -0
- {v0/relationalai/early_access/dsl/snow → relationalai/semantics/tests}/__init__.py +0 -0
- {v0/relationalai → relationalai}/semantics/tests/logging.py +0 -0
- {v0/relationalai → relationalai}/std/aggregates.py +0 -0
- {v0/relationalai → relationalai}/std/dates.py +0 -0
- {v0/relationalai → relationalai}/std/graphs.py +0 -0
- {v0/relationalai → relationalai}/std/inspect.py +0 -0
- {v0/relationalai → relationalai}/std/math.py +0 -0
- {v0/relationalai → relationalai}/std/re.py +0 -0
- {v0/relationalai → relationalai}/std/strings.py +0 -0
- {v0/relationalai/loaders → relationalai/tools}/__init__.py +0 -0
- {v0/relationalai → relationalai}/tools/cleanup_snapshots.py +0 -0
- {v0/relationalai → relationalai}/tools/constants.py +0 -0
- {v0/relationalai → relationalai}/tools/query_utils.py +0 -0
- {v0/relationalai → relationalai}/tools/snapshot_viewer.py +0 -0
- {v0/relationalai → relationalai}/util/__init__.py +0 -0
- {v0/relationalai → relationalai}/util/constants.py +0 -0
- {v0/relationalai → relationalai}/util/graph.py +0 -0
- {v0/relationalai → relationalai}/util/timeout.py +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Optional, Sequence
|
|
3
|
+
from relationalai.semantics.internal import internal
|
|
4
|
+
from relationalai.semantics.metamodel.ir import (
|
|
5
|
+
Node, Require, Logical, Var, Relation, Lookup, ScalarType
|
|
6
|
+
)
|
|
7
|
+
from relationalai.semantics.metamodel import builtins
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Helper functions for converting `Require` nodes with unique constraints to functional
|
|
12
|
+
dependencies. The main functionalities provided are:
|
|
13
|
+
1. Check whether a `Require` node is a valid unique constraint representation
|
|
14
|
+
2. Represent the uniqueness constraint as a functional dependency
|
|
15
|
+
3. Check if the functional dependency is structural i.e., can be represented with
|
|
16
|
+
`@function(k)` annotation on a single relation.
|
|
17
|
+
|
|
18
|
+
=========================== Structure of unique constraints ================================
|
|
19
|
+
A `Require` node represents a _unique constraint_ if it meets the following criteria:
|
|
20
|
+
* the `Require` node's `domain` is an empty `Logical` node
|
|
21
|
+
* the `Require` node's `checks` has a single `Check` node
|
|
22
|
+
* the single `Check` node has `Logical` task that is a list of `Lookup` tasks
|
|
23
|
+
* precisely one `Lookup` task in the `Check` uses the `unique` builtin relation name
|
|
24
|
+
* the `unique` lookup has precisely one argument, which is a `TupleArg` or a `tuple`
|
|
25
|
+
containing at least one `Var`
|
|
26
|
+
* all `Lookup` nodes use variables only (no constants)
|
|
27
|
+
* the variables used in the `unique` lookup are a subset of the variables used in other
|
|
28
|
+
lookups
|
|
29
|
+
============================================================================================
|
|
30
|
+
|
|
31
|
+
We use the following unique constraint as the running example.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Require
|
|
35
|
+
domain
|
|
36
|
+
Logical
|
|
37
|
+
checks:
|
|
38
|
+
Check
|
|
39
|
+
check:
|
|
40
|
+
Logical
|
|
41
|
+
Person(person::Person)
|
|
42
|
+
first_name(person::Person, firstname::String)
|
|
43
|
+
last_name(person::Person, lastname::String)
|
|
44
|
+
unique((firstname::String, lastname::String))
|
|
45
|
+
error:
|
|
46
|
+
...
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
=========================== Semantics of unique constraints ================================
|
|
50
|
+
A unique constraint states that the columns declared in the `unique` predicate must be
|
|
51
|
+
unique in the result of the conjunctive query consisting of all remaining predicates.
|
|
52
|
+
============================================================================================
|
|
53
|
+
|
|
54
|
+
In the running example, the conjunctive query computes a table with 3 columns, the person id
|
|
55
|
+
`person::Person`, the first name `firstname::String`, and the last name `lastname::String`.
|
|
56
|
+
The uniqueness predicate `unique((firstname::String, lastname::String))` states that no person
|
|
57
|
+
can have more than a single combination of first and last name.
|
|
58
|
+
|
|
59
|
+
The unique constraint in the running example above corresponds to the following functional
|
|
60
|
+
dependency.
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Person(x) ∧ first_name(x, y) ∧ last_name(x, z): {y, z} -> {x}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
------------------------------ Redundant Type Atoms ----------------------------------------
|
|
67
|
+
At the time of writing, PyRel does not yet remove redundant unary atoms. For instance, in
|
|
68
|
+
the running example, the atom `Person(person::Person)` is redundant because the type of the
|
|
69
|
+
`person` variable is specified in the other two atoms `first_name` and `last_name`.
|
|
70
|
+
Consequently, we identify redundant atoms and remove them from the definition of the
|
|
71
|
+
corresponding functional dependency.
|
|
72
|
+
|
|
73
|
+
Formally, a _guard_ atom is any `Lookup` node whose relation name is not `unique`. Now, a
|
|
74
|
+
unary guard atom `T(x::T)` is _redundant_ if the uniqueness constraint has a non-unary guard
|
|
75
|
+
atom `R(...,x::T,...)`.
|
|
76
|
+
|
|
77
|
+
================================ Normalized FDs ============================================
|
|
78
|
+
Now, the _(normalized)_ functional dependency_ corresponding to a unique constraint is an
|
|
79
|
+
object of the form `φ: X → Y`, where :
|
|
80
|
+
1. `φ` is the set of all non-redundant guard atoms.
|
|
81
|
+
2. `X` is the set of variables used in the `unique` atom
|
|
82
|
+
3. `Y` is the set of all other variables used in the constraint
|
|
83
|
+
============================================================================================
|
|
84
|
+
|
|
85
|
+
The normalized functional dependency corresponding to the unique constraints from the running
|
|
86
|
+
example is :
|
|
87
|
+
```
|
|
88
|
+
first_name(person::Person, firstname::String) ∧ last_name(person::Person, lastname::String): {firstname:String, lastname:String} -> {person:Person}
|
|
89
|
+
```
|
|
90
|
+
Note that the unary atom `Person(person::Person)` is redundant and thus omitted from the
|
|
91
|
+
decomposition.
|
|
92
|
+
|
|
93
|
+
Some simple functional dependencies can, however, be expressed simply with `@function(k)`
|
|
94
|
+
attribute of a single relation. Specifically, a functional dependency `φ: X → Y` is
|
|
95
|
+
_structural_ if φ consists of a single atom `R(x1,...,xm,y1,...,yk)` and `X = {x1,...,xm}`.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
#
|
|
99
|
+
# Checks that an input `Require` node is a valid unique constraint. Returns `None` if not.
|
|
100
|
+
# If yes, we return the decomposition of the unique constraint as a tuple
|
|
101
|
+
# `(all_vars, unique_vars, guard)`, where
|
|
102
|
+
# - `all_vars` is the list of all variables used in the constraint
|
|
103
|
+
# - `unique_vars` is the list of variables used in the `unique` atom
|
|
104
|
+
# - `guard` is the list of all other `Lookup` atoms
|
|
105
|
+
#
|
|
106
|
+
def _split_unique_require_node(node: Require) -> Optional[tuple[list[Var], list[Var], list[Lookup]]]:
|
|
107
|
+
if not isinstance(node.domain, Logical):
|
|
108
|
+
return None
|
|
109
|
+
if len(node.domain.body) != 0:
|
|
110
|
+
return None
|
|
111
|
+
if len(node.checks) != 1:
|
|
112
|
+
return None
|
|
113
|
+
check = node.checks[0]
|
|
114
|
+
if not isinstance(check.check, Logical):
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
unique_atom: Optional[Lookup] = None
|
|
118
|
+
guard: list[Lookup] = []
|
|
119
|
+
for task in check.check.body:
|
|
120
|
+
if not isinstance(task, Lookup):
|
|
121
|
+
return None
|
|
122
|
+
if task.relation.name == builtins.unique.name:
|
|
123
|
+
if unique_atom is not None:
|
|
124
|
+
return None
|
|
125
|
+
unique_atom = task
|
|
126
|
+
else:
|
|
127
|
+
guard.append(task)
|
|
128
|
+
|
|
129
|
+
if unique_atom is None:
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
# collect variables
|
|
133
|
+
all_vars: list[Var] = []
|
|
134
|
+
for lookup in guard:
|
|
135
|
+
for arg in lookup.args:
|
|
136
|
+
if not isinstance(arg, Var):
|
|
137
|
+
return None
|
|
138
|
+
if arg in all_vars:
|
|
139
|
+
continue
|
|
140
|
+
all_vars.append(arg)
|
|
141
|
+
|
|
142
|
+
unique_vars: list[Var] = []
|
|
143
|
+
if len(unique_atom.args) != 1:
|
|
144
|
+
return None
|
|
145
|
+
if not isinstance(unique_atom.args[0], (internal.TupleArg, tuple)):
|
|
146
|
+
return None
|
|
147
|
+
if len(unique_atom.args[0]) == 0:
|
|
148
|
+
return None
|
|
149
|
+
for arg in unique_atom.args[0]:
|
|
150
|
+
if not isinstance(arg, Var):
|
|
151
|
+
return None
|
|
152
|
+
if arg in unique_vars:
|
|
153
|
+
return None
|
|
154
|
+
unique_vars.append(arg)
|
|
155
|
+
|
|
156
|
+
# check that unique vars are a subset of other vars
|
|
157
|
+
if not set(unique_vars).issubset(set(all_vars)):
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
return list(all_vars), list(unique_vars), guard
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def is_valid_unique_constraint(node: Require) -> bool:
|
|
164
|
+
"""
|
|
165
|
+
Checks whether the input `Require` node is a valid unique constraint. See description at
|
|
166
|
+
the top of the file for details.
|
|
167
|
+
"""
|
|
168
|
+
return _split_unique_require_node(node) is not None
|
|
169
|
+
|
|
170
|
+
#
|
|
171
|
+
# A unary guard atom `T(x::T)` is redundant if the constraint contains a non-unary atom
|
|
172
|
+
# `R(...,x::T,...)`. We discard all redundant guard atoms in the constructed fd.
|
|
173
|
+
#
|
|
174
|
+
def normalized_fd(node: Require) -> Optional[FunctionalDependency]:
|
|
175
|
+
"""
|
|
176
|
+
If the input `Require` node is a uniqueness constraint, constructs its reduced
|
|
177
|
+
functional dependency `φ: X -> Y`, where `φ` contains all non-redundant guard atoms,
|
|
178
|
+
`X` are the variables used in the `unique` atom, and `Y` are the remaining variables.
|
|
179
|
+
Returns `None` if the input node is not a valid uniqueness constraint.
|
|
180
|
+
"""
|
|
181
|
+
parts = _split_unique_require_node(node)
|
|
182
|
+
if parts is None:
|
|
183
|
+
return None
|
|
184
|
+
all_vars, unique_vars, guard_atoms = parts
|
|
185
|
+
|
|
186
|
+
# remove redundant lookups
|
|
187
|
+
redundant_guard_atoms: list[Lookup] = []
|
|
188
|
+
for atom in guard_atoms:
|
|
189
|
+
# the atom is unary A(x::T)
|
|
190
|
+
if len(atom.args) != 1:
|
|
191
|
+
continue
|
|
192
|
+
var = atom.args[0]
|
|
193
|
+
assert isinstance(var, Var)
|
|
194
|
+
# T is a scalar type (which includes entity types)
|
|
195
|
+
var_type = var.type
|
|
196
|
+
if not isinstance(var_type, ScalarType):
|
|
197
|
+
continue
|
|
198
|
+
# the atom is a entity typing T(x::T) i.e., T = A (and hence not a Boolean property)
|
|
199
|
+
var_type_name = var_type.name
|
|
200
|
+
rel_name = atom.relation.name
|
|
201
|
+
if rel_name != var_type_name:
|
|
202
|
+
continue
|
|
203
|
+
# Found an atom of the form T(x::T)
|
|
204
|
+
# check if there is another atom R(...,x::T,...)
|
|
205
|
+
for typed_atom in guard_atoms:
|
|
206
|
+
if len(typed_atom.args) == 1:
|
|
207
|
+
continue
|
|
208
|
+
if var in typed_atom.args:
|
|
209
|
+
redundant_guard_atoms.append(atom)
|
|
210
|
+
break
|
|
211
|
+
|
|
212
|
+
guard = [atom for atom in guard_atoms if atom not in redundant_guard_atoms]
|
|
213
|
+
keys = unique_vars
|
|
214
|
+
values = [v for v in all_vars if v not in keys]
|
|
215
|
+
|
|
216
|
+
return FunctionalDependency(guard, keys, values)
|
|
217
|
+
|
|
218
|
+
class FunctionalDependency:
|
|
219
|
+
"""
|
|
220
|
+
Represents a functional dependency of the form `φ: X -> Y`, where
|
|
221
|
+
- `φ` is a set of `Lookup` atoms
|
|
222
|
+
- `X` and `Y` are disjoint and covering sets of variables used in `φ`
|
|
223
|
+
"""
|
|
224
|
+
def __init__(self, guard: Sequence[Lookup], keys: Sequence[Var], values: Sequence[Var]):
|
|
225
|
+
self.guard = tuple(guard)
|
|
226
|
+
self.keys = tuple(keys)
|
|
227
|
+
self.values = tuple(values)
|
|
228
|
+
assert set(self.keys).isdisjoint(set(self.values)), "Keys and values must be disjoint"
|
|
229
|
+
|
|
230
|
+
# for structural fd check
|
|
231
|
+
self._is_structural:bool = False
|
|
232
|
+
self._structural_relation:Optional[Relation] = None
|
|
233
|
+
self._structural_rank:Optional[int] = None
|
|
234
|
+
|
|
235
|
+
self._determine_is_structural()
|
|
236
|
+
|
|
237
|
+
# A functional dependency `φ: X → Y` is _k-functional_ if `φ` consists of a single atom
|
|
238
|
+
# `R(x1,...,xm,y1,...,yk)` and `X = {x1,...,xm}`. Not all functional dependencies are
|
|
239
|
+
# k-functional. For instance, `R(x, y, z): {y, z} → {x}` cannot be expressed with
|
|
240
|
+
# `@function`. neither can `R(x, y) ∧ P(x, z) : {x} → {y, z}`.
|
|
241
|
+
def _determine_is_structural(self):
|
|
242
|
+
if len(self.guard) != 1:
|
|
243
|
+
self._is_structural = False
|
|
244
|
+
return
|
|
245
|
+
atom = next(iter(self.guard))
|
|
246
|
+
atom_vars = atom.args
|
|
247
|
+
if len(atom_vars) <= len(self.keys): # @function(0) provides no information
|
|
248
|
+
self._is_structural = False
|
|
249
|
+
return
|
|
250
|
+
prefix_vars = atom_vars[:len(self.keys)]
|
|
251
|
+
if set(prefix_vars) != set(self.keys):
|
|
252
|
+
self._is_structural = False
|
|
253
|
+
return
|
|
254
|
+
self._is_structural = True
|
|
255
|
+
self._structural_relation = atom.relation
|
|
256
|
+
self._structural_rank = len(atom_vars) - len(self.keys)
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def is_structural(self) -> bool:
|
|
260
|
+
"""
|
|
261
|
+
Whether the functional dependency is functional, i.e., can be represented
|
|
262
|
+
with `@function(k)` annotation on a single relation.
|
|
263
|
+
"""
|
|
264
|
+
return self._is_structural
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def structural_relation(self) -> Relation:
|
|
268
|
+
"""
|
|
269
|
+
The structural relation of a functional dependency. Raises ValueError if the functional
|
|
270
|
+
dependency is not structural.
|
|
271
|
+
"""
|
|
272
|
+
if not self._is_structural:
|
|
273
|
+
raise ValueError("Functional dependency is not structural")
|
|
274
|
+
assert self._structural_relation is not None
|
|
275
|
+
return self._structural_relation
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def structural_rank(self) -> int:
|
|
279
|
+
"""
|
|
280
|
+
The structural rank k of k-structural fd. Raises ValueError if the structural
|
|
281
|
+
dependency is not k-structural.
|
|
282
|
+
"""
|
|
283
|
+
if not self._is_structural:
|
|
284
|
+
raise ValueError("Functional dependency is not structural")
|
|
285
|
+
assert self._structural_rank is not None
|
|
286
|
+
return self._structural_rank
|
|
287
|
+
|
|
288
|
+
def __str__(self) -> str:
|
|
289
|
+
guard_str = " ∧ ".join([str(atom) for atom in self.guard]).strip()
|
|
290
|
+
keys_str = ", ".join([str(var) for var in self.keys]).strip()
|
|
291
|
+
values_str = ", ".join([str(var) for var in self.values]).strip()
|
|
292
|
+
return f"{guard_str}: {{{keys_str}}} -> {{{values_str}}}"
|
|
293
|
+
|
|
294
|
+
def contains_only_declarable_constraints(node: Node) -> bool:
|
|
295
|
+
"""
|
|
296
|
+
Checks whether the input `Logical` node contains only `Require` nodes annotated with
|
|
297
|
+
`declare_constraint`.
|
|
298
|
+
"""
|
|
299
|
+
if not isinstance(node, Logical):
|
|
300
|
+
return False
|
|
301
|
+
if len(node.body) == 0:
|
|
302
|
+
return False
|
|
303
|
+
for task in node.body:
|
|
304
|
+
if not isinstance(task, Require):
|
|
305
|
+
return False
|
|
306
|
+
if not is_declarable_constraint(task):
|
|
307
|
+
return False
|
|
308
|
+
return True
|
|
309
|
+
|
|
310
|
+
def is_declarable_constraint(node: Require) -> bool:
|
|
311
|
+
"""
|
|
312
|
+
Checks whether the input `Require` node is annotated with `declare_constraint`.
|
|
313
|
+
"""
|
|
314
|
+
return builtins.declare_constraint_annotation in node.annotations
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from relationalai.semantics.metamodel import ir, factory as f, helpers
|
|
4
|
+
from relationalai.semantics.metamodel.compiler import Pass
|
|
5
|
+
from relationalai.semantics.metamodel.visitor import Visitor, Rewriter
|
|
6
|
+
from relationalai.semantics.metamodel.util import OrderedSet, ordered_set
|
|
7
|
+
from typing import Optional, Any, Tuple, Iterable
|
|
8
|
+
from .functional_dependencies import contains_only_declarable_constraints
|
|
9
|
+
|
|
10
|
+
class QuantifyVars(Pass):
|
|
11
|
+
"""
|
|
12
|
+
Introduce existential quantifiers as closely as possible to the affected sub-tasks.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def rewrite(self, model: ir.Model, options:dict={}) -> ir.Model:
|
|
16
|
+
var_info = VarScopeInfo()
|
|
17
|
+
model.root.accept(var_info)
|
|
18
|
+
quant_nodes = FindQuantificationNodes(var_info)
|
|
19
|
+
model.root.accept(quant_nodes)
|
|
20
|
+
return QuantifyVarsRewriter(quant_nodes).walk(model)
|
|
21
|
+
|
|
22
|
+
def _ignored_vars(node: ir.Logical|ir.Not):
|
|
23
|
+
if isinstance(node, ir.Not):
|
|
24
|
+
return ordered_set()
|
|
25
|
+
|
|
26
|
+
vars_to_ignore = ordered_set()
|
|
27
|
+
for task in node.body:
|
|
28
|
+
if isinstance(task, ir.Output):
|
|
29
|
+
# Vars that are output don't need to be quantified.
|
|
30
|
+
vars_to_ignore.update(helpers.output_vars(task.aliases))
|
|
31
|
+
|
|
32
|
+
elif isinstance(task, ir.Update):
|
|
33
|
+
# Vars that are in effects don't need to be quantified.
|
|
34
|
+
vars_to_ignore.update(helpers.vars(task.args))
|
|
35
|
+
|
|
36
|
+
elif isinstance(task, ir.Aggregate):
|
|
37
|
+
# Variables that are inputs to an aggregate don't need to be quantified.
|
|
38
|
+
for var in helpers.vars(task.args):
|
|
39
|
+
if helpers.is_aggregate_input(var, task):
|
|
40
|
+
vars_to_ignore.add(var)
|
|
41
|
+
# Variables that are in the projections, and not in the group-by, don't need to be quantified.
|
|
42
|
+
for var in task.projection:
|
|
43
|
+
if var not in task.group:
|
|
44
|
+
vars_to_ignore.add(var)
|
|
45
|
+
|
|
46
|
+
elif isinstance(task, ir.Rank):
|
|
47
|
+
# Variables that are keys, and not in the group-by, don't need to be quantified.
|
|
48
|
+
for var in task.args + task.projection:
|
|
49
|
+
if var not in task.group:
|
|
50
|
+
vars_to_ignore.add(var)
|
|
51
|
+
|
|
52
|
+
return vars_to_ignore
|
|
53
|
+
|
|
54
|
+
class VarScopeInfo(Visitor):
|
|
55
|
+
"""
|
|
56
|
+
Compute which variables are still in scope for a given node.
|
|
57
|
+
Those variables will be potentially quantified in this node.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
# Keep track of variables that are still in scope for a given node.
|
|
61
|
+
# Variables are introduced into scope in Var nodes and then propagated upwards.
|
|
62
|
+
# The propagation stops when:
|
|
63
|
+
# 1. They are explicitly quantified, or
|
|
64
|
+
# 2. A node that needs to quantify them is identified.
|
|
65
|
+
# That node will be the top-most node that still has them in scope.
|
|
66
|
+
_vars_in_scope: dict[int, OrderedSet[ir.Var]]
|
|
67
|
+
|
|
68
|
+
IGNORED_NODES = (ir.Type,
|
|
69
|
+
ir.Var, ir.Literal, ir.Relation, ir.Field,
|
|
70
|
+
ir.Default, ir.Output, ir.Update, ir.Aggregate,
|
|
71
|
+
ir.Check, ir.Require,
|
|
72
|
+
ir.Annotation, ir.Rank)
|
|
73
|
+
|
|
74
|
+
def __init__(self):
|
|
75
|
+
super().__init__()
|
|
76
|
+
self._vars_in_scope = {}
|
|
77
|
+
|
|
78
|
+
def leave(self, node: ir.Node, parent: Optional[ir.Node]=None):
|
|
79
|
+
if contains_only_declarable_constraints(node):
|
|
80
|
+
return node
|
|
81
|
+
|
|
82
|
+
if isinstance(node, ir.Lookup):
|
|
83
|
+
self._record(node, helpers.vars(node.args))
|
|
84
|
+
|
|
85
|
+
elif isinstance(node, ir.Data):
|
|
86
|
+
self._record(node, helpers.vars(node.vars))
|
|
87
|
+
|
|
88
|
+
elif isinstance(node, ir.Construct):
|
|
89
|
+
self._record(node, helpers.vars(node.values))
|
|
90
|
+
self._record(node, [node.id_var])
|
|
91
|
+
|
|
92
|
+
elif isinstance(node, ir.Exists) or isinstance(node, ir.ForAll):
|
|
93
|
+
# Exists and ForAll inherit the vars in scope from their sub-task,
|
|
94
|
+
# but then remove the vars they quantify over.
|
|
95
|
+
scope_vars = self._vars_in_scope.get(node.task.id, None)
|
|
96
|
+
if scope_vars:
|
|
97
|
+
scope_vars.difference_update(node.vars)
|
|
98
|
+
self._record(node, scope_vars)
|
|
99
|
+
|
|
100
|
+
elif isinstance(node, ir.Not):
|
|
101
|
+
# Not inherits the vars in scope from its sub-task.
|
|
102
|
+
scope_vars = self._vars_in_scope.get(node.task.id, None)
|
|
103
|
+
self._record(node, scope_vars)
|
|
104
|
+
|
|
105
|
+
elif isinstance(node, (ir.Match, ir.Union)):
|
|
106
|
+
# Match/Union inherits the vars in scope from its sub-tasks.
|
|
107
|
+
scope_vars = ordered_set()
|
|
108
|
+
for task in node.tasks:
|
|
109
|
+
sub_scope_vars = self._vars_in_scope.get(task.id, None)
|
|
110
|
+
if sub_scope_vars:
|
|
111
|
+
scope_vars.update(sub_scope_vars)
|
|
112
|
+
# Hoisted vars are not considered for quantification at this level.
|
|
113
|
+
scope_vars.difference_update(helpers.hoisted_vars(node.hoisted))
|
|
114
|
+
self._record(node, scope_vars)
|
|
115
|
+
|
|
116
|
+
elif isinstance(node, ir.Logical):
|
|
117
|
+
self._do_logical(node)
|
|
118
|
+
|
|
119
|
+
else:
|
|
120
|
+
assert isinstance(node, self.IGNORED_NODES), f"Unexpected node kind ({node.kind}) -> {node}"
|
|
121
|
+
|
|
122
|
+
return node
|
|
123
|
+
|
|
124
|
+
def _do_logical(self, node: ir.Logical):
|
|
125
|
+
ignored_vars = _ignored_vars(node)
|
|
126
|
+
|
|
127
|
+
scope_vars = ordered_set()
|
|
128
|
+
all_nested_vars = ordered_set()
|
|
129
|
+
output_vars = ordered_set()
|
|
130
|
+
|
|
131
|
+
# Collect all variables from logical sub-tasks
|
|
132
|
+
for task in node.body:
|
|
133
|
+
if isinstance(task, ir.Output):
|
|
134
|
+
output_vars.update(helpers.output_vars(task.aliases))
|
|
135
|
+
|
|
136
|
+
if isinstance(task, (ir.Aggregate, ir.Rank)):
|
|
137
|
+
# Variables that are in the group-by, and not in the projections, can come into scope.
|
|
138
|
+
for var in task.group:
|
|
139
|
+
if var not in task.args:
|
|
140
|
+
scope_vars.add(var)
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
sub_scope_vars = self._vars_in_scope.get(task.id, None)
|
|
144
|
+
|
|
145
|
+
# Hoisted variables from sub-tasks are brought again into scope.
|
|
146
|
+
if isinstance(task, (ir.Logical, ir.Union, ir.Match)):
|
|
147
|
+
scope_vars.update(helpers.hoisted_vars(task.hoisted))
|
|
148
|
+
|
|
149
|
+
if sub_scope_vars:
|
|
150
|
+
if isinstance(task, ir.Logical):
|
|
151
|
+
all_nested_vars.update(sub_scope_vars)
|
|
152
|
+
elif not isinstance(task, ir.Not):
|
|
153
|
+
# For all other node kinds (except Not), just propagate the variables in scope.
|
|
154
|
+
# Not nodes stop the propagation of variables coming from their sub-tasks.
|
|
155
|
+
scope_vars.update(sub_scope_vars)
|
|
156
|
+
|
|
157
|
+
# Nested variables also need to be introduced, provided they are not output variables.
|
|
158
|
+
for var in all_nested_vars:
|
|
159
|
+
if var not in output_vars:
|
|
160
|
+
scope_vars.add(var)
|
|
161
|
+
|
|
162
|
+
if scope_vars:
|
|
163
|
+
scope_vars.difference_update(ignored_vars)
|
|
164
|
+
# Hoisted vars are not considered for quantification at this level.
|
|
165
|
+
scope_vars.difference_update(helpers.hoisted_vars(node.hoisted))
|
|
166
|
+
self._record(node, scope_vars)
|
|
167
|
+
|
|
168
|
+
def _record(self, node: ir.Node, vars: Iterable[ir.Var]|None):
|
|
169
|
+
if not vars:
|
|
170
|
+
return
|
|
171
|
+
if node.id not in self._vars_in_scope:
|
|
172
|
+
self._vars_in_scope[node.id] = ordered_set()
|
|
173
|
+
self._vars_in_scope[node.id].update(vars)
|
|
174
|
+
|
|
175
|
+
class FindQuantificationNodes(Visitor):
|
|
176
|
+
"""
|
|
177
|
+
Find the top-most nodes that need to quantify a variable.
|
|
178
|
+
The same variable may be quantified at different points assuming they are not parent/child.
|
|
179
|
+
E.g.,
|
|
180
|
+
Logical
|
|
181
|
+
Exists(x)
|
|
182
|
+
...
|
|
183
|
+
Logical
|
|
184
|
+
Exists(x, y)
|
|
185
|
+
...
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
node_quantifies_vars: dict[int, OrderedSet[ir.Var]]
|
|
189
|
+
|
|
190
|
+
def __init__(self, var_info: VarScopeInfo):
|
|
191
|
+
super().__init__()
|
|
192
|
+
self._vars_in_scope = var_info._vars_in_scope
|
|
193
|
+
self._handled_vars = ordered_set()
|
|
194
|
+
self.node_quantifies_vars = {}
|
|
195
|
+
|
|
196
|
+
def enter(self, node: ir.Node, parent: Optional[ir.Node]=None) -> "Visitor":
|
|
197
|
+
if contains_only_declarable_constraints(node):
|
|
198
|
+
return self
|
|
199
|
+
|
|
200
|
+
if isinstance(node, (ir.Logical, ir.Not)):
|
|
201
|
+
ignored_vars = _ignored_vars(node)
|
|
202
|
+
self._handled_vars.update(ignored_vars)
|
|
203
|
+
|
|
204
|
+
scope_vars = self._vars_in_scope.get(node.id, None)
|
|
205
|
+
if scope_vars:
|
|
206
|
+
scope_vars.difference_update(self._handled_vars)
|
|
207
|
+
if scope_vars:
|
|
208
|
+
self._handled_vars.update(scope_vars)
|
|
209
|
+
self.node_quantifies_vars[node.id] = scope_vars
|
|
210
|
+
return self
|
|
211
|
+
|
|
212
|
+
def leave(self, node: ir.Node, parent: Optional[ir.Node]=None) -> ir.Node:
|
|
213
|
+
if contains_only_declarable_constraints(node):
|
|
214
|
+
return node
|
|
215
|
+
|
|
216
|
+
if isinstance(node, (ir.Logical, ir.Not)):
|
|
217
|
+
ignored_vars = _ignored_vars(node)
|
|
218
|
+
self._handled_vars.difference_update(ignored_vars)
|
|
219
|
+
|
|
220
|
+
scope_vars = self._vars_in_scope.get(node.id, None)
|
|
221
|
+
if scope_vars:
|
|
222
|
+
self._handled_vars.difference_update(scope_vars)
|
|
223
|
+
return node
|
|
224
|
+
|
|
225
|
+
class QuantifyVarsRewriter(Rewriter):
|
|
226
|
+
"""
|
|
227
|
+
Rewrite the model to quantify variables as closely as possible to the affected sub-tasks.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
def __init__(self, quant: FindQuantificationNodes):
|
|
231
|
+
super().__init__()
|
|
232
|
+
self.node_quantifies_vars = quant.node_quantifies_vars
|
|
233
|
+
|
|
234
|
+
def handle_logical(self, node: ir.Logical, parent: ir.Node, ctx:Optional[Any]=None) -> ir.Logical:
|
|
235
|
+
if contains_only_declarable_constraints(node):
|
|
236
|
+
return node
|
|
237
|
+
|
|
238
|
+
new_body = self.walk_list(node.body, node)
|
|
239
|
+
|
|
240
|
+
if node.id in self.node_quantifies_vars:
|
|
241
|
+
vars = self.node_quantifies_vars[node.id]
|
|
242
|
+
effect_tasks = []
|
|
243
|
+
inner_tasks = []
|
|
244
|
+
agg_or_rank_tasks = []
|
|
245
|
+
for task in new_body:
|
|
246
|
+
if isinstance(task, ir.Output):
|
|
247
|
+
effect_tasks.append(task)
|
|
248
|
+
|
|
249
|
+
elif isinstance(task, ir.Update):
|
|
250
|
+
effect_tasks.append(task)
|
|
251
|
+
|
|
252
|
+
elif isinstance(task, (ir.Aggregate, ir.Rank)):
|
|
253
|
+
# TODO: QB shouldn't generate multiple aggregate tasks, but unit tests written
|
|
254
|
+
# in IR directly may do so and the flatten pass doesn't split them yet.
|
|
255
|
+
if len(agg_or_rank_tasks) > 0:
|
|
256
|
+
print(f"Multiple aggregate/rank tasks found: {agg_or_rank_tasks} and {task}")
|
|
257
|
+
agg_or_rank_tasks.append(task)
|
|
258
|
+
|
|
259
|
+
else:
|
|
260
|
+
inner_tasks.append(task)
|
|
261
|
+
|
|
262
|
+
if vars:
|
|
263
|
+
var_list = list(vars)
|
|
264
|
+
var_list.sort(key=lambda var: var.name)
|
|
265
|
+
if len(inner_tasks) == 1 and isinstance(inner_tasks[0], ir.Logical):
|
|
266
|
+
body = f.exists(var_list, inner_tasks[0])
|
|
267
|
+
else:
|
|
268
|
+
body = f.exists(var_list, f.logical(inner_tasks))
|
|
269
|
+
# If the logical is describing an aggregate/rank, confine the existential to
|
|
270
|
+
# the aggregate/rank's body, by wrapping it in another logical.
|
|
271
|
+
if agg_or_rank_tasks:
|
|
272
|
+
body = f.logical([body, *agg_or_rank_tasks])
|
|
273
|
+
return f.logical([body, *effect_tasks], node.hoisted)
|
|
274
|
+
|
|
275
|
+
return node if self._eq_tasks(node.body, new_body) else f.logical(new_body, node.hoisted)
|
|
276
|
+
|
|
277
|
+
def handle_not(self, node: ir.Not, parent: ir.Node, ctx:Optional[Any]=None) -> ir.Not:
|
|
278
|
+
new_task = self.walk(node.task)
|
|
279
|
+
|
|
280
|
+
if node.id in self.node_quantifies_vars:
|
|
281
|
+
vars = self.node_quantifies_vars[node.id]
|
|
282
|
+
return f.not_(f.exists(list(vars), new_task))
|
|
283
|
+
|
|
284
|
+
return node if node.task is new_task else f.not_(new_task)
|
|
285
|
+
|
|
286
|
+
# To avoid unnecessary cloning of vars in the visitor.
|
|
287
|
+
def handle_var(self, node: ir.Var, parent: ir.Node, ctx:Optional[Any]=None) -> ir.Var:
|
|
288
|
+
return node
|
|
289
|
+
|
|
290
|
+
def _eq_tasks(self, xs: Tuple[ir.Task, ...], ys: Tuple[ir.Task, ...]) -> bool:
|
|
291
|
+
if len(xs) != len(ys):
|
|
292
|
+
return False
|
|
293
|
+
for x, y in zip(xs, ys):
|
|
294
|
+
if x is not y:
|
|
295
|
+
return False
|
|
296
|
+
return True
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Sequence as PySequence, cast
|
|
4
|
+
|
|
5
|
+
from relationalai.semantics.metamodel import ir, compiler as c, factory as f, util
|
|
6
|
+
from relationalai.semantics.metamodel.helpers import collect_implicit_vars
|
|
7
|
+
|
|
8
|
+
class Splinter(c.Pass):
|
|
9
|
+
"""
|
|
10
|
+
Splits multi-headed rules into multiple rules. Additionally, infers missing Exists tasks.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
super().__init__()
|
|
15
|
+
self.name_cache = util.NameCache(start_from_one=True)
|
|
16
|
+
|
|
17
|
+
def rewrite(self, model: ir.Model, options:dict={}) -> ir.Model:
|
|
18
|
+
if isinstance(model.root, ir.Logical):
|
|
19
|
+
final = []
|
|
20
|
+
new_relations:list[ir.Relation] = []
|
|
21
|
+
new_relations.extend(model.relations)
|
|
22
|
+
for child in model.root.body:
|
|
23
|
+
new_logicals, relation = self.split(cast(ir.Logical, child))
|
|
24
|
+
final.extend(new_logicals)
|
|
25
|
+
if relation:
|
|
26
|
+
new_relations.append(relation)
|
|
27
|
+
return ir.Model(
|
|
28
|
+
model.engines,
|
|
29
|
+
util.FrozenOrderedSet.from_iterable(new_relations),
|
|
30
|
+
model.types,
|
|
31
|
+
ir.Logical(
|
|
32
|
+
model.root.engine,
|
|
33
|
+
model.root.hoisted,
|
|
34
|
+
tuple(final)
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
return model
|
|
38
|
+
|
|
39
|
+
def split(self, node: ir.Logical) -> tuple[list[ir.Logical], Optional[ir.Relation]]:
|
|
40
|
+
# Split this logical, which represents a rule, into potentially many logicals, one
|
|
41
|
+
# for each head (update or output)
|
|
42
|
+
effects, body = self.split_items(node.body)
|
|
43
|
+
|
|
44
|
+
if len(effects) > 1:
|
|
45
|
+
effects_vars = collect_implicit_vars(*effects)
|
|
46
|
+
final:list[ir.Logical] = []
|
|
47
|
+
connection = None
|
|
48
|
+
if body:
|
|
49
|
+
# if the node has a body, create a connection, derive the body into the
|
|
50
|
+
# connection, and then lookup this connection on the other logicals
|
|
51
|
+
name = self.name_cache.get_name(node.id, "_intermediate")
|
|
52
|
+
connection = f.relation(name, [f.field(f"f_{i+1}", v.type) for i, v in enumerate(effects_vars)])
|
|
53
|
+
final.append(f.logical([*body, f.derive(connection, list(effects_vars))]))
|
|
54
|
+
|
|
55
|
+
for effect in effects:
|
|
56
|
+
if connection:
|
|
57
|
+
# there's a connection, create a logical that looks up from the connection
|
|
58
|
+
# and derives into the effect
|
|
59
|
+
lookup = f.lookup(connection, effects_vars.get_list())
|
|
60
|
+
final.append(f.logical([lookup, effect]))
|
|
61
|
+
else:
|
|
62
|
+
# if there's no connection, the effect is self contained (probably literals)
|
|
63
|
+
final.append(f.logical([effect]))
|
|
64
|
+
return final, connection
|
|
65
|
+
return [node], None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def split_items(self, items: PySequence[ir.Task]) -> tuple[list[ir.Task], list[ir.Task]]:
|
|
69
|
+
effects = []
|
|
70
|
+
body = []
|
|
71
|
+
for item in items:
|
|
72
|
+
if isinstance(item, (ir.Update, ir.Output)):
|
|
73
|
+
effects.append(item)
|
|
74
|
+
else:
|
|
75
|
+
body.append(item)
|
|
76
|
+
return effects, body
|