relationalai 0.13.0__py3-none-any.whl → 0.13.0.dev0__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.
- relationalai/__init__.py +1 -256
- relationalai/config/__init__.py +56 -0
- relationalai/config/config.py +289 -0
- relationalai/config/config_fields.py +86 -0
- relationalai/config/connections/__init__.py +46 -0
- relationalai/config/connections/base.py +23 -0
- relationalai/config/connections/duckdb.py +29 -0
- relationalai/config/connections/snowflake.py +243 -0
- relationalai/config/external/__init__.py +17 -0
- relationalai/config/external/dbt_converter.py +101 -0
- relationalai/config/external/dbt_models.py +93 -0
- relationalai/config/external/snowflake_converter.py +41 -0
- relationalai/config/external/snowflake_models.py +85 -0
- relationalai/config/external/utils.py +19 -0
- relationalai/semantics/__init__.py +146 -22
- relationalai/semantics/backends/lqp/annotations.py +11 -0
- relationalai/semantics/backends/sql/sql_compiler.py +327 -0
- relationalai/semantics/frontend/base.py +1707 -0
- relationalai/semantics/frontend/core.py +179 -0
- relationalai/semantics/frontend/front_compiler.py +1313 -0
- relationalai/semantics/frontend/pprint.py +408 -0
- relationalai/semantics/metamodel/__init__.py +6 -40
- relationalai/semantics/metamodel/builtins.py +205 -771
- relationalai/semantics/metamodel/metamodel.py +437 -0
- relationalai/semantics/metamodel/metamodel_analyzer.py +519 -0
- relationalai/semantics/metamodel/pprint.py +412 -0
- relationalai/semantics/metamodel/rewriter.py +266 -0
- relationalai/semantics/metamodel/typer.py +1378 -0
- relationalai/semantics/std/__init__.py +60 -40
- relationalai/semantics/std/aggregates.py +149 -0
- relationalai/semantics/std/common.py +44 -0
- relationalai/semantics/std/constraints.py +37 -43
- relationalai/semantics/std/datetime.py +246 -135
- relationalai/semantics/std/decimals.py +45 -52
- relationalai/semantics/std/floats.py +13 -5
- relationalai/semantics/std/integers.py +26 -11
- relationalai/semantics/std/math.py +183 -112
- relationalai/semantics/std/numbers.py +86 -0
- relationalai/semantics/std/re.py +80 -62
- relationalai/semantics/std/strings.py +117 -60
- relationalai/shims/executor.py +147 -0
- relationalai/shims/helpers.py +126 -0
- relationalai/shims/hoister.py +221 -0
- relationalai/shims/mm2v0.py +1290 -0
- relationalai/tools/cli/__init__.py +6 -0
- relationalai/tools/cli/cli.py +90 -0
- relationalai/tools/cli/components/__init__.py +5 -0
- relationalai/tools/cli/components/progress_reader.py +1524 -0
- relationalai/tools/cli/components/utils.py +58 -0
- relationalai/tools/cli/config_template.py +45 -0
- relationalai/tools/cli/dev.py +19 -0
- relationalai/tools/debugger.py +289 -183
- relationalai/tools/typer_debugger.py +93 -0
- relationalai/util/dataclasses.py +43 -0
- relationalai/util/docutils.py +40 -0
- relationalai/util/error.py +199 -0
- relationalai/util/format.py +48 -106
- relationalai/util/naming.py +145 -0
- relationalai/util/python.py +35 -0
- relationalai/util/runtime.py +156 -0
- relationalai/util/schema.py +197 -0
- relationalai/util/source.py +185 -0
- relationalai/util/structures.py +163 -0
- relationalai/util/tracing.py +261 -0
- relationalai-0.13.0.dev0.dist-info/METADATA +46 -0
- relationalai-0.13.0.dev0.dist-info/RECORD +488 -0
- relationalai-0.13.0.dev0.dist-info/WHEEL +5 -0
- relationalai-0.13.0.dev0.dist-info/entry_points.txt +3 -0
- relationalai-0.13.0.dev0.dist-info/top_level.txt +2 -0
- v0/relationalai/__init__.py +216 -0
- v0/relationalai/clients/__init__.py +5 -0
- v0/relationalai/clients/azure.py +477 -0
- v0/relationalai/clients/client.py +912 -0
- v0/relationalai/clients/config.py +673 -0
- v0/relationalai/clients/direct_access_client.py +118 -0
- v0/relationalai/clients/hash_util.py +31 -0
- v0/relationalai/clients/local.py +571 -0
- v0/relationalai/clients/profile_polling.py +73 -0
- v0/relationalai/clients/result_helpers.py +420 -0
- v0/relationalai/clients/snowflake.py +3869 -0
- v0/relationalai/clients/types.py +113 -0
- v0/relationalai/clients/use_index_poller.py +980 -0
- v0/relationalai/clients/util.py +356 -0
- v0/relationalai/debugging.py +389 -0
- v0/relationalai/dsl.py +1749 -0
- v0/relationalai/early_access/builder/__init__.py +30 -0
- v0/relationalai/early_access/builder/builder/__init__.py +35 -0
- v0/relationalai/early_access/builder/snowflake/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/__init__.py +25 -0
- v0/relationalai/early_access/builder/std/decimals/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/integers/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/math/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/strings/__init__.py +14 -0
- v0/relationalai/early_access/devtools/__init__.py +12 -0
- v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
- v0/relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
- v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
- v0/relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
- v0/relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
- v0/relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
- v0/relationalai/early_access/dsl/bindings/common.py +402 -0
- v0/relationalai/early_access/dsl/bindings/csv.py +170 -0
- v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
- v0/relationalai/early_access/dsl/bindings/snowflake.py +64 -0
- v0/relationalai/early_access/dsl/codegen/binder.py +411 -0
- v0/relationalai/early_access/dsl/codegen/common.py +79 -0
- v0/relationalai/early_access/dsl/codegen/helpers.py +23 -0
- v0/relationalai/early_access/dsl/codegen/relations.py +700 -0
- v0/relationalai/early_access/dsl/codegen/weaver.py +417 -0
- v0/relationalai/early_access/dsl/core/builders/__init__.py +47 -0
- v0/relationalai/early_access/dsl/core/builders/logic.py +19 -0
- v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
- v0/relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
- v0/relationalai/early_access/dsl/core/context.py +13 -0
- v0/relationalai/early_access/dsl/core/cset.py +132 -0
- v0/relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
- v0/relationalai/early_access/dsl/core/exprs/relational.py +18 -0
- v0/relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
- v0/relationalai/early_access/dsl/core/instances.py +44 -0
- v0/relationalai/early_access/dsl/core/logic/__init__.py +193 -0
- v0/relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
- v0/relationalai/early_access/dsl/core/logic/exists.py +223 -0
- v0/relationalai/early_access/dsl/core/logic/helper.py +163 -0
- v0/relationalai/early_access/dsl/core/namespaces.py +32 -0
- v0/relationalai/early_access/dsl/core/relations.py +276 -0
- v0/relationalai/early_access/dsl/core/rules.py +112 -0
- v0/relationalai/early_access/dsl/core/std/__init__.py +45 -0
- v0/relationalai/early_access/dsl/core/temporal/recall.py +6 -0
- v0/relationalai/early_access/dsl/core/types/__init__.py +270 -0
- v0/relationalai/early_access/dsl/core/types/concepts.py +128 -0
- v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
- v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
- v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
- v0/relationalai/early_access/dsl/core/types/standard.py +92 -0
- v0/relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
- v0/relationalai/early_access/dsl/core/types/variables.py +203 -0
- v0/relationalai/early_access/dsl/ir/compiler.py +318 -0
- v0/relationalai/early_access/dsl/ir/executor.py +260 -0
- v0/relationalai/early_access/dsl/ontologies/constraints.py +88 -0
- v0/relationalai/early_access/dsl/ontologies/export.py +30 -0
- v0/relationalai/early_access/dsl/ontologies/models.py +453 -0
- v0/relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
- v0/relationalai/early_access/dsl/ontologies/readings.py +60 -0
- v0/relationalai/early_access/dsl/ontologies/relationships.py +322 -0
- v0/relationalai/early_access/dsl/ontologies/roles.py +87 -0
- v0/relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
- v0/relationalai/early_access/dsl/orm/constraints.py +438 -0
- v0/relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
- v0/relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
- v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
- v0/relationalai/early_access/dsl/orm/measures/measures.py +299 -0
- v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
- v0/relationalai/early_access/dsl/orm/models.py +256 -0
- v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
- v0/relationalai/early_access/dsl/orm/printer.py +469 -0
- v0/relationalai/early_access/dsl/orm/reasoners.py +480 -0
- v0/relationalai/early_access/dsl/orm/relations.py +19 -0
- v0/relationalai/early_access/dsl/orm/relationships.py +251 -0
- v0/relationalai/early_access/dsl/orm/types.py +42 -0
- v0/relationalai/early_access/dsl/orm/utils.py +79 -0
- v0/relationalai/early_access/dsl/orm/verb.py +204 -0
- v0/relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
- v0/relationalai/early_access/dsl/relations.py +170 -0
- v0/relationalai/early_access/dsl/rulesets.py +69 -0
- v0/relationalai/early_access/dsl/schemas/__init__.py +450 -0
- v0/relationalai/early_access/dsl/schemas/builder.py +48 -0
- v0/relationalai/early_access/dsl/schemas/comp_names.py +51 -0
- v0/relationalai/early_access/dsl/schemas/components.py +203 -0
- v0/relationalai/early_access/dsl/schemas/contexts.py +156 -0
- v0/relationalai/early_access/dsl/schemas/exprs.py +89 -0
- v0/relationalai/early_access/dsl/schemas/fragments.py +464 -0
- v0/relationalai/early_access/dsl/serialization.py +79 -0
- v0/relationalai/early_access/dsl/serialize/exporter.py +163 -0
- v0/relationalai/early_access/dsl/snow/api.py +104 -0
- v0/relationalai/early_access/dsl/snow/common.py +76 -0
- v0/relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
- v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
- v0/relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
- v0/relationalai/early_access/dsl/types/__init__.py +40 -0
- v0/relationalai/early_access/dsl/types/concepts.py +12 -0
- v0/relationalai/early_access/dsl/types/entities.py +135 -0
- v0/relationalai/early_access/dsl/types/values.py +17 -0
- v0/relationalai/early_access/dsl/utils.py +102 -0
- v0/relationalai/early_access/graphs/__init__.py +13 -0
- v0/relationalai/early_access/lqp/__init__.py +12 -0
- v0/relationalai/early_access/lqp/compiler/__init__.py +12 -0
- v0/relationalai/early_access/lqp/constructors/__init__.py +18 -0
- v0/relationalai/early_access/lqp/executor/__init__.py +12 -0
- v0/relationalai/early_access/lqp/ir/__init__.py +12 -0
- v0/relationalai/early_access/lqp/passes/__init__.py +12 -0
- v0/relationalai/early_access/lqp/pragmas/__init__.py +12 -0
- v0/relationalai/early_access/lqp/primitives/__init__.py +12 -0
- v0/relationalai/early_access/lqp/types/__init__.py +12 -0
- v0/relationalai/early_access/lqp/utils/__init__.py +12 -0
- v0/relationalai/early_access/lqp/validators/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/__init__.py +58 -0
- v0/relationalai/early_access/metamodel/builtins/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/compiler/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/dependency/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/factory/__init__.py +17 -0
- v0/relationalai/early_access/metamodel/helpers/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/ir/__init__.py +14 -0
- v0/relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/metamodel/typer/__init__.py +3 -0
- v0/relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/types/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/util/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/visitor/__init__.py +12 -0
- v0/relationalai/early_access/rel/__init__.py +12 -0
- v0/relationalai/early_access/rel/executor/__init__.py +12 -0
- v0/relationalai/early_access/rel/rel_utils/__init__.py +12 -0
- v0/relationalai/early_access/rel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/solvers/__init__.py +19 -0
- v0/relationalai/early_access/sql/__init__.py +11 -0
- v0/relationalai/early_access/sql/executor/__init__.py +3 -0
- v0/relationalai/early_access/sql/rewrite/__init__.py +3 -0
- v0/relationalai/early_access/tests/logging/__init__.py +12 -0
- v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
- v0/relationalai/early_access/tests/utils/__init__.py +12 -0
- v0/relationalai/environments/__init__.py +35 -0
- v0/relationalai/environments/base.py +381 -0
- v0/relationalai/environments/colab.py +14 -0
- v0/relationalai/environments/generic.py +71 -0
- v0/relationalai/environments/ipython.py +68 -0
- v0/relationalai/environments/jupyter.py +9 -0
- v0/relationalai/environments/snowbook.py +169 -0
- v0/relationalai/errors.py +2455 -0
- v0/relationalai/experimental/SF.py +38 -0
- v0/relationalai/experimental/inspect.py +47 -0
- v0/relationalai/experimental/pathfinder/__init__.py +158 -0
- v0/relationalai/experimental/pathfinder/api.py +160 -0
- v0/relationalai/experimental/pathfinder/automaton.py +584 -0
- v0/relationalai/experimental/pathfinder/bridge.py +226 -0
- v0/relationalai/experimental/pathfinder/compiler.py +416 -0
- v0/relationalai/experimental/pathfinder/datalog.py +214 -0
- v0/relationalai/experimental/pathfinder/diagnostics.py +56 -0
- v0/relationalai/experimental/pathfinder/filter.py +236 -0
- v0/relationalai/experimental/pathfinder/glushkov.py +439 -0
- v0/relationalai/experimental/pathfinder/options.py +265 -0
- v0/relationalai/experimental/pathfinder/rpq.py +344 -0
- v0/relationalai/experimental/pathfinder/transition.py +200 -0
- v0/relationalai/experimental/pathfinder/utils.py +26 -0
- v0/relationalai/experimental/paths/api.py +143 -0
- v0/relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
- v0/relationalai/experimental/paths/examples/basic_example.py +40 -0
- v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
- v0/relationalai/experimental/paths/examples/movie_example.py +77 -0
- v0/relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
- v0/relationalai/experimental/paths/examples/paths_example.py +116 -0
- v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
- v0/relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
- v0/relationalai/experimental/paths/graph.py +185 -0
- v0/relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
- v0/relationalai/experimental/paths/path_algorithms/single.py +59 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
- v0/relationalai/experimental/paths/path_algorithms/usp.py +150 -0
- v0/relationalai/experimental/paths/product_graph.py +93 -0
- v0/relationalai/experimental/paths/rpq/automaton.py +584 -0
- v0/relationalai/experimental/paths/rpq/diagnostics.py +56 -0
- v0/relationalai/experimental/paths/rpq/rpq.py +378 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
- v0/relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
- v0/relationalai/experimental/paths/tree_agg.py +168 -0
- v0/relationalai/experimental/paths/utilities/iterators.py +27 -0
- v0/relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
- v0/relationalai/experimental/solvers.py +1087 -0
- v0/relationalai/loaders/__init__.py +0 -0
- v0/relationalai/loaders/csv.py +195 -0
- v0/relationalai/loaders/loader.py +177 -0
- v0/relationalai/loaders/types.py +23 -0
- v0/relationalai/rel_emitter.py +373 -0
- v0/relationalai/rel_utils.py +185 -0
- v0/relationalai/semantics/__init__.py +29 -0
- v0/relationalai/semantics/devtools/benchmark_lqp.py +536 -0
- v0/relationalai/semantics/devtools/compilation_manager.py +294 -0
- v0/relationalai/semantics/devtools/extract_lqp.py +110 -0
- v0/relationalai/semantics/internal/internal.py +3785 -0
- v0/relationalai/semantics/internal/snowflake.py +324 -0
- v0/relationalai/semantics/lqp/builtins.py +16 -0
- v0/relationalai/semantics/lqp/compiler.py +22 -0
- v0/relationalai/semantics/lqp/constructors.py +68 -0
- v0/relationalai/semantics/lqp/executor.py +469 -0
- v0/relationalai/semantics/lqp/intrinsics.py +24 -0
- v0/relationalai/semantics/lqp/model2lqp.py +839 -0
- v0/relationalai/semantics/lqp/passes.py +680 -0
- v0/relationalai/semantics/lqp/primitives.py +252 -0
- v0/relationalai/semantics/lqp/result_helpers.py +202 -0
- v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
- v0/relationalai/semantics/lqp/rewrite/cdc.py +216 -0
- v0/relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +449 -0
- v0/relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
- v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
- v0/relationalai/semantics/lqp/rewrite/splinter.py +76 -0
- v0/relationalai/semantics/lqp/types.py +101 -0
- v0/relationalai/semantics/lqp/utils.py +160 -0
- v0/relationalai/semantics/lqp/validators.py +57 -0
- v0/relationalai/semantics/metamodel/__init__.py +40 -0
- v0/relationalai/semantics/metamodel/builtins.py +774 -0
- v0/relationalai/semantics/metamodel/compiler.py +133 -0
- v0/relationalai/semantics/metamodel/dependency.py +862 -0
- v0/relationalai/semantics/metamodel/executor.py +61 -0
- v0/relationalai/semantics/metamodel/factory.py +287 -0
- v0/relationalai/semantics/metamodel/helpers.py +361 -0
- v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
- v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +549 -0
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
- v0/relationalai/semantics/metamodel/typer/checker.py +353 -0
- v0/relationalai/semantics/metamodel/typer/typer.py +1395 -0
- v0/relationalai/semantics/metamodel/util.py +505 -0
- v0/relationalai/semantics/reasoners/__init__.py +10 -0
- v0/relationalai/semantics/reasoners/graph/__init__.py +37 -0
- v0/relationalai/semantics/reasoners/graph/core.py +9020 -0
- v0/relationalai/semantics/reasoners/optimization/__init__.py +68 -0
- v0/relationalai/semantics/reasoners/optimization/common.py +88 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +1163 -0
- v0/relationalai/semantics/rel/builtins.py +40 -0
- v0/relationalai/semantics/rel/compiler.py +989 -0
- v0/relationalai/semantics/rel/executor.py +359 -0
- v0/relationalai/semantics/rel/rel.py +482 -0
- v0/relationalai/semantics/rel/rel_utils.py +276 -0
- v0/relationalai/semantics/snowflake/__init__.py +3 -0
- v0/relationalai/semantics/sql/compiler.py +2503 -0
- v0/relationalai/semantics/sql/executor/duck_db.py +52 -0
- v0/relationalai/semantics/sql/executor/result_helpers.py +64 -0
- v0/relationalai/semantics/sql/executor/snowflake.py +145 -0
- v0/relationalai/semantics/sql/rewrite/denormalize.py +222 -0
- v0/relationalai/semantics/sql/rewrite/double_negation.py +49 -0
- v0/relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
- v0/relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
- v0/relationalai/semantics/sql/sql.py +504 -0
- v0/relationalai/semantics/std/__init__.py +54 -0
- v0/relationalai/semantics/std/constraints.py +43 -0
- v0/relationalai/semantics/std/datetime.py +363 -0
- v0/relationalai/semantics/std/decimals.py +62 -0
- v0/relationalai/semantics/std/floats.py +7 -0
- v0/relationalai/semantics/std/integers.py +22 -0
- v0/relationalai/semantics/std/math.py +141 -0
- v0/relationalai/semantics/std/pragmas.py +11 -0
- v0/relationalai/semantics/std/re.py +83 -0
- v0/relationalai/semantics/std/std.py +14 -0
- v0/relationalai/semantics/std/strings.py +63 -0
- v0/relationalai/semantics/tests/__init__.py +0 -0
- v0/relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
- v0/relationalai/semantics/tests/test_snapshot_base.py +9 -0
- v0/relationalai/semantics/tests/utils.py +46 -0
- v0/relationalai/std/__init__.py +70 -0
- v0/relationalai/tools/__init__.py +0 -0
- v0/relationalai/tools/cli.py +1940 -0
- v0/relationalai/tools/cli_controls.py +1826 -0
- v0/relationalai/tools/cli_helpers.py +390 -0
- v0/relationalai/tools/debugger.py +183 -0
- v0/relationalai/tools/debugger_client.py +109 -0
- v0/relationalai/tools/debugger_server.py +302 -0
- v0/relationalai/tools/dev.py +685 -0
- v0/relationalai/tools/qb_debugger.py +425 -0
- v0/relationalai/util/clean_up_databases.py +95 -0
- v0/relationalai/util/format.py +123 -0
- v0/relationalai/util/list_databases.py +9 -0
- v0/relationalai/util/otel_configuration.py +25 -0
- v0/relationalai/util/otel_handler.py +484 -0
- v0/relationalai/util/snowflake_handler.py +88 -0
- v0/relationalai/util/span_format_test.py +43 -0
- v0/relationalai/util/span_tracker.py +207 -0
- v0/relationalai/util/spans_file_handler.py +72 -0
- v0/relationalai/util/tracing_handler.py +34 -0
- frontend/debugger/dist/.gitignore +0 -2
- frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
- frontend/debugger/dist/assets/index-Cssla-O7.js +0 -208
- frontend/debugger/dist/assets/index-DlHsYx1V.css +0 -9
- frontend/debugger/dist/index.html +0 -17
- relationalai/clients/__init__.py +0 -18
- relationalai/clients/client.py +0 -912
- relationalai/clients/config.py +0 -673
- relationalai/clients/direct_access_client.py +0 -118
- relationalai/clients/hash_util.py +0 -31
- relationalai/clients/local.py +0 -571
- relationalai/clients/profile_polling.py +0 -73
- relationalai/clients/resources/__init__.py +0 -8
- relationalai/clients/resources/azure/azure.py +0 -477
- relationalai/clients/resources/snowflake/__init__.py +0 -20
- relationalai/clients/resources/snowflake/cli_resources.py +0 -87
- relationalai/clients/resources/snowflake/direct_access_resources.py +0 -711
- relationalai/clients/resources/snowflake/engine_state_handlers.py +0 -309
- relationalai/clients/resources/snowflake/error_handlers.py +0 -199
- relationalai/clients/resources/snowflake/export_procedure.py.jinja +0 -249
- relationalai/clients/resources/snowflake/resources_factory.py +0 -99
- relationalai/clients/resources/snowflake/snowflake.py +0 -3083
- relationalai/clients/resources/snowflake/use_index_poller.py +0 -1011
- relationalai/clients/resources/snowflake/use_index_resources.py +0 -188
- relationalai/clients/resources/snowflake/util.py +0 -387
- relationalai/clients/result_helpers.py +0 -420
- relationalai/clients/types.py +0 -113
- relationalai/clients/util.py +0 -356
- relationalai/debugging.py +0 -389
- relationalai/dsl.py +0 -1749
- relationalai/early_access/builder/__init__.py +0 -30
- relationalai/early_access/builder/builder/__init__.py +0 -35
- relationalai/early_access/builder/snowflake/__init__.py +0 -12
- relationalai/early_access/builder/std/__init__.py +0 -25
- relationalai/early_access/builder/std/decimals/__init__.py +0 -12
- relationalai/early_access/builder/std/integers/__init__.py +0 -12
- relationalai/early_access/builder/std/math/__init__.py +0 -12
- relationalai/early_access/builder/std/strings/__init__.py +0 -14
- relationalai/early_access/devtools/__init__.py +0 -12
- relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
- relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
- relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
- relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
- relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
- relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
- relationalai/early_access/dsl/bindings/common.py +0 -402
- relationalai/early_access/dsl/bindings/csv.py +0 -170
- relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
- relationalai/early_access/dsl/bindings/snowflake.py +0 -64
- relationalai/early_access/dsl/codegen/binder.py +0 -411
- relationalai/early_access/dsl/codegen/common.py +0 -79
- relationalai/early_access/dsl/codegen/helpers.py +0 -23
- relationalai/early_access/dsl/codegen/relations.py +0 -700
- relationalai/early_access/dsl/codegen/weaver.py +0 -417
- relationalai/early_access/dsl/core/builders/__init__.py +0 -47
- relationalai/early_access/dsl/core/builders/logic.py +0 -19
- relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
- relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
- relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
- relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
- relationalai/early_access/dsl/core/context.py +0 -13
- relationalai/early_access/dsl/core/cset.py +0 -132
- relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
- relationalai/early_access/dsl/core/exprs/relational.py +0 -18
- relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
- relationalai/early_access/dsl/core/instances.py +0 -44
- relationalai/early_access/dsl/core/logic/__init__.py +0 -193
- relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
- relationalai/early_access/dsl/core/logic/exists.py +0 -223
- relationalai/early_access/dsl/core/logic/helper.py +0 -163
- relationalai/early_access/dsl/core/namespaces.py +0 -32
- relationalai/early_access/dsl/core/relations.py +0 -276
- relationalai/early_access/dsl/core/rules.py +0 -112
- relationalai/early_access/dsl/core/std/__init__.py +0 -45
- relationalai/early_access/dsl/core/temporal/recall.py +0 -6
- relationalai/early_access/dsl/core/types/__init__.py +0 -270
- relationalai/early_access/dsl/core/types/concepts.py +0 -128
- relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
- relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
- relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
- relationalai/early_access/dsl/core/types/standard.py +0 -92
- relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
- relationalai/early_access/dsl/core/types/variables.py +0 -203
- relationalai/early_access/dsl/ir/compiler.py +0 -318
- relationalai/early_access/dsl/ir/executor.py +0 -260
- relationalai/early_access/dsl/ontologies/constraints.py +0 -88
- relationalai/early_access/dsl/ontologies/export.py +0 -30
- relationalai/early_access/dsl/ontologies/models.py +0 -453
- relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
- relationalai/early_access/dsl/ontologies/readings.py +0 -60
- relationalai/early_access/dsl/ontologies/relationships.py +0 -322
- relationalai/early_access/dsl/ontologies/roles.py +0 -87
- relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
- relationalai/early_access/dsl/orm/constraints.py +0 -438
- relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
- relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
- relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
- relationalai/early_access/dsl/orm/measures/measures.py +0 -299
- relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
- relationalai/early_access/dsl/orm/models.py +0 -256
- relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
- relationalai/early_access/dsl/orm/printer.py +0 -469
- relationalai/early_access/dsl/orm/reasoners.py +0 -480
- relationalai/early_access/dsl/orm/relations.py +0 -19
- relationalai/early_access/dsl/orm/relationships.py +0 -251
- relationalai/early_access/dsl/orm/types.py +0 -42
- relationalai/early_access/dsl/orm/utils.py +0 -79
- relationalai/early_access/dsl/orm/verb.py +0 -204
- relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
- relationalai/early_access/dsl/relations.py +0 -170
- relationalai/early_access/dsl/rulesets.py +0 -69
- relationalai/early_access/dsl/schemas/__init__.py +0 -450
- relationalai/early_access/dsl/schemas/builder.py +0 -48
- relationalai/early_access/dsl/schemas/comp_names.py +0 -51
- relationalai/early_access/dsl/schemas/components.py +0 -203
- relationalai/early_access/dsl/schemas/contexts.py +0 -156
- relationalai/early_access/dsl/schemas/exprs.py +0 -89
- relationalai/early_access/dsl/schemas/fragments.py +0 -464
- relationalai/early_access/dsl/serialization.py +0 -79
- relationalai/early_access/dsl/serialize/exporter.py +0 -163
- relationalai/early_access/dsl/snow/api.py +0 -105
- relationalai/early_access/dsl/snow/common.py +0 -76
- relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
- relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
- relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
- relationalai/early_access/dsl/types/__init__.py +0 -40
- relationalai/early_access/dsl/types/concepts.py +0 -12
- relationalai/early_access/dsl/types/entities.py +0 -135
- relationalai/early_access/dsl/types/values.py +0 -17
- relationalai/early_access/dsl/utils.py +0 -102
- relationalai/early_access/graphs/__init__.py +0 -13
- relationalai/early_access/lqp/__init__.py +0 -12
- relationalai/early_access/lqp/compiler/__init__.py +0 -12
- relationalai/early_access/lqp/constructors/__init__.py +0 -18
- relationalai/early_access/lqp/executor/__init__.py +0 -12
- relationalai/early_access/lqp/ir/__init__.py +0 -12
- relationalai/early_access/lqp/passes/__init__.py +0 -12
- relationalai/early_access/lqp/pragmas/__init__.py +0 -12
- relationalai/early_access/lqp/primitives/__init__.py +0 -12
- relationalai/early_access/lqp/types/__init__.py +0 -12
- relationalai/early_access/lqp/utils/__init__.py +0 -12
- relationalai/early_access/lqp/validators/__init__.py +0 -12
- relationalai/early_access/metamodel/__init__.py +0 -58
- relationalai/early_access/metamodel/builtins/__init__.py +0 -12
- relationalai/early_access/metamodel/compiler/__init__.py +0 -12
- relationalai/early_access/metamodel/dependency/__init__.py +0 -12
- relationalai/early_access/metamodel/factory/__init__.py +0 -17
- relationalai/early_access/metamodel/helpers/__init__.py +0 -12
- relationalai/early_access/metamodel/ir/__init__.py +0 -14
- relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
- relationalai/early_access/metamodel/typer/__init__.py +0 -3
- relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
- relationalai/early_access/metamodel/types/__init__.py +0 -15
- relationalai/early_access/metamodel/util/__init__.py +0 -15
- relationalai/early_access/metamodel/visitor/__init__.py +0 -12
- relationalai/early_access/rel/__init__.py +0 -12
- relationalai/early_access/rel/executor/__init__.py +0 -12
- relationalai/early_access/rel/rel_utils/__init__.py +0 -12
- relationalai/early_access/rel/rewrite/__init__.py +0 -7
- relationalai/early_access/solvers/__init__.py +0 -19
- relationalai/early_access/sql/__init__.py +0 -11
- relationalai/early_access/sql/executor/__init__.py +0 -3
- relationalai/early_access/sql/rewrite/__init__.py +0 -3
- relationalai/early_access/tests/logging/__init__.py +0 -12
- relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
- relationalai/early_access/tests/utils/__init__.py +0 -12
- relationalai/environments/__init__.py +0 -35
- relationalai/environments/base.py +0 -381
- relationalai/environments/colab.py +0 -14
- relationalai/environments/generic.py +0 -71
- relationalai/environments/ipython.py +0 -68
- relationalai/environments/jupyter.py +0 -9
- relationalai/environments/snowbook.py +0 -169
- relationalai/errors.py +0 -2478
- relationalai/experimental/SF.py +0 -38
- relationalai/experimental/inspect.py +0 -47
- relationalai/experimental/pathfinder/__init__.py +0 -158
- relationalai/experimental/pathfinder/api.py +0 -160
- relationalai/experimental/pathfinder/automaton.py +0 -584
- relationalai/experimental/pathfinder/bridge.py +0 -226
- relationalai/experimental/pathfinder/compiler.py +0 -416
- relationalai/experimental/pathfinder/datalog.py +0 -214
- relationalai/experimental/pathfinder/diagnostics.py +0 -56
- relationalai/experimental/pathfinder/filter.py +0 -236
- relationalai/experimental/pathfinder/glushkov.py +0 -439
- relationalai/experimental/pathfinder/options.py +0 -265
- relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +0 -1951
- relationalai/experimental/pathfinder/rpq.py +0 -344
- relationalai/experimental/pathfinder/transition.py +0 -200
- relationalai/experimental/pathfinder/utils.py +0 -26
- relationalai/experimental/paths/README.md +0 -107
- relationalai/experimental/paths/api.py +0 -143
- relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
- relationalai/experimental/paths/code_organization.md +0 -2
- relationalai/experimental/paths/examples/Movies.ipynb +0 -16328
- relationalai/experimental/paths/examples/basic_example.py +0 -40
- relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
- relationalai/experimental/paths/examples/movie_example.py +0 -77
- relationalai/experimental/paths/examples/movies_data/actedin.csv +0 -193
- relationalai/experimental/paths/examples/movies_data/directed.csv +0 -45
- relationalai/experimental/paths/examples/movies_data/follows.csv +0 -7
- relationalai/experimental/paths/examples/movies_data/movies.csv +0 -39
- relationalai/experimental/paths/examples/movies_data/person.csv +0 -134
- relationalai/experimental/paths/examples/movies_data/produced.csv +0 -16
- relationalai/experimental/paths/examples/movies_data/ratings.csv +0 -10
- relationalai/experimental/paths/examples/movies_data/wrote.csv +0 -11
- relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
- relationalai/experimental/paths/examples/paths_example.py +0 -116
- relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
- relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
- relationalai/experimental/paths/graph.py +0 -185
- relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
- relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
- relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
- relationalai/experimental/paths/path_algorithms/single.py +0 -59
- relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
- relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
- relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
- relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
- relationalai/experimental/paths/path_algorithms/usp.py +0 -150
- relationalai/experimental/paths/product_graph.py +0 -93
- relationalai/experimental/paths/rpq/automaton.py +0 -584
- relationalai/experimental/paths/rpq/diagnostics.py +0 -56
- relationalai/experimental/paths/rpq/rpq.py +0 -378
- relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
- relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
- relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
- relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
- relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
- relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
- relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
- relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
- relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
- relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
- relationalai/experimental/paths/tree_agg.py +0 -168
- relationalai/experimental/paths/utilities/iterators.py +0 -27
- relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
- relationalai/experimental/solvers.py +0 -1087
- relationalai/loaders/csv.py +0 -195
- relationalai/loaders/loader.py +0 -177
- relationalai/loaders/types.py +0 -23
- relationalai/rel_emitter.py +0 -373
- relationalai/rel_utils.py +0 -185
- relationalai/semantics/designs/query_builder/identify_by.md +0 -106
- relationalai/semantics/devtools/benchmark_lqp.py +0 -535
- relationalai/semantics/devtools/compilation_manager.py +0 -294
- relationalai/semantics/devtools/extract_lqp.py +0 -110
- relationalai/semantics/internal/internal.py +0 -3785
- relationalai/semantics/internal/snowflake.py +0 -325
- relationalai/semantics/lqp/README.md +0 -34
- relationalai/semantics/lqp/builtins.py +0 -16
- relationalai/semantics/lqp/compiler.py +0 -22
- relationalai/semantics/lqp/constructors.py +0 -68
- relationalai/semantics/lqp/executor.py +0 -469
- relationalai/semantics/lqp/intrinsics.py +0 -24
- relationalai/semantics/lqp/model2lqp.py +0 -877
- relationalai/semantics/lqp/passes.py +0 -680
- relationalai/semantics/lqp/primitives.py +0 -252
- relationalai/semantics/lqp/result_helpers.py +0 -202
- relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -57
- relationalai/semantics/lqp/rewrite/cdc.py +0 -216
- relationalai/semantics/lqp/rewrite/extract_common.py +0 -338
- relationalai/semantics/lqp/rewrite/extract_keys.py +0 -506
- relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
- relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -314
- relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -296
- relationalai/semantics/lqp/rewrite/splinter.py +0 -76
- relationalai/semantics/lqp/types.py +0 -101
- relationalai/semantics/lqp/utils.py +0 -160
- relationalai/semantics/lqp/validators.py +0 -57
- relationalai/semantics/metamodel/compiler.py +0 -133
- relationalai/semantics/metamodel/dependency.py +0 -862
- relationalai/semantics/metamodel/executor.py +0 -61
- relationalai/semantics/metamodel/factory.py +0 -287
- relationalai/semantics/metamodel/helpers.py +0 -361
- relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
- relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -210
- relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
- relationalai/semantics/metamodel/rewrite/flatten.py +0 -554
- relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -165
- relationalai/semantics/metamodel/typer/checker.py +0 -353
- relationalai/semantics/metamodel/typer/typer.py +0 -1395
- relationalai/semantics/metamodel/util.py +0 -506
- relationalai/semantics/reasoners/__init__.py +0 -10
- relationalai/semantics/reasoners/graph/README.md +0 -620
- relationalai/semantics/reasoners/graph/__init__.py +0 -37
- relationalai/semantics/reasoners/graph/core.py +0 -9019
- relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +0 -797
- relationalai/semantics/reasoners/graph/tests/README.md +0 -21
- relationalai/semantics/reasoners/optimization/__init__.py +0 -68
- relationalai/semantics/reasoners/optimization/common.py +0 -88
- relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
- relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1163
- relationalai/semantics/rel/builtins.py +0 -40
- relationalai/semantics/rel/compiler.py +0 -989
- relationalai/semantics/rel/executor.py +0 -362
- relationalai/semantics/rel/rel.py +0 -482
- relationalai/semantics/rel/rel_utils.py +0 -276
- relationalai/semantics/snowflake/__init__.py +0 -3
- relationalai/semantics/sql/compiler.py +0 -2503
- relationalai/semantics/sql/executor/duck_db.py +0 -52
- relationalai/semantics/sql/executor/result_helpers.py +0 -64
- relationalai/semantics/sql/executor/snowflake.py +0 -149
- relationalai/semantics/sql/rewrite/denormalize.py +0 -222
- relationalai/semantics/sql/rewrite/double_negation.py +0 -49
- relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
- relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
- relationalai/semantics/sql/sql.py +0 -504
- relationalai/semantics/std/pragmas.py +0 -11
- relationalai/semantics/std/std.py +0 -14
- relationalai/semantics/tests/test_snapshot_abstract.py +0 -143
- relationalai/semantics/tests/test_snapshot_base.py +0 -9
- relationalai/semantics/tests/utils.py +0 -46
- relationalai/std/__init__.py +0 -70
- relationalai/tools/cli.py +0 -1936
- relationalai/tools/cli_controls.py +0 -1826
- relationalai/tools/cli_helpers.py +0 -398
- relationalai/tools/debugger_client.py +0 -109
- relationalai/tools/debugger_server.py +0 -302
- relationalai/tools/dev.py +0 -685
- relationalai/tools/notes +0 -7
- relationalai/tools/qb_debugger.py +0 -425
- relationalai/util/clean_up_databases.py +0 -95
- relationalai/util/list_databases.py +0 -9
- relationalai/util/otel_configuration.py +0 -26
- relationalai/util/otel_handler.py +0 -484
- relationalai/util/snowflake_handler.py +0 -88
- relationalai/util/span_format_test.py +0 -43
- relationalai/util/span_tracker.py +0 -207
- relationalai/util/spans_file_handler.py +0 -72
- relationalai/util/tracing_handler.py +0 -34
- relationalai-0.13.0.dist-info/METADATA +0 -74
- relationalai-0.13.0.dist-info/RECORD +0 -458
- relationalai-0.13.0.dist-info/WHEEL +0 -4
- relationalai-0.13.0.dist-info/entry_points.txt +0 -3
- relationalai-0.13.0.dist-info/licenses/LICENSE +0 -202
- relationalai_test_util/__init__.py +0 -4
- relationalai_test_util/fixtures.py +0 -229
- relationalai_test_util/snapshot.py +0 -252
- relationalai_test_util/traceback.py +0 -118
- /relationalai/{analysis → semantics/frontend}/__init__.py +0 -0
- /relationalai/{auth/__init__.py → semantics/metamodel/metamodel_compiler.py} +0 -0
- /relationalai/{early_access → shims}/__init__.py +0 -0
- {relationalai/early_access/dsl/adapters → v0/relationalai/analysis}/__init__.py +0 -0
- {relationalai → v0/relationalai}/analysis/mechanistic.py +0 -0
- {relationalai → v0/relationalai}/analysis/whynot.py +0 -0
- {relationalai/early_access/dsl/adapters/orm → v0/relationalai/auth}/__init__.py +0 -0
- {relationalai → v0/relationalai}/auth/jwt_generator.py +0 -0
- {relationalai → v0/relationalai}/auth/oauth_callback_server.py +0 -0
- {relationalai → v0/relationalai}/auth/token_handler.py +0 -0
- {relationalai → v0/relationalai}/auth/util.py +0 -0
- {relationalai/clients/resources/snowflake → v0/relationalai/clients}/cache_store.py +0 -0
- {relationalai → v0/relationalai}/compiler.py +0 -0
- {relationalai → v0/relationalai}/dependencies.py +0 -0
- {relationalai → v0/relationalai}/docutils.py +0 -0
- {relationalai/early_access/dsl/adapters/owl → v0/relationalai/early_access}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings → v0/relationalai/early_access/dsl/adapters}/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings/legacy → v0/relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
- {relationalai/early_access/dsl/codegen → v0/relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
- {relationalai/early_access/dsl/core/temporal → v0/relationalai/early_access/dsl/bindings}/__init__.py +0 -0
- {relationalai/early_access/dsl/ir → v0/relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
- {relationalai/early_access/dsl/ontologies → v0/relationalai/early_access/dsl/codegen}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/constants.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/stack.py +0 -0
- {relationalai/early_access/dsl/orm → v0/relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/utils.py +0 -0
- {relationalai/early_access/dsl/orm/measures → v0/relationalai/early_access/dsl/ir}/__init__.py +0 -0
- {relationalai/early_access/dsl/physical_metadata → v0/relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
- {relationalai/early_access/dsl/serialize → v0/relationalai/early_access/dsl/orm}/__init__.py +0 -0
- {relationalai/early_access/dsl/snow → v0/relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
- {relationalai/loaders → v0/relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
- {relationalai/semantics/tests → v0/relationalai/early_access/dsl/serialize}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/model.py +0 -0
- {relationalai/tools → v0/relationalai/early_access/dsl/snow}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/tests/__init__.py +0 -0
- {relationalai → v0/relationalai}/environments/ci.py +0 -0
- {relationalai → v0/relationalai}/environments/hex.py +0 -0
- {relationalai → v0/relationalai}/environments/terminal.py +0 -0
- {relationalai → v0/relationalai}/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/graphs.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/filter.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/glushkov.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/transition.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/utilities.py +0 -0
- {relationalai → v0/relationalai}/metagen.py +0 -0
- {relationalai → v0/relationalai}/metamodel.py +0 -0
- {relationalai → v0/relationalai}/rel.py +0 -0
- {relationalai → v0/relationalai}/semantics/devtools/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/annotations.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/ir.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/pragmas.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/dataflow.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/ir.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/typer/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/types.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/visitor.py +0 -0
- {relationalai → v0/relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/rel/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/executor/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/tests/logging.py +0 -0
- {relationalai → v0/relationalai}/std/aggregates.py +0 -0
- {relationalai → v0/relationalai}/std/dates.py +0 -0
- {relationalai → v0/relationalai}/std/graphs.py +0 -0
- {relationalai → v0/relationalai}/std/inspect.py +0 -0
- {relationalai → v0/relationalai}/std/math.py +0 -0
- {relationalai → v0/relationalai}/std/re.py +0 -0
- {relationalai → v0/relationalai}/std/strings.py +0 -0
- {relationalai → v0/relationalai}/tools/cleanup_snapshots.py +0 -0
- {relationalai → v0/relationalai}/tools/constants.py +0 -0
- {relationalai → v0/relationalai}/tools/query_utils.py +0 -0
- {relationalai → v0/relationalai}/tools/snapshot_viewer.py +0 -0
- {relationalai → v0/relationalai}/util/__init__.py +0 -0
- {relationalai → v0/relationalai}/util/constants.py +0 -0
- {relationalai → v0/relationalai}/util/graph.py +0 -0
- {relationalai → v0/relationalai}/util/timeout.py +0 -0
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
from typing import Callable
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
from relationalai.dsl import Type, Symbol, create_vars, create_var, next_id, global_ns
|
|
5
|
-
from relationalai.std import rel
|
|
6
|
-
from relationalai.debugging import logger
|
|
7
|
-
|
|
8
|
-
from relationalai.experimental.pathfinder.rpq import RPQ
|
|
9
|
-
from relationalai.experimental.pathfinder.utils import get_model
|
|
10
|
-
from relationalai.experimental.pathfinder.datalog import install_program
|
|
11
|
-
from relationalai.experimental.pathfinder.compiler import (
|
|
12
|
-
compile_conn, compile_product_graph
|
|
13
|
-
)
|
|
14
|
-
from relationalai.experimental.pathfinder.api import (
|
|
15
|
-
make_config_relation, make_input_relation
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
import importlib.resources as pkg_resources
|
|
19
|
-
|
|
20
|
-
# Dictionary to keep track of models with Pathfinder already installed
|
|
21
|
-
PATHFINDER_INSTALLED = {}
|
|
22
|
-
|
|
23
|
-
# -----------------------------------------------------------------------------------------
|
|
24
|
-
# Installing the Pathfinder source code
|
|
25
|
-
# -----------------------------------------------------------------------------------------
|
|
26
|
-
# Whilst the Package manager is not yet available, the Pathfinder is installed from manually
|
|
27
|
-
# prepared single source file (present in the current directory). Ideally, we want to use a
|
|
28
|
-
# single version but for comparative benchmarking and potential bug fixes we ensure that
|
|
29
|
-
# multiple versions can be installed and used.
|
|
30
|
-
# ----------------------------------------------------------------------------------------
|
|
31
|
-
def ensure_pathfinder_installed(model, options) -> str:
|
|
32
|
-
|
|
33
|
-
pathfinder_lib_version = options['pathfinder_lib_version']
|
|
34
|
-
|
|
35
|
-
key = (model.name, pathfinder_lib_version)
|
|
36
|
-
|
|
37
|
-
if not PATHFINDER_INSTALLED.get(key, False):
|
|
38
|
-
source = get_pathfinder_source_code(pathfinder_lib_version)
|
|
39
|
-
|
|
40
|
-
logger.info(f'Installing Pathfinder source version {pathfinder_lib_version}')
|
|
41
|
-
|
|
42
|
-
module_name = f"pathfinder_v{pathfinder_lib_version.replace('.', '_')}"
|
|
43
|
-
|
|
44
|
-
# replace `pathfinder` with versioned module name in Rel source:
|
|
45
|
-
import re
|
|
46
|
-
source = re.sub(r'\bpathfinder\b', module_name, source)
|
|
47
|
-
|
|
48
|
-
model.install_raw(source, name=module_name, overwrite=True)
|
|
49
|
-
PATHFINDER_INSTALLED[key] = module_name
|
|
50
|
-
|
|
51
|
-
return PATHFINDER_INSTALLED[key]
|
|
52
|
-
|
|
53
|
-
def get_pathfinder_source_code(version):
|
|
54
|
-
try:
|
|
55
|
-
resource_name = f"pathfinder-v{version}.rel"
|
|
56
|
-
with pkg_resources.open_text('relationalai.experimental.pathfinder', resource_name) as file:
|
|
57
|
-
return file.read()
|
|
58
|
-
except FileNotFoundError:
|
|
59
|
-
raise Exception("Pathfinder source file not found.")
|
|
60
|
-
|
|
61
|
-
# -----------------------------------------------------------------------------------------
|
|
62
|
-
# Pathfinder invocation
|
|
63
|
-
# -----------------------------------------------------------------------------------------
|
|
64
|
-
# The invocation of pathfinder consists of installing the logic and calling the appropriate
|
|
65
|
-
# method of the `pathfinder` module. The invocation is parameterized by various input
|
|
66
|
-
# options.
|
|
67
|
-
# -----------------------------------------------------------------------------------------
|
|
68
|
-
# The main entry point for invoking the pathfinder i.e., installing the logic for
|
|
69
|
-
# constructing the paths (if not does already). Returns the dedicated Path type containing
|
|
70
|
-
# all paths matching the input compiled pattern, as controlled by the options.
|
|
71
|
-
# ----------------------------------------------------------------------------------------
|
|
72
|
-
def invoke_pathfinder(pattern: RPQ, options):
|
|
73
|
-
logger.info("Invoking pathfinder with options:")
|
|
74
|
-
for option in options:
|
|
75
|
-
logger.info(f" * {option}: {options[option]}")
|
|
76
|
-
|
|
77
|
-
model = get_model(options)
|
|
78
|
-
# make sure pathfinder is installed
|
|
79
|
-
pathfinder_module = ensure_pathfinder_installed(model, options)
|
|
80
|
-
pathfinder = getattr(global_ns, pathfinder_module)
|
|
81
|
-
|
|
82
|
-
# use a unique identifier for all compiled types and relations
|
|
83
|
-
pq_id = next_id()
|
|
84
|
-
# source and target relations
|
|
85
|
-
source_rel = f"pq_source_{pq_id}"
|
|
86
|
-
source = getattr(rel, source_rel)
|
|
87
|
-
target_rel = f"pq_target_{pq_id}"
|
|
88
|
-
target = getattr(rel, target_rel)
|
|
89
|
-
|
|
90
|
-
# use the connectivity relation to find the source or target nodes unless specified
|
|
91
|
-
conn = None
|
|
92
|
-
if options['source'] is None or options['target'] is None:
|
|
93
|
-
conn_program = compile_conn(pattern, options)
|
|
94
|
-
conn_rel = conn_program.root_rel['conn_rel']
|
|
95
|
-
# connectivity relation
|
|
96
|
-
conn = getattr(rel, conn_rel)
|
|
97
|
-
# installing connectivity pattern rules
|
|
98
|
-
install_program(model, conn_program, {**options, 'suppress_groundedness_test': True})
|
|
99
|
-
|
|
100
|
-
define_endpoint_relations(source, target, model, conn, options)
|
|
101
|
-
|
|
102
|
-
pg_program = compile_product_graph(pattern, source_rel, target_rel, options)
|
|
103
|
-
pg_graph_rel = pg_program.root_rel['pg_graph_rel']
|
|
104
|
-
pg_source_rel = pg_program.root_rel['pg_source_rel']
|
|
105
|
-
pg_target_rel = pg_program.root_rel['pg_target_rel']
|
|
106
|
-
edge_label_map = pg_program.edge_label_map
|
|
107
|
-
pg_graph = getattr(rel, pg_graph_rel)
|
|
108
|
-
pg_source = getattr(rel, pg_source_rel)
|
|
109
|
-
pg_target = getattr(rel, pg_target_rel)
|
|
110
|
-
install_program(model, pg_program, options)
|
|
111
|
-
|
|
112
|
-
# output types
|
|
113
|
-
Path = model.Type(f"Path{pq_id}")
|
|
114
|
-
PathPosition = model.Type(f"PathPosition{pq_id}")
|
|
115
|
-
PathEdge = model.Type(f"PathEdge{pq_id}")
|
|
116
|
-
PathEdgeLabelMap = model.Type(f"PathEdgeLabelMap{pq_id}")
|
|
117
|
-
|
|
118
|
-
# creating edge label map
|
|
119
|
-
define_edge_label_mapping(model, edge_label_map, PathEdgeLabelMap, options)
|
|
120
|
-
|
|
121
|
-
input_relation = make_input_relation(model, pg_graph, pg_source, pg_target)
|
|
122
|
-
config_relation = make_config_relation(model, options)
|
|
123
|
-
with model.rule(dynamic=True):
|
|
124
|
-
path_id, kind, index, value = create_vars(4)
|
|
125
|
-
pathfinder.find_paths(
|
|
126
|
-
input_relation,
|
|
127
|
-
config_relation,
|
|
128
|
-
path_id,
|
|
129
|
-
kind,
|
|
130
|
-
index,
|
|
131
|
-
value
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
path = Path.add(path_id=path_id)
|
|
135
|
-
|
|
136
|
-
map_path_positions(PathPosition, path, kind, index, value)
|
|
137
|
-
|
|
138
|
-
map_edge_labels(PathEdgeLabelMap, PathEdge, path, edge_label_map, kind, index, value)
|
|
139
|
-
|
|
140
|
-
connect_edge_positions(model, Path, PathEdge, PathPosition)
|
|
141
|
-
|
|
142
|
-
return Path()
|
|
143
|
-
|
|
144
|
-
def map_path_positions(PathPosition, path, kind, index, value):
|
|
145
|
-
with kind == Symbol("node"):
|
|
146
|
-
pos = PathPosition.add(path=path, index=index)
|
|
147
|
-
pos.set(node=value)
|
|
148
|
-
path.position.add(pos)
|
|
149
|
-
|
|
150
|
-
def map_edge_labels(PathEdgeLabelMap, PathEdge, path, edge_label_map, kind, index, value):
|
|
151
|
-
if len(edge_label_map) != 0:
|
|
152
|
-
with kind == Symbol("edge_label"):
|
|
153
|
-
lab = PathEdgeLabelMap(pq_edge_label=value)
|
|
154
|
-
edge = PathEdge.add(path=path, index=index)
|
|
155
|
-
edge.set(label=lab.label, direction=lab.direction, property=lab.property)
|
|
156
|
-
path.edge.add(edge)
|
|
157
|
-
|
|
158
|
-
def connect_edge_positions(model, Path, PathEdge, PathPosition):
|
|
159
|
-
with model.rule():
|
|
160
|
-
path = Path()
|
|
161
|
-
e = PathEdge(path=path)
|
|
162
|
-
from_pos = PathPosition(path=path, index=e.index-1)
|
|
163
|
-
to_pos = PathPosition(path=path, index=e.index)
|
|
164
|
-
e.set(from_node=from_pos.node, to_node=to_pos.node)
|
|
165
|
-
|
|
166
|
-
def define_endpoint_relations(source, target, model, conn, options):
|
|
167
|
-
if options['source'] is None and options['target'] is None:
|
|
168
|
-
assert conn is not None
|
|
169
|
-
with model.rule():
|
|
170
|
-
x, y = create_vars(2)
|
|
171
|
-
conn(x, y)
|
|
172
|
-
source.add(x)
|
|
173
|
-
target.add(y)
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
assert options['source'] is not None or options['target'] is not None
|
|
177
|
-
|
|
178
|
-
if options['source'] is not None:
|
|
179
|
-
define_relation_from_spec(source, options['source'], model)
|
|
180
|
-
|
|
181
|
-
if options['target'] is not None:
|
|
182
|
-
define_relation_from_spec(target, options['target'], model)
|
|
183
|
-
|
|
184
|
-
if options['source'] is None:
|
|
185
|
-
define_relation_with_conn(source, 'backward', conn, target, model)
|
|
186
|
-
|
|
187
|
-
if options['target'] is None:
|
|
188
|
-
define_relation_with_conn(target, 'forward', conn, source, model)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def define_relation_from_spec(relation, relation_spec, model):
|
|
192
|
-
if isinstance(relation_spec, Type):
|
|
193
|
-
with model.rule():
|
|
194
|
-
x = relation_spec()
|
|
195
|
-
relation.add(x)
|
|
196
|
-
else:
|
|
197
|
-
assert isinstance(relation_spec, Callable)
|
|
198
|
-
with model.rule():
|
|
199
|
-
x = create_var()
|
|
200
|
-
relation_spec(x)
|
|
201
|
-
relation.add(x)
|
|
202
|
-
|
|
203
|
-
def define_relation_with_conn(relation, direction, conn, opposite_relation, model):
|
|
204
|
-
assert conn is not None
|
|
205
|
-
|
|
206
|
-
with model.rule(dynamic=True):
|
|
207
|
-
x, y = create_vars(2)
|
|
208
|
-
conn(x, y)
|
|
209
|
-
if direction == 'forward':
|
|
210
|
-
opposite_relation(x)
|
|
211
|
-
relation.add(y)
|
|
212
|
-
else:
|
|
213
|
-
opposite_relation(y)
|
|
214
|
-
relation.add(x)
|
|
215
|
-
|
|
216
|
-
def define_edge_label_mapping(model, edge_label_map, PathEdgeLabelMap, options):
|
|
217
|
-
if len(edge_label_map) == 0:
|
|
218
|
-
return
|
|
219
|
-
with model.rule(dynamic=True):
|
|
220
|
-
for pq_edge_label in edge_label_map:
|
|
221
|
-
edge_label = edge_label_map[pq_edge_label]
|
|
222
|
-
label = str(edge_label)
|
|
223
|
-
property = edge_label.label
|
|
224
|
-
direction = edge_label.direction
|
|
225
|
-
label_map = PathEdgeLabelMap.add(pq_edge_label=pq_edge_label)
|
|
226
|
-
label_map.set(label=label, direction=direction, property=property)
|
|
@@ -1,416 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from abc import ABC
|
|
3
|
-
from typing import Dict, List, Iterable
|
|
4
|
-
|
|
5
|
-
from relationalai.debugging import logger
|
|
6
|
-
from relationalai.dsl import next_id
|
|
7
|
-
|
|
8
|
-
from relationalai.experimental.pathfinder.options import DEFAULT_OPTIONS
|
|
9
|
-
from relationalai.experimental.pathfinder.rpq import RPQ
|
|
10
|
-
from relationalai.experimental.pathfinder.filter import (
|
|
11
|
-
NodeFilter, NodeLabel, EdgeLabel, AnonymousNodeFilter
|
|
12
|
-
)
|
|
13
|
-
from relationalai.experimental.pathfinder.automaton import prepare_automaton
|
|
14
|
-
from relationalai.experimental.pathfinder.transition import EdgeTransition, NodeTransition
|
|
15
|
-
|
|
16
|
-
from relationalai.experimental.pathfinder.datalog import (
|
|
17
|
-
ConstantEqualityAtom, Rule, RelAtom, AnonymousFilterAtom,
|
|
18
|
-
VariableEqualityAtom, Atom, DatalogProgram
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
# =========================================================================================
|
|
22
|
-
# Compiling a pattern into Rel programs
|
|
23
|
-
# =========================================================================================
|
|
24
|
-
#
|
|
25
|
-
# We compile a RPQ pattern into two kinds of programs:
|
|
26
|
-
# 1. A program that computes the connectivity relation of the input automaton.
|
|
27
|
-
# 2. A program that computes the product graph of the input automaton and a knowledge graph.
|
|
28
|
-
#
|
|
29
|
-
# We illustrate the compilation process on the following example pattern:
|
|
30
|
-
# -----------------------------------------------------------------------------------------
|
|
31
|
-
# Running example
|
|
32
|
-
# -----------------------------------------------------------------------------------------
|
|
33
|
-
# An example of the program generation is presented on the pattern below.
|
|
34
|
-
#
|
|
35
|
-
# path(Odd, star('-[A]->', Even)) | path('<-[B]-', N)
|
|
36
|
-
#
|
|
37
|
-
# which is parsed into the following RPQ
|
|
38
|
-
#
|
|
39
|
-
# ╷ Union
|
|
40
|
-
# ├──┐ Concat
|
|
41
|
-
# │ ├──╴ Node(Odd)
|
|
42
|
-
# │ └──┐ Star
|
|
43
|
-
# │ └──┐ Concat
|
|
44
|
-
# │ ├──╴ Edge(-[A]→) [pos=1]
|
|
45
|
-
# │ └──╴ Node(Even)
|
|
46
|
-
# └──┐ Concat
|
|
47
|
-
# ├──╴ Edge(←[B]-) [pos=2]
|
|
48
|
-
# └──╴ Node(N)
|
|
49
|
-
#
|
|
50
|
-
# The RPQ is compiled into the following automaton (with transitions explicitly labeled):
|
|
51
|
-
# * states: 0 1 2
|
|
52
|
-
# * init: 0
|
|
53
|
-
# * delta:
|
|
54
|
-
# - 0
|
|
55
|
-
# → 1
|
|
56
|
-
# ⊨(Odd)=[-[A]→]=()⇒ (t1)
|
|
57
|
-
# → 2
|
|
58
|
-
# ⊨()=[←[B]-]=()⇒ (t2)
|
|
59
|
-
# - 1
|
|
60
|
-
# → 1
|
|
61
|
-
# ⊨(Even)=[-[A]→]=()⇒ (t3)
|
|
62
|
-
# * final:
|
|
63
|
-
# - 0
|
|
64
|
-
# ⊨(Odd)⇒ (f1)
|
|
65
|
-
# - 1
|
|
66
|
-
# ⊨(Even)⇒ (f2)
|
|
67
|
-
# - 2
|
|
68
|
-
# ⊨(N)⇒ (f3)
|
|
69
|
-
#
|
|
70
|
-
# =========================================================================================
|
|
71
|
-
# 1. Connectivity Program
|
|
72
|
-
# =========================================================================================
|
|
73
|
-
# The Rel connectivity program defines a binary relation `pq_conn(x, y)` that selects the
|
|
74
|
-
# nodes `y` reachable from `x` with the automaton having an accepting run. The program has
|
|
75
|
-
# two independent uses:
|
|
76
|
-
# 1. When the RPQ is meant to be evaluated as a connectivity query, the program is used to
|
|
77
|
-
# evaluate the query.
|
|
78
|
-
# 2. When the RPQ is meant to produce paths but the user does not specify the source or
|
|
79
|
-
# target nodes to be used during evaluation.
|
|
80
|
-
#
|
|
81
|
-
# The program consists of binary predicates `pq_conn_from_q(x, y)` that selects the nodes
|
|
82
|
-
# `y` reachable from `x` with the automaton having a run from state `q` to an accepting
|
|
83
|
-
# state. Note that when the automaton has cycles, the program may be recursive. To make sure
|
|
84
|
-
# that each introduced predicate is grounded we may "contract" the final node transitions of
|
|
85
|
-
# an accepting state `q` with every incoming transition of `q` (note that the final node
|
|
86
|
-
# transitions may be ungrounded). As a consequence, an accepting state `q` that does not
|
|
87
|
-
# have any outgoing transitions, called an _exit state_, does not need its own dedicated
|
|
88
|
-
# `pq_conn_fom_q` predicate. At this time, we decorate every predicate with `@no_inline`
|
|
89
|
-
# attribute to prevent any inlining. Diligent inlining may be beneficial for performance but
|
|
90
|
-
# is left for future work.
|
|
91
|
-
#
|
|
92
|
-
# -----------------------------------------------------------------------------------------
|
|
93
|
-
# In the running example, the state 2 is an exit state. Also note that the initial state is
|
|
94
|
-
# also a final state, thus the automaton accepts empty paths (consisting of a single node
|
|
95
|
-
# with type OddNode). The compiled Rel program follows. (All relations have `@no_inline`
|
|
96
|
-
# attribute that we omit here for brevity)
|
|
97
|
-
#
|
|
98
|
-
# // The main connectivity predicate
|
|
99
|
-
# def pq_conn(x0, x1): pq_conn_from_0(x0, x1)
|
|
100
|
-
#
|
|
101
|
-
# // Accepting empty paths with node transition f1
|
|
102
|
-
# def pq_conn(x0, x1): x0 = x1 ∧ Odd(x0)
|
|
103
|
-
#
|
|
104
|
-
# // Paths from state 0 going through t1 to state 1
|
|
105
|
-
# def pq_conn_from_0(x0, x2): A(x0, x1) ∧ Odd(x0) ∧ pq_conn_from_1(x1, x2)
|
|
106
|
-
#
|
|
107
|
-
# // Paths from state 0 through t1 (to state 1) and terminating with f2
|
|
108
|
-
# def pq_conn_from_0(x0, x1): A(x0, x1) ∧ Odd(x0) ∧ Even(x1)
|
|
109
|
-
#
|
|
110
|
-
# // Paths from state 0 through t2 (to state 1) and terminating with f3
|
|
111
|
-
# def pq_conn_from_0(x0, x1): A(x0, x1) ∧ Even(x0) ∧ Even(x1)
|
|
112
|
-
#
|
|
113
|
-
# // Paths from state 1 through t3 to state 1
|
|
114
|
-
# def pq_conn_from_1(x0, x2): A(x0, x1) ∧ Even(x0) ∧ pq_conn_from_1(x1, x2)
|
|
115
|
-
#
|
|
116
|
-
# // Paths from state 1 through t3 and terminating with f2
|
|
117
|
-
# def pq_conn_from_1(x0, x1): A(x0, x1) ∧ Even(x0) ∧ Even(x1)
|
|
118
|
-
#
|
|
119
|
-
# =========================================================================================
|
|
120
|
-
# 2. Product Graph Program
|
|
121
|
-
# =========================================================================================
|
|
122
|
-
# The Product Graph program defines a relation `pg_graph` of arity 5 that defines the set of
|
|
123
|
-
# edges in the product graph: `pg_graph(q, p, a, n, m)` holds iff the product graph has an
|
|
124
|
-
# edge from `(q, n)` to `(p, m)` and the hash value of the edge label is `a`. The program
|
|
125
|
-
# also defines two unary relations `pg_source(n, q)` and `pg_target(n, q)` that define the
|
|
126
|
-
# source and target nodes of the product graph. The computation of the product graph is
|
|
127
|
-
# based on the input finite automaton corresponding to the RPQ and additionally two
|
|
128
|
-
# relations `source` and `target` with the sets of source and target nodes of the knowledge
|
|
129
|
-
# graph.
|
|
130
|
-
#
|
|
131
|
-
# The program is used to compute the product graph of the automaton and a knowledge graph.
|
|
132
|
-
# The program is used when the user specifies the source and target nodes to be used during
|
|
133
|
-
# evaluation.
|
|
134
|
-
#
|
|
135
|
-
# -----------------------------------------------------------------------------------------
|
|
136
|
-
# In the running example, the compiled Rel program follows
|
|
137
|
-
#
|
|
138
|
-
# // Source nodes of the product graph
|
|
139
|
-
# def pg_source(x0, x1): source(x0) x1 = 0
|
|
140
|
-
#
|
|
141
|
-
# // Target nodes of the product graph
|
|
142
|
-
# def pg_target(x0, x1): target(x0) ∧ x1 = 0 ∧ Odd(x0)
|
|
143
|
-
# def pg_target(x0, x1): target(x0) ∧ x1 = 1 ∧ Even(x0)
|
|
144
|
-
# def pg_target(x0, x1): target(x0) ∧ x1 = 2 ∧ N(x0)
|
|
145
|
-
#
|
|
146
|
-
# // Edges of the product graph
|
|
147
|
-
# def pg_graph(x0, x1, x2, x3, x4): x0 = 0 ∧ x1 = 1 ∧ x2 = hash(-[A]→) ∧ A(x3, x4) ∧ Odd(x3)
|
|
148
|
-
# def pg_graph(x0, x1, x2, x3, x4): x0 = 0 ∧ x1 = 2 ∧ x2 = hash(←[B]-) ∧ B(x4, x3)
|
|
149
|
-
# def pg_graph(x0, x1, x2, x3, x4): x0 = 1 ∧ x1 = 1 ∧ x2 = hash(-[A]→) ∧ A(x3, x4) ∧ Even(x3)
|
|
150
|
-
#
|
|
151
|
-
# =========================================================================================
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
class RPQCompiler(ABC):
|
|
155
|
-
def __init__(self, pattern: RPQ, options):
|
|
156
|
-
self.a = prepare_automaton(pattern, options)
|
|
157
|
-
|
|
158
|
-
self.prog_id = next_id()
|
|
159
|
-
|
|
160
|
-
self.rules: List[Rule] = []
|
|
161
|
-
self.rel_attrs: Dict[str, List[str]] = dict()
|
|
162
|
-
|
|
163
|
-
def yield_node_filters_atoms(self, filters: Iterable[NodeFilter], x: int):
|
|
164
|
-
for f in filters:
|
|
165
|
-
if isinstance(f, NodeLabel):
|
|
166
|
-
yield RelAtom(f.label, (x,))
|
|
167
|
-
elif isinstance(f, AnonymousNodeFilter):
|
|
168
|
-
yield AnonymousFilterAtom(f._unary_function, (x,))
|
|
169
|
-
|
|
170
|
-
def yield_edge_transition_atoms(self, t, x, y):
|
|
171
|
-
edge_label = t.get_label()
|
|
172
|
-
if edge_label.direction == 'forward':
|
|
173
|
-
yield RelAtom(edge_label.label, (x, y))
|
|
174
|
-
else:
|
|
175
|
-
yield RelAtom(edge_label.label, (y, x))
|
|
176
|
-
|
|
177
|
-
if t.has_anon_edge_filters():
|
|
178
|
-
for f in t.get_anon_edge_filters():
|
|
179
|
-
yield AnonymousFilterAtom(f.binary_function, (x, y))
|
|
180
|
-
|
|
181
|
-
if t.has_src_filters():
|
|
182
|
-
yield from self.yield_node_filters_atoms(t.src_filters, x)
|
|
183
|
-
|
|
184
|
-
if t.has_trg_filters():
|
|
185
|
-
yield from self.yield_node_filters_atoms(t.trg_filters, y)
|
|
186
|
-
|
|
187
|
-
def add_rule(self, head: RelAtom, body: List[Atom], n=None):
|
|
188
|
-
if n is None:
|
|
189
|
-
var_refs = set(head.vars).union([v for a in body for v in a.vars])
|
|
190
|
-
n = len(var_refs)
|
|
191
|
-
self.rules.append(Rule(head, n, body))
|
|
192
|
-
logger.info(f"Added rule: {self.rules[-1]}")
|
|
193
|
-
|
|
194
|
-
# Prepares (decorates) relations and gathers their definitions.
|
|
195
|
-
class ConnCompiler(RPQCompiler):
|
|
196
|
-
def __init__(self, pattern: RPQ, options):
|
|
197
|
-
super().__init__(pattern, options)
|
|
198
|
-
|
|
199
|
-
self.edge_transition_id = dict()
|
|
200
|
-
self.final_transition_id = dict()
|
|
201
|
-
|
|
202
|
-
self.rules: List[Rule] = []
|
|
203
|
-
self.rel_attrs: Dict[str, List[str]] = dict()
|
|
204
|
-
|
|
205
|
-
# self.main_conn_rel is the name of the binary connectivity relation `pq_conn` such
|
|
206
|
-
# that `pq_conn(x, y)` holds iff there is a path from x to y with the automaton
|
|
207
|
-
# having an accepting run (from an initial state to a final state).
|
|
208
|
-
self.main_conn_rel = f'pq_{self.prog_id}_conn'
|
|
209
|
-
|
|
210
|
-
# maps state q to the name of a binary connectivity relation `pg_conn_from_q` such
|
|
211
|
-
# that `pg_conn_from_q(x, y)` holds iff there is a path from x to y with the
|
|
212
|
-
# automaton having an accepting run when starting in state q.
|
|
213
|
-
self.conn_rel: Dict[int, str] = dict()
|
|
214
|
-
|
|
215
|
-
logger.debug("Initializing PyRel Connectivity Predicate emitter")
|
|
216
|
-
logger.debug(self.a)
|
|
217
|
-
|
|
218
|
-
self.prepare_relations()
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
# -------------------------------------------------------------------------------------
|
|
222
|
-
# Prepare relations for states, transitions, and final states with necessary decorators
|
|
223
|
-
# -------------------------------------------------------------------------------------
|
|
224
|
-
def prepare_relations(self):
|
|
225
|
-
self.rel_attrs[self.main_conn_rel] = ['@track', '@no_inline']
|
|
226
|
-
|
|
227
|
-
for q in self.a.states:
|
|
228
|
-
self.prepare_state_conn_relation(q)
|
|
229
|
-
|
|
230
|
-
def prepare_state_conn_relation(self, q):
|
|
231
|
-
if self.a.is_exit(q):
|
|
232
|
-
# the state does not outgoing edge-transitions but only ungrounded final node
|
|
233
|
-
# transitions: we will not create an ungrounded connectivity relation for it
|
|
234
|
-
# but instead we will always contract it with the preceding transition.
|
|
235
|
-
return
|
|
236
|
-
|
|
237
|
-
self.conn_rel[q] = f'pq_{self.prog_id}_conn_from_{q}'
|
|
238
|
-
self.rel_attrs[self.conn_rel[q]] = ['@no_inline']
|
|
239
|
-
|
|
240
|
-
# -------------------------------------------------------------------------------------
|
|
241
|
-
# Create rules from the automaton
|
|
242
|
-
# -------------------------------------------------------------------------------------
|
|
243
|
-
def make_rules(self):
|
|
244
|
-
self.make_main_conn_rule()
|
|
245
|
-
|
|
246
|
-
for q in self.a.delta:
|
|
247
|
-
for p in self.a.delta[q]:
|
|
248
|
-
for t in self.a.delta[q][p]:
|
|
249
|
-
self.make_edge_rules(q, p, t)
|
|
250
|
-
|
|
251
|
-
def make_main_conn_rule(self):
|
|
252
|
-
q_0 = self.a.get_initial_state()
|
|
253
|
-
if not self.a.is_exit(q_0):
|
|
254
|
-
init_conn_rel = self.conn_rel[q_0]
|
|
255
|
-
self.add_rule(
|
|
256
|
-
head = RelAtom(self.main_conn_rel, (0, 1)),
|
|
257
|
-
body = [RelAtom(init_conn_rel, (0, 1))]
|
|
258
|
-
)
|
|
259
|
-
if q_0 in self.a.final:
|
|
260
|
-
for e in self.a.final[q_0]:
|
|
261
|
-
self.add_rule(
|
|
262
|
-
head = RelAtom(self.main_conn_rel, (0, 1)),
|
|
263
|
-
body = [
|
|
264
|
-
VariableEqualityAtom((0, 1)),
|
|
265
|
-
*self.yield_node_filters_atoms(e.filters, 0)
|
|
266
|
-
]
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
def make_edge_rules(self, q, p, t: EdgeTransition):
|
|
270
|
-
if not self.a.is_exit(p):
|
|
271
|
-
self.make_transition_rule(q, p, t)
|
|
272
|
-
|
|
273
|
-
if p in self.a.final:
|
|
274
|
-
for e in self.a.final[p]:
|
|
275
|
-
self.make_transition_final_rule(q, t, e)
|
|
276
|
-
|
|
277
|
-
def make_transition_rule(self, q, p, t: EdgeTransition):
|
|
278
|
-
assert not self.a.is_exit(p)
|
|
279
|
-
|
|
280
|
-
conn_q_rel = self.conn_rel[q]
|
|
281
|
-
conn_p_rel = self.conn_rel[p]
|
|
282
|
-
|
|
283
|
-
self.add_rule(
|
|
284
|
-
head = RelAtom(conn_q_rel, (0, 2)),
|
|
285
|
-
body = [
|
|
286
|
-
*self.yield_edge_transition_atoms(t, 0, 1),
|
|
287
|
-
RelAtom(conn_p_rel, (1, 2))
|
|
288
|
-
]
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
def make_transition_final_rule(self, q, t: EdgeTransition, e: NodeTransition):
|
|
292
|
-
conn_q_rel = self.conn_rel[q]
|
|
293
|
-
|
|
294
|
-
self.add_rule(
|
|
295
|
-
head = RelAtom(conn_q_rel, (0, 1)),
|
|
296
|
-
body = [
|
|
297
|
-
*self.yield_edge_transition_atoms(t, 0, 1),
|
|
298
|
-
*self.yield_node_filters_atoms(e._filters, 1)
|
|
299
|
-
]
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
def compile_conn(pattern, options=DEFAULT_OPTIONS) -> DatalogProgram:
|
|
303
|
-
compiler = ConnCompiler(pattern, options)
|
|
304
|
-
compiler.make_rules()
|
|
305
|
-
|
|
306
|
-
program = DatalogProgram(
|
|
307
|
-
root_rel = {'conn_rel': compiler.main_conn_rel},
|
|
308
|
-
rel_attrs = compiler.rel_attrs,
|
|
309
|
-
rules = compiler.rules,
|
|
310
|
-
edge_label_map = None
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
return program
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
class ProductGraphCompiler(RPQCompiler):
|
|
317
|
-
def __init__(self, pattern: RPQ, source_rel: str, target_rel: str, options):
|
|
318
|
-
super().__init__(pattern, options)
|
|
319
|
-
|
|
320
|
-
self.source_rel = source_rel
|
|
321
|
-
self.target_rel = target_rel
|
|
322
|
-
|
|
323
|
-
# The name of the relation with the edges in the product graph of the knowledge
|
|
324
|
-
# graph and the input automaton. The relation has arity `5` and contains a tuple
|
|
325
|
-
# `(q, p, a, n, m)` iff the product graph has an edge from `(q, n)` to `(p, m)` and
|
|
326
|
-
# the hash value of the edge label is `a`.
|
|
327
|
-
self.pg_graph_rel = f'pg_{self.prog_id}_graph'
|
|
328
|
-
|
|
329
|
-
# The relation names of the source and target nodes of the product graph; arity 2,
|
|
330
|
-
# each contains pairs `(n, q)`, where `n` is the node of the knowledge graph and `q`
|
|
331
|
-
# is a state of the automaton.
|
|
332
|
-
self.pg_source_rel = f'pg_{self.prog_id}_source'
|
|
333
|
-
self.pg_target_rel = f'pg_{self.prog_id}_target'
|
|
334
|
-
|
|
335
|
-
self.rel_attrs[self.pg_graph_rel] = ['@pipeline']
|
|
336
|
-
self.rel_attrs[self.pg_source_rel] = ['@pipeline']
|
|
337
|
-
self.rel_attrs[self.pg_target_rel] = ['@pipeline']
|
|
338
|
-
|
|
339
|
-
# maps hashes of edge labels to edge labels
|
|
340
|
-
self.pg_edge_label_map: Dict[int, EdgeLabel] = {
|
|
341
|
-
hash(lab): lab for lab in self.a.alphabet
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
logger.info("Initializing PyRel Product Graph emitter")
|
|
345
|
-
logger.info(self.a)
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
# -------------------------------------------------------------------------------------
|
|
349
|
-
# Prepare definitions of the 3 main relations
|
|
350
|
-
# -------------------------------------------------------------------------------------
|
|
351
|
-
|
|
352
|
-
def make_rules(self):
|
|
353
|
-
self.make_pg_source_rules()
|
|
354
|
-
self.make_pg_graph_rules()
|
|
355
|
-
self.make_pg_target_rules()
|
|
356
|
-
|
|
357
|
-
def make_pg_source_rules(self):
|
|
358
|
-
for q in self.a.init:
|
|
359
|
-
# pg_source(n, x) ← source_rel(n) ∧ x = q
|
|
360
|
-
self.add_rule(
|
|
361
|
-
head = RelAtom(self.pg_source_rel, (0, 1)),
|
|
362
|
-
body = [
|
|
363
|
-
RelAtom(self.source_rel, (0,)),
|
|
364
|
-
ConstantEqualityAtom((1, q))
|
|
365
|
-
]
|
|
366
|
-
)
|
|
367
|
-
|
|
368
|
-
def make_pg_target_rules(self):
|
|
369
|
-
for q in self.a.final:
|
|
370
|
-
for e in self.a.final[q]:
|
|
371
|
-
# pg_target(n, x) ← target_rel(n) ∧ x = q ∧ e(n)
|
|
372
|
-
self.add_rule(
|
|
373
|
-
head = RelAtom(self.pg_target_rel, (0, 1)),
|
|
374
|
-
body = [
|
|
375
|
-
RelAtom(self.target_rel, (0,)),
|
|
376
|
-
ConstantEqualityAtom((1, q)),
|
|
377
|
-
*self.yield_node_filters_atoms(e.filters, 0)
|
|
378
|
-
]
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
def make_pg_graph_rules(self):
|
|
382
|
-
for q in self.a.delta:
|
|
383
|
-
for p in self.a.delta[q]:
|
|
384
|
-
for t in self.a.delta[q][p]:
|
|
385
|
-
# pg_edge(x, y, a, n, m) ← q = x ∧ p = y ∧ a = #label(t) ∧ t(n, m)
|
|
386
|
-
self.add_rule(
|
|
387
|
-
head = RelAtom(self.pg_graph_rel, (0, 1, 2, 3, 4)),
|
|
388
|
-
body = [
|
|
389
|
-
ConstantEqualityAtom((0, q)),
|
|
390
|
-
ConstantEqualityAtom((1, p)),
|
|
391
|
-
ConstantEqualityAtom((2, hash(t.get_label()))),
|
|
392
|
-
*self.yield_edge_transition_atoms(t, 3, 4)
|
|
393
|
-
]
|
|
394
|
-
)
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
def compile_product_graph(pattern: RPQ, source_rel: str, target_rel: str, options=DEFAULT_OPTIONS) -> DatalogProgram:
|
|
398
|
-
compiler = ProductGraphCompiler(pattern, source_rel, target_rel, options)
|
|
399
|
-
compiler.make_rules()
|
|
400
|
-
|
|
401
|
-
logger.info('Mapping edge labels:')
|
|
402
|
-
for pq_edge_label in compiler.pg_edge_label_map:
|
|
403
|
-
logger.info(f" * {pq_edge_label} is {compiler.pg_edge_label_map[pq_edge_label]}")
|
|
404
|
-
|
|
405
|
-
program = DatalogProgram(
|
|
406
|
-
root_rel = {
|
|
407
|
-
'pg_graph_rel': compiler.pg_graph_rel,
|
|
408
|
-
'pg_source_rel': compiler.pg_source_rel,
|
|
409
|
-
'pg_target_rel': compiler.pg_target_rel
|
|
410
|
-
},
|
|
411
|
-
rel_attrs = compiler.rel_attrs,
|
|
412
|
-
rules = compiler.rules,
|
|
413
|
-
edge_label_map = compiler.pg_edge_label_map
|
|
414
|
-
)
|
|
415
|
-
|
|
416
|
-
return program
|