relationalai 0.13.5__py3-none-any.whl → 1.0.0a1__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/config/shims.py +1 -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 +1716 -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 -772
- 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 +1186 -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 +101 -46
- relationalai/shims/executor.py +161 -0
- relationalai/shims/helpers.py +126 -0
- relationalai/shims/hoister.py +221 -0
- relationalai/shims/mm2v0.py +1324 -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 -109
- 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-1.0.0a1.dist-info/METADATA +44 -0
- relationalai-1.0.0a1.dist-info/RECORD +489 -0
- relationalai-1.0.0a1.dist-info/WHEEL +5 -0
- relationalai-1.0.0a1.dist-info/entry_points.txt +3 -0
- relationalai-1.0.0a1.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/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/ir.py +124 -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/__init__.py +18 -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/ir.py +923 -0
- v0/relationalai/semantics/metamodel/rewrite/__init__.py +7 -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/metamodel/visitor.py +944 -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 -946
- relationalai/clients/config.py +0 -673
- relationalai/clients/direct_access_client.py +0 -118
- relationalai/clients/exec_txn_poller.py +0 -153
- relationalai/clients/hash_util.py +0 -31
- relationalai/clients/local.py +0 -594
- relationalai/clients/profile_polling.py +0 -73
- relationalai/clients/resources/__init__.py +0 -8
- relationalai/clients/resources/azure/azure.py +0 -502
- relationalai/clients/resources/snowflake/__init__.py +0 -20
- relationalai/clients/resources/snowflake/cli_resources.py +0 -98
- relationalai/clients/resources/snowflake/direct_access_resources.py +0 -739
- relationalai/clients/resources/snowflake/engine_service.py +0 -381
- relationalai/clients/resources/snowflake/engine_state_handlers.py +0 -315
- relationalai/clients/resources/snowflake/error_handlers.py +0 -240
- 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 -3193
- relationalai/clients/resources/snowflake/use_index_poller.py +0 -1019
- 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 -118
- 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 -2496
- 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 -1095
- 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 -329
- relationalai/semantics/lqp/README.md +0 -34
- relationalai/semantics/lqp/algorithms.py +0 -173
- relationalai/semantics/lqp/builtins.py +0 -213
- relationalai/semantics/lqp/compiler.py +0 -22
- relationalai/semantics/lqp/constructors.py +0 -68
- relationalai/semantics/lqp/executor.py +0 -518
- relationalai/semantics/lqp/export_rewriter.py +0 -40
- relationalai/semantics/lqp/intrinsics.py +0 -24
- relationalai/semantics/lqp/ir.py +0 -150
- relationalai/semantics/lqp/model2lqp.py +0 -1056
- relationalai/semantics/lqp/passes.py +0 -38
- relationalai/semantics/lqp/primitives.py +0 -252
- relationalai/semantics/lqp/result_helpers.py +0 -266
- relationalai/semantics/lqp/rewrite/__init__.py +0 -32
- relationalai/semantics/lqp/rewrite/algorithm.py +0 -385
- relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -69
- relationalai/semantics/lqp/rewrite/cdc.py +0 -216
- relationalai/semantics/lqp/rewrite/constants_to_vars.py +0 -70
- relationalai/semantics/lqp/rewrite/deduplicate_vars.py +0 -104
- relationalai/semantics/lqp/rewrite/eliminate_data.py +0 -108
- relationalai/semantics/lqp/rewrite/extract_common.py +0 -340
- relationalai/semantics/lqp/rewrite/extract_keys.py +0 -577
- relationalai/semantics/lqp/rewrite/flatten_script.py +0 -301
- relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
- relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -348
- relationalai/semantics/lqp/rewrite/period_math.py +0 -77
- relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -339
- relationalai/semantics/lqp/rewrite/splinter.py +0 -76
- relationalai/semantics/lqp/rewrite/unify_definitions.py +0 -323
- relationalai/semantics/lqp/types.py +0 -101
- relationalai/semantics/lqp/utils.py +0 -170
- relationalai/semantics/lqp/validators.py +0 -70
- relationalai/semantics/metamodel/compiler.py +0 -134
- relationalai/semantics/metamodel/dependency.py +0 -880
- relationalai/semantics/metamodel/executor.py +0 -78
- relationalai/semantics/metamodel/factory.py +0 -287
- relationalai/semantics/metamodel/helpers.py +0 -368
- relationalai/semantics/metamodel/ir.py +0 -924
- relationalai/semantics/metamodel/rewrite/__init__.py +0 -8
- relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
- relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -220
- relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
- relationalai/semantics/metamodel/rewrite/flatten.py +0 -590
- relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -256
- relationalai/semantics/metamodel/rewrite/handle_aggregations_and_ranks.py +0 -237
- relationalai/semantics/metamodel/typer/checker.py +0 -355
- relationalai/semantics/metamodel/typer/typer.py +0 -1396
- relationalai/semantics/metamodel/util.py +0 -506
- relationalai/semantics/metamodel/visitor.py +0 -945
- 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 -1407
- relationalai/semantics/rel/builtins.py +0 -40
- relationalai/semantics/rel/compiler.py +0 -994
- relationalai/semantics/rel/executor.py +0 -363
- 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/lqp/algorithms.py +0 -345
- relationalai/semantics/tests/test_snapshot_abstract.py +0 -144
- 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 -2089
- relationalai/tools/cli_controls.py +0 -1975
- relationalai/tools/cli_helpers.py +0 -802
- 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/tools/txn_progress.py +0 -188
- 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.5.dist-info/METADATA +0 -74
- relationalai-0.13.5.dist-info/RECORD +0 -473
- relationalai-0.13.5.dist-info/WHEEL +0 -4
- relationalai-0.13.5.dist-info/entry_points.txt +0 -3
- relationalai-0.13.5.dist-info/licenses/LICENSE +0 -202
- relationalai_test_util/__init__.py +0 -4
- relationalai_test_util/fixtures.py +0 -233
- 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/semantics/tests/lqp → 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/tools → v0/relationalai/loaders}/__init__.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/pragmas.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/dataflow.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/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,1095 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
import time
|
|
3
|
-
from typing import Any, List, Optional, cast
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
import textwrap
|
|
6
|
-
from .. import dsl, std
|
|
7
|
-
from ..std import rel
|
|
8
|
-
from ..metamodel import Builtins
|
|
9
|
-
from ..tools.cli_controls import Spinner
|
|
10
|
-
from ..tools.constants import DEFAULT_QUERY_TIMEOUT_MINS
|
|
11
|
-
from .. import debugging
|
|
12
|
-
from .. errors import ResponseStatusException
|
|
13
|
-
import uuid
|
|
14
|
-
import relationalai
|
|
15
|
-
import json
|
|
16
|
-
from ..clients.util import poll_with_specified_overhead
|
|
17
|
-
from ..clients.resources.snowflake import Resources as SnowflakeResources, APP_NAME
|
|
18
|
-
from ..clients.resources.snowflake import DirectAccessResources
|
|
19
|
-
from ..clients.direct_access_client import DirectAccessClient
|
|
20
|
-
from ..util.timeout import calc_remaining_timeout_minutes
|
|
21
|
-
|
|
22
|
-
rel_sv = rel._tagged(Builtins.SingleValued)
|
|
23
|
-
|
|
24
|
-
ENGINE_TYPE_SOLVER = "SOLVER"
|
|
25
|
-
# TODO (dba) The ERP still uses `worker` instead of `engine`. Change
|
|
26
|
-
# this once we fix this in the ERP.
|
|
27
|
-
WORKER_ERRORS = ["worker is suspended", "create/resume", "worker not found", "no workers found", "worker was deleted"]
|
|
28
|
-
ENGINE_ERRORS = ["engine is suspended", "create/resume", "engine not found", "no engines found", "engine was deleted"]
|
|
29
|
-
ENGINE_NOT_READY_MSGS = ["worker is in pending", "worker is provisioning", "worker is not ready to accept jobs"]
|
|
30
|
-
|
|
31
|
-
# --------------------------------------------------
|
|
32
|
-
# SolverModel object.
|
|
33
|
-
# --------------------------------------------------
|
|
34
|
-
|
|
35
|
-
class SolverModel:
|
|
36
|
-
def __init__(self, graph:dsl.Graph):
|
|
37
|
-
self.graph = graph
|
|
38
|
-
self.id = dsl.next_id()
|
|
39
|
-
self.scope = f"solvermodel{self.id}_"
|
|
40
|
-
scope = self.scope
|
|
41
|
-
self.Variable = dsl.Type(graph, "variables", scope=scope)
|
|
42
|
-
self.MinObjective = dsl.Type(graph, "min_objectives", scope=scope)
|
|
43
|
-
self.MaxObjective = dsl.Type(graph, "max_objectives", scope=scope)
|
|
44
|
-
self.Constraint = dsl.Type(graph, "constraints", scope=scope)
|
|
45
|
-
self.Solution = dsl.Type(graph, "solutions", scope=scope)
|
|
46
|
-
self.components = [
|
|
47
|
-
(self.MinObjective, "minimization objectives"),
|
|
48
|
-
(self.MaxObjective, "maximization objectives"),
|
|
49
|
-
(self.Constraint, "constraints"),
|
|
50
|
-
]
|
|
51
|
-
self.solve_index = 0
|
|
52
|
-
self.is_solved = False
|
|
53
|
-
|
|
54
|
-
# Install model helpers.
|
|
55
|
-
self.graph.install_raw(textwrap.dedent(f"""
|
|
56
|
-
@inline
|
|
57
|
-
def _solverlib_ho_appl(op, {{R}}, s): rel_primitive_solverlib_ho_appl(R, op, s)
|
|
58
|
-
|
|
59
|
-
@inline
|
|
60
|
-
def _solver_unwrap({{R}}, h, x...): exists((v) | R(v, x...) and pyrel_unwrap(v, h))
|
|
61
|
-
|
|
62
|
-
declare {scope}variable_name
|
|
63
|
-
declare {scope}component_name
|
|
64
|
-
declare {scope}serialized
|
|
65
|
-
declare {scope}primal_start
|
|
66
|
-
|
|
67
|
-
def {scope}component_string(h, s):
|
|
68
|
-
rel_primitive_solverlib_print_expr(
|
|
69
|
-
{scope}serialized[h], _solver_unwrap[{scope}variable_name], s
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
declare {scope}solve_output
|
|
73
|
-
"""))
|
|
74
|
-
return None
|
|
75
|
-
|
|
76
|
-
# Add an entity to the variable set, (optionally) set a string name from the
|
|
77
|
-
# arguments and add domain constraints on the variable.
|
|
78
|
-
def variable(
|
|
79
|
-
self,
|
|
80
|
-
var, # variable entity
|
|
81
|
-
name_args:List|None=None, # list of strings to concatenate into a string name
|
|
82
|
-
type:str|None=None, # variable type: "integer" or "zero_one"
|
|
83
|
-
lower:int|float|None=None, # lower bound
|
|
84
|
-
upper:int|float|None=None, # upper bound
|
|
85
|
-
fixed:int|float|None=None, # fixed value
|
|
86
|
-
start:int|float|None=None, # (primal) start value
|
|
87
|
-
):
|
|
88
|
-
if type not in {"integer", "zero_one", None}:
|
|
89
|
-
raise Exception(f"Invalid domain type: {type}.")
|
|
90
|
-
var.set(self.Variable)
|
|
91
|
-
|
|
92
|
-
# Set variable name.
|
|
93
|
-
if name_args:
|
|
94
|
-
var.set(**{f"{self.scope}variable_name": make_string(name_args)})
|
|
95
|
-
|
|
96
|
-
# Add domain constraints.
|
|
97
|
-
cons = []
|
|
98
|
-
if fixed is not None:
|
|
99
|
-
cons.append(eq(var, fixed))
|
|
100
|
-
if type == "zero_one":
|
|
101
|
-
cons.append(zero_one(var))
|
|
102
|
-
if lower is not None and upper is not None:
|
|
103
|
-
if type == "integer":
|
|
104
|
-
cons.append(integer_interval(var, lower, upper))
|
|
105
|
-
else:
|
|
106
|
-
cons.append(interval(var, lower, upper))
|
|
107
|
-
else:
|
|
108
|
-
if type == "integer":
|
|
109
|
-
cons.append(integer(var))
|
|
110
|
-
if lower is not None:
|
|
111
|
-
cons.append(gte(var, lower))
|
|
112
|
-
if upper is not None:
|
|
113
|
-
cons.append(lte(var, upper))
|
|
114
|
-
if len(cons) == 1:
|
|
115
|
-
self.constraint(cons[0])
|
|
116
|
-
elif len(cons) > 1:
|
|
117
|
-
self.constraint(and_(*cons))
|
|
118
|
-
|
|
119
|
-
# Set primal start.
|
|
120
|
-
if start is not None:
|
|
121
|
-
var.set(**{f"{self.scope}primal_start": start})
|
|
122
|
-
return var
|
|
123
|
-
|
|
124
|
-
# Get variable string name.
|
|
125
|
-
def variable_name(self, var):
|
|
126
|
-
return std.alias(getattr(var, f"{self.scope}variable_name"), "name")
|
|
127
|
-
|
|
128
|
-
# Add a constraint, minimization objective, or maximization objective.
|
|
129
|
-
def constraint(self, expr, name_args:List|None=None):
|
|
130
|
-
return self._add_component(self.Constraint, expr, name_args)
|
|
131
|
-
|
|
132
|
-
def min_objective(self, expr, name_args:List|None=None):
|
|
133
|
-
return self._add_component(self.MinObjective, expr, name_args)
|
|
134
|
-
|
|
135
|
-
def max_objective(self, expr, name_args:List|None=None):
|
|
136
|
-
return self._add_component(self.MaxObjective, expr, name_args)
|
|
137
|
-
|
|
138
|
-
def _add_component(self, typ, expr, name_args:List|None):
|
|
139
|
-
comp = typ.add(serialized=_wrap_expr(expr))
|
|
140
|
-
if name_args:
|
|
141
|
-
comp.set(component_name=make_string(name_args))
|
|
142
|
-
return comp
|
|
143
|
-
|
|
144
|
-
# Get component string name.
|
|
145
|
-
def component_name(self, comp):
|
|
146
|
-
return std.alias(comp.component_name, "name")
|
|
147
|
-
|
|
148
|
-
# Get serialized component string in human-readable format.
|
|
149
|
-
def component_string(self, comp):
|
|
150
|
-
return std.alias(comp.component_string, "string")
|
|
151
|
-
|
|
152
|
-
# Summarize the model by printing the number of variables and components.
|
|
153
|
-
# Use outside a rule/query.
|
|
154
|
-
def summarize(self):
|
|
155
|
-
with self.graph.query() as select:
|
|
156
|
-
vars = select(std.aggregates.count(self.Variable()))
|
|
157
|
-
s = f"Model has: {vars.results.iat[0, 0]} variables"
|
|
158
|
-
for (c_type, c_name) in self.components:
|
|
159
|
-
with self.graph.query() as select:
|
|
160
|
-
exprs = select(std.aggregates.count(c_type()))
|
|
161
|
-
if not exprs.results.empty:
|
|
162
|
-
s += f", {exprs.results.iat[0, 0]} {c_name}"
|
|
163
|
-
print(s)
|
|
164
|
-
return None
|
|
165
|
-
|
|
166
|
-
# Print the model in human-readable format. Use outside a rule/query.
|
|
167
|
-
def print(self):
|
|
168
|
-
with self.graph.query() as select:
|
|
169
|
-
vars = select(rel.last(getattr(rel, f"{self.scope}variable_name")))
|
|
170
|
-
print("variables:")
|
|
171
|
-
print(vars.results.to_string(index=False, header=False))
|
|
172
|
-
for (c_type, c_name) in self.components:
|
|
173
|
-
with self.graph.query() as select:
|
|
174
|
-
exprs = select(self.component_string(c_type()))
|
|
175
|
-
if not exprs.results.empty:
|
|
176
|
-
print(c_name + ":")
|
|
177
|
-
print(exprs.results.to_string(index=False, header=False))
|
|
178
|
-
return None
|
|
179
|
-
|
|
180
|
-
# Solve the model given a solver and solver options. Use outside a rule/query.
|
|
181
|
-
def solve(self, solver: Solver, log_to_console=True, **kwargs):
|
|
182
|
-
self.is_solved = False
|
|
183
|
-
self.solve_index += 1
|
|
184
|
-
self.solve_output = dsl.RelationNS([f"{self.scope}solve_output"], f"i_{self.solve_index}")
|
|
185
|
-
|
|
186
|
-
options = kwargs
|
|
187
|
-
options["version"] = 1
|
|
188
|
-
|
|
189
|
-
# Validate options.
|
|
190
|
-
for k, v in options.items():
|
|
191
|
-
if not isinstance(k, str):
|
|
192
|
-
raise Exception(f"Invalid parameter key. Expected string, got {type(k)} for {k}.")
|
|
193
|
-
if not isinstance(v, (int, float, str, bool)):
|
|
194
|
-
raise Exception(
|
|
195
|
-
f"Invalid parameter value. Expected string, integer, float, or boolean, got {type(v)} for {k}."
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
# Run the solve query and insert the solve_output result.
|
|
199
|
-
scope = self.scope
|
|
200
|
-
variable_name_string = f"{scope}variable_name" if "print_format" in options else "{}"
|
|
201
|
-
component_name_string = f"{scope}component_name" if "print_format" in options else "{}"
|
|
202
|
-
|
|
203
|
-
input_id = uuid.uuid4()
|
|
204
|
-
model_uri = f"snowflake://APP_STATE.RAI_INTERNAL_STAGE/job-inputs/solver/{input_id}/model.binpb"
|
|
205
|
-
sf_input_uri = f"snowflake://job-inputs/solver/{input_id}/model.binpb"
|
|
206
|
-
|
|
207
|
-
payload: dict[str, Any] = {"solver": solver.solver_name.lower()}
|
|
208
|
-
payload["options"] = options
|
|
209
|
-
payload["model_uri"] = sf_input_uri
|
|
210
|
-
|
|
211
|
-
rai_config = self.graph._config
|
|
212
|
-
query_timeout_mins = kwargs.get("query_timeout_mins", None)
|
|
213
|
-
if query_timeout_mins is None and (timeout_value := rai_config.get("query_timeout_mins", DEFAULT_QUERY_TIMEOUT_MINS)) is not None:
|
|
214
|
-
query_timeout_mins = int(timeout_value)
|
|
215
|
-
config_file_path = getattr(rai_config, 'file_path', None)
|
|
216
|
-
start_time = time.monotonic()
|
|
217
|
-
remaining_timeout_minutes = query_timeout_mins
|
|
218
|
-
response = self.graph.exec_raw(
|
|
219
|
-
textwrap.dedent(f"""
|
|
220
|
-
@inline
|
|
221
|
-
def {scope}specialized_components(t, h, s):
|
|
222
|
-
exists((v) | {{
|
|
223
|
-
(:min_objective, {scope}min_objectives);
|
|
224
|
-
(:max_objective, {scope}max_objectives);
|
|
225
|
-
(:constraint, {scope}constraints);
|
|
226
|
-
}}(t, v) and pyrel_unwrap(v, h) and {scope}serialized(v, s)
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
@no_diagnostics(:EXPERIMENTAL)
|
|
230
|
-
def {scope}model_string {{
|
|
231
|
-
rel_primitive_solverlib_model_string[{{
|
|
232
|
-
(:variable, _solver_unwrap[{scope}variables]);
|
|
233
|
-
{scope}specialized_components;
|
|
234
|
-
(:variable_name, _solver_unwrap[{variable_name_string}]);
|
|
235
|
-
(:expression_name, _solver_unwrap[{component_name_string}]);
|
|
236
|
-
(:primal_start, _solver_unwrap[{scope}primal_start]);
|
|
237
|
-
}}]
|
|
238
|
-
}}
|
|
239
|
-
|
|
240
|
-
ic model_not_empty("Solver model is empty.") requires not empty({scope}model_string)
|
|
241
|
-
|
|
242
|
-
def config[:envelope, :content_type]: "application/octet-stream"
|
|
243
|
-
def config[:envelope, :payload, :data]: {scope}model_string
|
|
244
|
-
def config[:envelope, :payload, :path]: "{model_uri}"
|
|
245
|
-
def export {{ config }}
|
|
246
|
-
"""),
|
|
247
|
-
query_timeout_mins=remaining_timeout_minutes,
|
|
248
|
-
)
|
|
249
|
-
txn = response.transaction or {}
|
|
250
|
-
# The above `exec_raw` will throw an error if the transaction
|
|
251
|
-
# gets aborted. But in the case it gets cancelled, by the user
|
|
252
|
-
# or the system, it won't throw. In that case we also did not
|
|
253
|
-
# upload the input model.
|
|
254
|
-
if txn["state"] == "":
|
|
255
|
-
txn = solver.provider.resources.get_transaction(txn["id"]) or {}
|
|
256
|
-
if txn["state"] != "COMPLETED":
|
|
257
|
-
raise Exception(f"Transaction that materializes the solver inputs did not complete! ID: `{txn['id']}` State `{txn['state']}`")
|
|
258
|
-
|
|
259
|
-
# 2. Execute job and wait for completion.
|
|
260
|
-
remaining_timeout_minutes = calc_remaining_timeout_minutes(
|
|
261
|
-
start_time, query_timeout_mins, config_file_path=config_file_path
|
|
262
|
-
)
|
|
263
|
-
job_id = solver._exec_job(payload, log_to_console=log_to_console, query_timeout_mins=remaining_timeout_minutes)
|
|
264
|
-
|
|
265
|
-
# 3. Extract result.
|
|
266
|
-
remaining_timeout_minutes = calc_remaining_timeout_minutes(
|
|
267
|
-
start_time, query_timeout_mins, config_file_path=config_file_path
|
|
268
|
-
)
|
|
269
|
-
res = self.graph.exec_raw(
|
|
270
|
-
textwrap.dedent(f"""
|
|
271
|
-
ic result_not_empty("Solver result is empty.") requires not empty(result)
|
|
272
|
-
|
|
273
|
-
def result {{load_binary["snowflake://APP_STATE.RAI_INTERNAL_STAGE/job-results/{job_id}/result.binpb"] }}
|
|
274
|
-
def delete[:{scope}solve_output, :"i_{self.solve_index}"]: {scope}solve_output[:"i_{self.solve_index}"]
|
|
275
|
-
|
|
276
|
-
@no_diagnostics(:EXPERIMENTAL)
|
|
277
|
-
def insert[:{scope}solve_output, :"i_{self.solve_index}"]:
|
|
278
|
-
rel_primitive_solverlib_extract[result]
|
|
279
|
-
|
|
280
|
-
def output[:solver_error]: {scope}solve_output[:"i_{self.solve_index}", :error]
|
|
281
|
-
"""),
|
|
282
|
-
readonly=False,
|
|
283
|
-
query_timeout_mins=remaining_timeout_minutes,
|
|
284
|
-
)
|
|
285
|
-
errors = []
|
|
286
|
-
for result in res.results:
|
|
287
|
-
if result["relationId"] == "/:output/:solver_error/String":
|
|
288
|
-
errors.extend(result["table"]["v1"])
|
|
289
|
-
|
|
290
|
-
# 4. Map results to solution.
|
|
291
|
-
with self.graph.rule(dynamic=True):
|
|
292
|
-
sol = self.Solution.add(index = self.solve_index)
|
|
293
|
-
for name in {"error", "termination_status", "solve_time_sec", "objective_value", "solver_version", "printed_model"}:
|
|
294
|
-
val = dsl.create_var()
|
|
295
|
-
getattr(self.solve_output, name)(val)
|
|
296
|
-
sol.set(**{name:val})
|
|
297
|
-
|
|
298
|
-
self.is_solved = True
|
|
299
|
-
|
|
300
|
-
if len(errors) > 0:
|
|
301
|
-
raise Exception("\n".join(errors))
|
|
302
|
-
|
|
303
|
-
return None
|
|
304
|
-
|
|
305
|
-
# Get scalar result information after solving.
|
|
306
|
-
def __getattr__(self, name:str):
|
|
307
|
-
if not self.is_solved:
|
|
308
|
-
raise Exception("Model has not been solved yet.")
|
|
309
|
-
if name in {"error", "termination_status", "solve_time_sec", "objective_value", "solver_version", "printed_model"}:
|
|
310
|
-
return getattr(self.Solution(index = self.solve_index), name)
|
|
311
|
-
else:
|
|
312
|
-
return None
|
|
313
|
-
|
|
314
|
-
# Get variable point values after solving. If `index` is specified, get the value
|
|
315
|
-
# of the variable in the return the `index`-th solution.
|
|
316
|
-
def value(self, var, index:int|None=None):
|
|
317
|
-
if not self.is_solved:
|
|
318
|
-
raise Exception("Model has not been solved yet.")
|
|
319
|
-
val = dsl.create_var()
|
|
320
|
-
unwrap_var = rel_sv.pyrel_unwrap(var)
|
|
321
|
-
if index:
|
|
322
|
-
self.solve_output.points(unwrap_var, index, val)
|
|
323
|
-
else:
|
|
324
|
-
self.solve_output.point(unwrap_var, val)
|
|
325
|
-
std.alias(val, "value")
|
|
326
|
-
return val
|
|
327
|
-
|
|
328
|
-
# --------------------------------------------------
|
|
329
|
-
# Operator definitions
|
|
330
|
-
# --------------------------------------------------
|
|
331
|
-
|
|
332
|
-
# Builtin binary operators
|
|
333
|
-
|
|
334
|
-
def plus(left, right):
|
|
335
|
-
return _make_fo_expr(10, left, right)
|
|
336
|
-
|
|
337
|
-
def minus(left, right):
|
|
338
|
-
return _make_fo_expr(11, left, right)
|
|
339
|
-
|
|
340
|
-
def mult(left, right):
|
|
341
|
-
return _make_fo_expr(12, left, right)
|
|
342
|
-
|
|
343
|
-
def div(left, right):
|
|
344
|
-
return _make_fo_expr(13, left, right)
|
|
345
|
-
|
|
346
|
-
def pow(left, right):
|
|
347
|
-
return _make_fo_expr(14, left, right)
|
|
348
|
-
|
|
349
|
-
def eq(left, right):
|
|
350
|
-
return _make_fo_expr(30, left, right)
|
|
351
|
-
|
|
352
|
-
def neq(left, right):
|
|
353
|
-
return _make_fo_expr(31, left, right)
|
|
354
|
-
|
|
355
|
-
def lte(left, right):
|
|
356
|
-
return _make_fo_expr(32, left, right)
|
|
357
|
-
|
|
358
|
-
def gte(left, right):
|
|
359
|
-
return _make_fo_expr(33, left, right)
|
|
360
|
-
|
|
361
|
-
def lt(left, right):
|
|
362
|
-
return _make_fo_expr(34, left, right)
|
|
363
|
-
|
|
364
|
-
def gt(left, right):
|
|
365
|
-
return _make_fo_expr(35, left, right)
|
|
366
|
-
|
|
367
|
-
# First order operators
|
|
368
|
-
|
|
369
|
-
def abs(arg):
|
|
370
|
-
return _make_fo_expr(20, arg)
|
|
371
|
-
|
|
372
|
-
def exp(arg):
|
|
373
|
-
return _make_fo_expr(21, arg)
|
|
374
|
-
|
|
375
|
-
def log(arg):
|
|
376
|
-
return _make_fo_expr(22, arg)
|
|
377
|
-
|
|
378
|
-
def integer(arg):
|
|
379
|
-
return _make_fo_expr(41, arg)
|
|
380
|
-
|
|
381
|
-
def zero_one(arg):
|
|
382
|
-
return _make_fo_expr(42, arg)
|
|
383
|
-
|
|
384
|
-
def interval(arg, low, high):
|
|
385
|
-
return _make_fo_expr(51, low, high, arg)
|
|
386
|
-
|
|
387
|
-
def integer_interval(arg, low, high):
|
|
388
|
-
return _make_fo_expr(50, low, high, 1, arg)
|
|
389
|
-
|
|
390
|
-
def if_then_else(cond, left, right):
|
|
391
|
-
return _make_fo_expr(60, cond, left, right)
|
|
392
|
-
|
|
393
|
-
def not_(arg):
|
|
394
|
-
return _make_fo_expr(61, arg)
|
|
395
|
-
|
|
396
|
-
def implies(left, right):
|
|
397
|
-
return _make_fo_expr(62, left, right)
|
|
398
|
-
|
|
399
|
-
def iff(left, right):
|
|
400
|
-
return _make_fo_expr(63, left, right)
|
|
401
|
-
|
|
402
|
-
def xor(left, right):
|
|
403
|
-
return _make_fo_expr(64, left, right)
|
|
404
|
-
|
|
405
|
-
def and_(*args):
|
|
406
|
-
return _make_fo_expr(70, *args)
|
|
407
|
-
|
|
408
|
-
def or_(*args):
|
|
409
|
-
return _make_fo_expr(71, *args)
|
|
410
|
-
|
|
411
|
-
# Aggregate operators
|
|
412
|
-
|
|
413
|
-
def sum(*args, per=[]) -> Any:
|
|
414
|
-
return _make_ho_expr(80, args, per)
|
|
415
|
-
|
|
416
|
-
def product(*args, per=[]) -> Any:
|
|
417
|
-
return _make_ho_expr(81, args, per)
|
|
418
|
-
|
|
419
|
-
def min(*args, per=[]) -> Any:
|
|
420
|
-
return _make_ho_expr(82, args, per)
|
|
421
|
-
|
|
422
|
-
def max(*args, per=[]) -> Any:
|
|
423
|
-
return _make_ho_expr(83, args, per)
|
|
424
|
-
|
|
425
|
-
def count(*args, per=[]) -> Any:
|
|
426
|
-
return _make_ho_expr(84, args, per)
|
|
427
|
-
|
|
428
|
-
def all_different(*args, per=[]) -> Any:
|
|
429
|
-
return _make_ho_expr(90, args, per)
|
|
430
|
-
|
|
431
|
-
# --------------------------------------------------
|
|
432
|
-
# Symbolic expression helpers
|
|
433
|
-
# --------------------------------------------------
|
|
434
|
-
|
|
435
|
-
def _make_fo_expr(*args):
|
|
436
|
-
expr = rel_sv.rel_primitive_solverlib_fo_appl(*args)
|
|
437
|
-
expr.__class__ = SolverExpression
|
|
438
|
-
return expr
|
|
439
|
-
|
|
440
|
-
# TODO(coey) test:
|
|
441
|
-
# dsl.tag(rel_sv.rel_primitive_solverlib_fo_appl, Builtins.Expensive)
|
|
442
|
-
|
|
443
|
-
def _make_ho_expr(op, args, per):
|
|
444
|
-
return SolverExpression(dsl.get_graph(), _ho_appl_def, [args, per, [op]])
|
|
445
|
-
|
|
446
|
-
_ho_appl_def = dsl.build.aggregate_def("_solverlib_ho_appl")
|
|
447
|
-
|
|
448
|
-
class SolverExpression(dsl.Expression):
|
|
449
|
-
def __init__(self, graph, op, args):
|
|
450
|
-
super().__init__(graph, op, args)
|
|
451
|
-
|
|
452
|
-
def _wrap_expr(e):
|
|
453
|
-
# If expression is not known to produce a serialized expression string,
|
|
454
|
-
# wrap it with the identity operation just in case
|
|
455
|
-
return e if isinstance(e, SolverExpression) else _make_fo_expr(0, e)
|
|
456
|
-
|
|
457
|
-
# Symbolic expression context, in which some builtin infix operators are redefined
|
|
458
|
-
# TODO(coey) handle comparison chains (e.g. 0 < x < y <= 1) or throw error
|
|
459
|
-
class Operators(dsl.Context):
|
|
460
|
-
def _supports_binary_op(self, op):
|
|
461
|
-
return op in _builtin_binary_map
|
|
462
|
-
|
|
463
|
-
def _make_binary_op(self, op, left, right):
|
|
464
|
-
return _make_fo_expr(_builtin_binary_map[op], left, right)
|
|
465
|
-
|
|
466
|
-
def operators():
|
|
467
|
-
return Operators(dsl.get_graph())
|
|
468
|
-
|
|
469
|
-
# Maps for Builtins operator to SolverLib operator ID
|
|
470
|
-
_builtin_binary_map = {
|
|
471
|
-
Builtins.plus: 10,
|
|
472
|
-
Builtins.minus: 11,
|
|
473
|
-
Builtins.mult: 12,
|
|
474
|
-
Builtins.div: 13,
|
|
475
|
-
Builtins.pow: 14,
|
|
476
|
-
Builtins.approx_eq: 30,
|
|
477
|
-
Builtins.neq: 31,
|
|
478
|
-
Builtins.lte: 32,
|
|
479
|
-
Builtins.gte: 33,
|
|
480
|
-
Builtins.lt: 34,
|
|
481
|
-
Builtins.gt: 35,
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
# Concatenate arguments into a string separated by underscores
|
|
485
|
-
def make_string(args:List):
|
|
486
|
-
string = args[0]
|
|
487
|
-
for arg in args[1:]:
|
|
488
|
-
string = rel_sv.concat(rel_sv.concat(string, "_"), arg)
|
|
489
|
-
return string
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
# --------------------------------------------------
|
|
493
|
-
# Solver
|
|
494
|
-
# --------------------------------------------------
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
@dataclass
|
|
498
|
-
class PollingState:
|
|
499
|
-
job_id: str
|
|
500
|
-
continuation_token: str
|
|
501
|
-
is_done: bool
|
|
502
|
-
log_to_console: bool
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
class Solver:
|
|
506
|
-
def __init__(
|
|
507
|
-
self,
|
|
508
|
-
solver_name: str,
|
|
509
|
-
engine_name: str | None = None,
|
|
510
|
-
engine_size: str | None = None,
|
|
511
|
-
auto_suspend_mins: int | None = None,
|
|
512
|
-
resources: SnowflakeResources | None = None,
|
|
513
|
-
):
|
|
514
|
-
self.provider = Provider(resources=resources)
|
|
515
|
-
self.solver_name = solver_name.lower()
|
|
516
|
-
|
|
517
|
-
self.rai_config = self.provider.resources.config
|
|
518
|
-
settings: dict[str, Any] = {}
|
|
519
|
-
if "experimental" in self.rai_config:
|
|
520
|
-
exp_config = self.rai_config.get("experimental", {})
|
|
521
|
-
if isinstance(exp_config, dict):
|
|
522
|
-
if "solvers" in exp_config:
|
|
523
|
-
settings = exp_config["solvers"].copy()
|
|
524
|
-
|
|
525
|
-
# Engine configuration fields are not necessary for the solver
|
|
526
|
-
# settings so we `pop` them from the settings object. Default
|
|
527
|
-
# size and auto_suspend_mins are set in the `Provider` methods.
|
|
528
|
-
engine_name = engine_name or settings.pop("engine", None)
|
|
529
|
-
if not engine_name:
|
|
530
|
-
engine_name = self.provider.resources.get_user_based_engine_name()
|
|
531
|
-
self.engine_name = engine_name
|
|
532
|
-
|
|
533
|
-
self.engine_size = engine_size or settings.pop("engine_size", None)
|
|
534
|
-
self.engine_auto_suspend_mins = auto_suspend_mins or settings.pop("auto_suspend_mins", None)
|
|
535
|
-
|
|
536
|
-
# Set default CSV store setting if not already configured
|
|
537
|
-
if "store" not in settings:
|
|
538
|
-
settings["store"] = {}
|
|
539
|
-
if "csv" not in settings["store"]:
|
|
540
|
-
settings["store"]["csv"] = {}
|
|
541
|
-
if "enabled" not in settings["store"]["csv"]:
|
|
542
|
-
settings["store"]["csv"]["enabled"] = True
|
|
543
|
-
|
|
544
|
-
# The settings are used when creating a solver engine, they
|
|
545
|
-
# may configure each individual solver.
|
|
546
|
-
self.engine_settings = settings
|
|
547
|
-
|
|
548
|
-
# Optimistically set the engine object to a `READY` engine to
|
|
549
|
-
# avoid checking the engine status on each execution.
|
|
550
|
-
self.engine:Optional[dict[str,Any]] = {"name": engine_name, "state": "READY"}
|
|
551
|
-
|
|
552
|
-
return None
|
|
553
|
-
|
|
554
|
-
# --------------------------------------------------
|
|
555
|
-
# Helper
|
|
556
|
-
# --------------------------------------------------
|
|
557
|
-
def _auto_create_solver_async(self):
|
|
558
|
-
name = self.engine_name
|
|
559
|
-
auto_suspend_mins = self.engine_auto_suspend_mins
|
|
560
|
-
size = self.engine_size
|
|
561
|
-
settings = self.engine_settings
|
|
562
|
-
with Spinner(
|
|
563
|
-
"Checking solver status",
|
|
564
|
-
leading_newline=True,
|
|
565
|
-
) as spinner:
|
|
566
|
-
engine = None
|
|
567
|
-
engines = [e for e in self.provider.list_solvers() if e["name"] == name]
|
|
568
|
-
assert len(engines) == 1 or len(engines) == 0
|
|
569
|
-
if len(engines) != 0:
|
|
570
|
-
engine = engines[0]
|
|
571
|
-
|
|
572
|
-
if engine:
|
|
573
|
-
# TODO (dba) Logic engines support altering the
|
|
574
|
-
# auto_suspend_mins setting. Currently, we don't have
|
|
575
|
-
# this capability for solver engines, so users need to
|
|
576
|
-
# recreate or use another engine. For both the size
|
|
577
|
-
# and Gurobi configuration the user anyways has to
|
|
578
|
-
# create a new one as this configuration must happen
|
|
579
|
-
# when the engine is created.
|
|
580
|
-
settings_cannot_be_altered_msg = "The configuration of a solver engine happens when the engine is created and _cannot_ be changed. You either need to specify a new engine name or delete the current engine.\n\nSee `solvers.Provider().delete_solver()`."
|
|
581
|
-
# Make sure that the solver requested is enabled
|
|
582
|
-
# on the engine.
|
|
583
|
-
if self.solver_name not in engine["solvers"]:
|
|
584
|
-
raise Exception(
|
|
585
|
-
f"Solver `{self.solver_name}` is not enabled on `{name}`.\n\n" + settings_cannot_be_altered_msg
|
|
586
|
-
)
|
|
587
|
-
|
|
588
|
-
# Make sure size and auto_suspend_mins settings match
|
|
589
|
-
# what the user requests.
|
|
590
|
-
if size is not None and size != engine["size"]:
|
|
591
|
-
raise Exception(
|
|
592
|
-
f"Engine `{name}` has size setting of `{engine['size']}` but size is requested to be `{size}`.\n\n" + settings_cannot_be_altered_msg
|
|
593
|
-
)
|
|
594
|
-
|
|
595
|
-
if auto_suspend_mins is not None and auto_suspend_mins != engine["auto_suspend_mins"]:
|
|
596
|
-
raise Exception(
|
|
597
|
-
f"Engine `{name}` has auto_suspend_mins setting of `{engine['auto_suspend_mins']}` but auto_suspend_mins is requested to be `{auto_suspend_mins}`.\n\n" + settings_cannot_be_altered_msg
|
|
598
|
-
)
|
|
599
|
-
|
|
600
|
-
if engine["state"] == "PENDING":
|
|
601
|
-
spinner.update_messages(
|
|
602
|
-
{
|
|
603
|
-
"finished_message": f"Solver {name} is starting",
|
|
604
|
-
}
|
|
605
|
-
)
|
|
606
|
-
pass
|
|
607
|
-
elif engine["state"] == "SUSPENDED":
|
|
608
|
-
spinner.update_messages(
|
|
609
|
-
{
|
|
610
|
-
"finished_message": f"Resuming solver {name}",
|
|
611
|
-
}
|
|
612
|
-
)
|
|
613
|
-
self.provider.resume_solver_async(name)
|
|
614
|
-
elif engine["state"] == "READY":
|
|
615
|
-
spinner.update_messages(
|
|
616
|
-
{
|
|
617
|
-
"finished_message": f"Solver {name} is ready",
|
|
618
|
-
}
|
|
619
|
-
)
|
|
620
|
-
pass
|
|
621
|
-
else:
|
|
622
|
-
spinner.update_messages(
|
|
623
|
-
{
|
|
624
|
-
"message": f"Restarting solver {name}",
|
|
625
|
-
}
|
|
626
|
-
)
|
|
627
|
-
self.provider.delete_solver(name)
|
|
628
|
-
engine = None
|
|
629
|
-
if not engine:
|
|
630
|
-
# Validate Gurobi config.
|
|
631
|
-
if self.solver_name == "gurobi":
|
|
632
|
-
is_gurobi_configured = False
|
|
633
|
-
gurobi_config = settings.get("gurobi", {})
|
|
634
|
-
if all(
|
|
635
|
-
k in gurobi_config
|
|
636
|
-
for k in ["license_secret_name", "external_access_integration"]
|
|
637
|
-
):
|
|
638
|
-
is_gurobi_configured = True
|
|
639
|
-
if not is_gurobi_configured:
|
|
640
|
-
raise Exception(
|
|
641
|
-
"Gurobi is not properly configured. You need to provide both `license_secret_name` and `external_access_integration` in its configuration, see https://docs.relational.ai/build/reasoners/prescriptive/solver-backends/gurobi/#usage"
|
|
642
|
-
)
|
|
643
|
-
self.provider.create_solver_async(name, settings=settings, size=size, auto_suspend_mins=auto_suspend_mins)
|
|
644
|
-
engine = self.provider.get_solver(name)
|
|
645
|
-
spinner.update_messages(
|
|
646
|
-
{
|
|
647
|
-
"finished_message": f"Starting solver {name}...",
|
|
648
|
-
}
|
|
649
|
-
)
|
|
650
|
-
|
|
651
|
-
self.engine = engine
|
|
652
|
-
|
|
653
|
-
def _exec_job(self, payload, log_to_console=True, query_timeout_mins: Optional[int]=None):
|
|
654
|
-
if self.engine is None:
|
|
655
|
-
raise Exception("Engine not initialized.")
|
|
656
|
-
|
|
657
|
-
with debugging.span("job") as job_span:
|
|
658
|
-
# Retry logic. If creating a job fails with an engine
|
|
659
|
-
# related error we will create/resume/... the engine and
|
|
660
|
-
# retry.
|
|
661
|
-
try:
|
|
662
|
-
job_id = self.provider.create_job_async(self.engine["name"], payload, query_timeout_mins=query_timeout_mins)
|
|
663
|
-
except Exception as e:
|
|
664
|
-
err_message = str(e).lower()
|
|
665
|
-
if isinstance(e, ResponseStatusException):
|
|
666
|
-
err_message = e.response.json().get("message", "")
|
|
667
|
-
if any(kw in err_message.lower() for kw in ENGINE_ERRORS + WORKER_ERRORS + ENGINE_NOT_READY_MSGS):
|
|
668
|
-
self._auto_create_solver_async()
|
|
669
|
-
# Wait until the engine is ready.
|
|
670
|
-
poll_with_specified_overhead(lambda: self._is_solver_ready(), 0.1)
|
|
671
|
-
job_id = self.provider.create_job_async(self.engine["name"], payload, query_timeout_mins=query_timeout_mins)
|
|
672
|
-
else:
|
|
673
|
-
raise e
|
|
674
|
-
|
|
675
|
-
job_span["job_id"] = job_id
|
|
676
|
-
debugging.event("job_created", job_span, job_id=job_id, engine_name=self.engine["name"], job_type=ENGINE_TYPE_SOLVER)
|
|
677
|
-
if not isinstance(job_id, str):
|
|
678
|
-
job_id = ""
|
|
679
|
-
polling_state = PollingState(job_id, "", False, log_to_console)
|
|
680
|
-
|
|
681
|
-
try:
|
|
682
|
-
with debugging.span("wait", job_id=job_id):
|
|
683
|
-
poll_with_specified_overhead(
|
|
684
|
-
lambda: self._check_job_status(polling_state), 0.1
|
|
685
|
-
)
|
|
686
|
-
except KeyboardInterrupt as e:
|
|
687
|
-
print(f"Canceling job {job_id}")
|
|
688
|
-
self.provider.cancel_job(job_id)
|
|
689
|
-
raise e
|
|
690
|
-
|
|
691
|
-
return job_id
|
|
692
|
-
|
|
693
|
-
def _is_solver_ready(self):
|
|
694
|
-
if self.engine is None:
|
|
695
|
-
raise Exception("Engine not initialized.")
|
|
696
|
-
|
|
697
|
-
result = self.provider.get_solver(self.engine["name"])
|
|
698
|
-
|
|
699
|
-
if result is None:
|
|
700
|
-
raise Exception("No engine available.")
|
|
701
|
-
|
|
702
|
-
self.engine = result
|
|
703
|
-
state = result["state"]
|
|
704
|
-
if state != "READY" and state != "PENDING":
|
|
705
|
-
# Might have suspended or otherwise gone. Recreate.
|
|
706
|
-
self._auto_create_solver_async()
|
|
707
|
-
return state == "READY"
|
|
708
|
-
|
|
709
|
-
def _check_job_status(self, state):
|
|
710
|
-
response = self.provider.get_job(state.job_id)
|
|
711
|
-
assert response, f"No results from get_job('{state.job_id}')"
|
|
712
|
-
|
|
713
|
-
status: str = response["state"]
|
|
714
|
-
|
|
715
|
-
self._print_solver_logs(state)
|
|
716
|
-
|
|
717
|
-
return status == "COMPLETED" or status == "FAILED" or status == "CANCELED"
|
|
718
|
-
|
|
719
|
-
def _print_solver_logs(self, state: PollingState):
|
|
720
|
-
if state.is_done:
|
|
721
|
-
return
|
|
722
|
-
|
|
723
|
-
resp = self.provider.get_job_events(state.job_id, state.continuation_token)
|
|
724
|
-
|
|
725
|
-
# Print solver logs to stdout.
|
|
726
|
-
for event in resp["events"]:
|
|
727
|
-
if event["type"] == "LogMessage":
|
|
728
|
-
if state.log_to_console:
|
|
729
|
-
print(event["event"]["message"])
|
|
730
|
-
else:
|
|
731
|
-
continue
|
|
732
|
-
|
|
733
|
-
state.continuation_token = resp["continuation_token"]
|
|
734
|
-
if state.continuation_token == "":
|
|
735
|
-
state.is_done = True
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
# --------------------------------------------------
|
|
739
|
-
# Provider
|
|
740
|
-
# --------------------------------------------------
|
|
741
|
-
#
|
|
742
|
-
# TODO (dba) We use an experimental and unified engine API for
|
|
743
|
-
# solvers. Once it is no longer experimental we can remove the
|
|
744
|
-
# provider here and use the normal PyRel provider.
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
class Provider:
|
|
748
|
-
def __init__(self, resources=None):
|
|
749
|
-
if not resources:
|
|
750
|
-
resources = relationalai.Resources()
|
|
751
|
-
if not isinstance(resources, SnowflakeResources):
|
|
752
|
-
raise Exception("Solvers are only supported on SPCS.")
|
|
753
|
-
|
|
754
|
-
# Type narrowing: resources is confirmed to be SnowflakeResources
|
|
755
|
-
self.resources: SnowflakeResources = cast(SnowflakeResources, resources)
|
|
756
|
-
self.direct_access_client: Optional[DirectAccessClient] = None
|
|
757
|
-
|
|
758
|
-
if isinstance(self.resources, DirectAccessResources):
|
|
759
|
-
self.direct_access_client = self.resources.direct_access_client
|
|
760
|
-
|
|
761
|
-
def create_solver(
|
|
762
|
-
self,
|
|
763
|
-
name: str,
|
|
764
|
-
size: str | None = None,
|
|
765
|
-
settings: dict | None = None,
|
|
766
|
-
auto_suspend_mins: int | None = None,
|
|
767
|
-
):
|
|
768
|
-
if size is None:
|
|
769
|
-
size = "HIGHMEM_X64_S"
|
|
770
|
-
if settings is None:
|
|
771
|
-
settings = {}
|
|
772
|
-
engine_config: dict[str, Any] = {"settings": settings}
|
|
773
|
-
if auto_suspend_mins is not None:
|
|
774
|
-
engine_config["auto_suspend_mins"] = auto_suspend_mins
|
|
775
|
-
self.resources._exec_sql(
|
|
776
|
-
f"CALL {APP_NAME}.experimental.create_engine('{ENGINE_TYPE_SOLVER}', '{name}', '{size}', {engine_config});", None
|
|
777
|
-
)
|
|
778
|
-
|
|
779
|
-
def create_solver_async(
|
|
780
|
-
self,
|
|
781
|
-
name: str,
|
|
782
|
-
size: str | None = None,
|
|
783
|
-
settings: dict | None = None,
|
|
784
|
-
auto_suspend_mins: int | None = None,
|
|
785
|
-
):
|
|
786
|
-
if size is None:
|
|
787
|
-
size = "HIGHMEM_X64_S"
|
|
788
|
-
|
|
789
|
-
if self.direct_access_client is not None:
|
|
790
|
-
payload:dict[str, Any] = {
|
|
791
|
-
"name": name,
|
|
792
|
-
"settings": settings,
|
|
793
|
-
}
|
|
794
|
-
if auto_suspend_mins is not None:
|
|
795
|
-
payload["auto_suspend_mins"] = auto_suspend_mins
|
|
796
|
-
if size is not None:
|
|
797
|
-
payload["size"] = size
|
|
798
|
-
response = self.direct_access_client.request(
|
|
799
|
-
"create_engine",
|
|
800
|
-
payload=payload,
|
|
801
|
-
path_params={"engine_type": "solver"},
|
|
802
|
-
)
|
|
803
|
-
if response.status_code != 200:
|
|
804
|
-
raise ResponseStatusException(
|
|
805
|
-
f"Failed to create engine {name} with size {size}.", response
|
|
806
|
-
)
|
|
807
|
-
else:
|
|
808
|
-
engine_config: dict[str, Any] = {}
|
|
809
|
-
if settings is not None:
|
|
810
|
-
engine_config["settings"] = settings
|
|
811
|
-
if auto_suspend_mins is not None:
|
|
812
|
-
engine_config["auto_suspend_mins"] = auto_suspend_mins
|
|
813
|
-
self.resources._exec_sql(
|
|
814
|
-
f"CALL {APP_NAME}.experimental.create_engine_async('{ENGINE_TYPE_SOLVER}', '{name}', '{size}', {engine_config});",
|
|
815
|
-
None
|
|
816
|
-
)
|
|
817
|
-
|
|
818
|
-
def delete_solver(self, name: str):
|
|
819
|
-
if self.direct_access_client is not None:
|
|
820
|
-
response = self.direct_access_client.request(
|
|
821
|
-
"delete_engine", path_params = {"engine_type": ENGINE_TYPE_SOLVER, "engine_name": name}
|
|
822
|
-
)
|
|
823
|
-
if response.status_code != 200:
|
|
824
|
-
raise ResponseStatusException("Failed to delete engine.", response)
|
|
825
|
-
return None
|
|
826
|
-
else:
|
|
827
|
-
self.resources._exec_sql(
|
|
828
|
-
f"CALL {APP_NAME}.experimental.delete_engine('{ENGINE_TYPE_SOLVER}', '{name}');",
|
|
829
|
-
None
|
|
830
|
-
)
|
|
831
|
-
|
|
832
|
-
def resume_solver_async(self, name: str):
|
|
833
|
-
if self.direct_access_client is not None:
|
|
834
|
-
response = self.direct_access_client.request(
|
|
835
|
-
"resume_engine", path_params = {"engine_type": ENGINE_TYPE_SOLVER, "engine_name": name}
|
|
836
|
-
)
|
|
837
|
-
if response.status_code != 200:
|
|
838
|
-
raise ResponseStatusException("Failed to resume engine.", response)
|
|
839
|
-
return None
|
|
840
|
-
else:
|
|
841
|
-
self.resources._exec_sql(
|
|
842
|
-
f"CALL {APP_NAME}.experimental.resume_engine_async('{ENGINE_TYPE_SOLVER}', '{name}');",
|
|
843
|
-
None
|
|
844
|
-
)
|
|
845
|
-
return None
|
|
846
|
-
|
|
847
|
-
def get_solver(self, name: str):
|
|
848
|
-
if self.direct_access_client is not None:
|
|
849
|
-
response = self.direct_access_client.request(
|
|
850
|
-
"get_engine", path_params = {"engine_type": ENGINE_TYPE_SOLVER, "engine_name": name}
|
|
851
|
-
)
|
|
852
|
-
if response.status_code != 200:
|
|
853
|
-
raise ResponseStatusException("Failed to get engine.", response)
|
|
854
|
-
solver = response.json()
|
|
855
|
-
if not solver :
|
|
856
|
-
return None
|
|
857
|
-
solver_state = {
|
|
858
|
-
"name": solver["name"],
|
|
859
|
-
"id": solver["id"],
|
|
860
|
-
"size": solver["size"],
|
|
861
|
-
"state": solver["status"], # callers are expecting 'state'
|
|
862
|
-
"created_by": solver["created_by"],
|
|
863
|
-
"created_on": solver["created_on"],
|
|
864
|
-
"updated_on": solver["updated_on"],
|
|
865
|
-
"version": solver["version"],
|
|
866
|
-
"auto_suspend": solver["auto_suspend_mins"],
|
|
867
|
-
"suspends_at": solver["suspends_at"],
|
|
868
|
-
"solvers": []
|
|
869
|
-
if solver["settings"] == ""
|
|
870
|
-
else [
|
|
871
|
-
k
|
|
872
|
-
for (k,v) in json.loads(solver["settings"]).items()
|
|
873
|
-
if isinstance(v, dict) and v.get("enabled", False)
|
|
874
|
-
],
|
|
875
|
-
}
|
|
876
|
-
return solver_state
|
|
877
|
-
else:
|
|
878
|
-
results = self.resources._exec_sql(
|
|
879
|
-
f"CALL {APP_NAME}.experimental.get_engine('{ENGINE_TYPE_SOLVER}', '{name}');",
|
|
880
|
-
None
|
|
881
|
-
)
|
|
882
|
-
return solver_list_to_dicts(results)[0]
|
|
883
|
-
|
|
884
|
-
def list_solvers(self, state: str | None = None):
|
|
885
|
-
if self.direct_access_client is not None:
|
|
886
|
-
response = self.direct_access_client.request(
|
|
887
|
-
"list_engines"
|
|
888
|
-
)
|
|
889
|
-
if response.status_code != 200:
|
|
890
|
-
raise ResponseStatusException("Failed to list engines.", response)
|
|
891
|
-
response_content = response.json()
|
|
892
|
-
if not response_content:
|
|
893
|
-
return []
|
|
894
|
-
engines = [
|
|
895
|
-
{
|
|
896
|
-
"name": engine["name"],
|
|
897
|
-
"id": engine["id"],
|
|
898
|
-
"size": engine["size"],
|
|
899
|
-
"state": engine["status"], # callers are expecting 'state'
|
|
900
|
-
"created_by": engine["created_by"],
|
|
901
|
-
"created_on": engine["created_on"],
|
|
902
|
-
"updated_on": engine["updated_on"],
|
|
903
|
-
"auto_suspend_mins": engine["auto_suspend_mins"],
|
|
904
|
-
"solvers": []
|
|
905
|
-
if engine["settings"] == ""
|
|
906
|
-
else [
|
|
907
|
-
k
|
|
908
|
-
for (k, v) in json.loads(engine["settings"]).items()
|
|
909
|
-
if isinstance(v, dict) and v.get("enabled", False)
|
|
910
|
-
],
|
|
911
|
-
}
|
|
912
|
-
for engine in response_content.get("engines", [])
|
|
913
|
-
if (state is None or engine.get("status") == state) and (engine.get("type") == ENGINE_TYPE_SOLVER)
|
|
914
|
-
]
|
|
915
|
-
return sorted(engines, key=lambda x: x["name"])
|
|
916
|
-
else:
|
|
917
|
-
where_clause = f"WHERE TYPE='{ENGINE_TYPE_SOLVER}'"
|
|
918
|
-
where_clause = (
|
|
919
|
-
f"{where_clause} AND STATUS = '{state.upper()}'" if state else where_clause
|
|
920
|
-
)
|
|
921
|
-
statement = f"SELECT NAME,ID,SIZE,STATUS,CREATED_BY,CREATED_ON,UPDATED_ON,AUTO_SUSPEND_MINS,SETTINGS FROM {APP_NAME}.experimental.engines {where_clause};"
|
|
922
|
-
results = self.resources._exec_sql(statement, None)
|
|
923
|
-
return solver_list_to_dicts(results)
|
|
924
|
-
|
|
925
|
-
# --------------------------------------------------
|
|
926
|
-
# Job API
|
|
927
|
-
# --------------------------------------------------
|
|
928
|
-
|
|
929
|
-
def create_job_async(self, engine_name, payload, query_timeout_mins: Optional[int]=None):
|
|
930
|
-
payload_json = json.dumps(payload)
|
|
931
|
-
|
|
932
|
-
if query_timeout_mins is None and (timeout_value := self.resources.config.get("query_timeout_mins", DEFAULT_QUERY_TIMEOUT_MINS)) is not None:
|
|
933
|
-
query_timeout_mins = int(timeout_value)
|
|
934
|
-
|
|
935
|
-
if self.direct_access_client is not None:
|
|
936
|
-
job = {
|
|
937
|
-
"job_type":ENGINE_TYPE_SOLVER,
|
|
938
|
-
"worker_name": engine_name,
|
|
939
|
-
"timeout_mins": query_timeout_mins,
|
|
940
|
-
"payload": payload_json,
|
|
941
|
-
}
|
|
942
|
-
response = self.direct_access_client.request(
|
|
943
|
-
"create_job",
|
|
944
|
-
payload=job,
|
|
945
|
-
)
|
|
946
|
-
if response.status_code != 200:
|
|
947
|
-
raise ResponseStatusException("Failed to create job.", response)
|
|
948
|
-
response_content = response.json()
|
|
949
|
-
return response_content["id"]
|
|
950
|
-
else:
|
|
951
|
-
if query_timeout_mins is not None:
|
|
952
|
-
sql_string = textwrap.dedent(f"""
|
|
953
|
-
CALL {APP_NAME}.experimental.exec_job_async('{ENGINE_TYPE_SOLVER}', '{engine_name}', '{payload_json}', null, {query_timeout_mins})
|
|
954
|
-
""")
|
|
955
|
-
else:
|
|
956
|
-
sql_string = textwrap.dedent(f"""
|
|
957
|
-
CALL {APP_NAME}.experimental.exec_job_async('{ENGINE_TYPE_SOLVER}', '{engine_name}', '{payload_json}')
|
|
958
|
-
""")
|
|
959
|
-
res = self.resources._exec_sql(sql_string, None)
|
|
960
|
-
return res[0]["ID"]
|
|
961
|
-
|
|
962
|
-
def list_jobs(self, state=None, limit=None):
|
|
963
|
-
if self.direct_access_client is not None:
|
|
964
|
-
response = self.direct_access_client.request(
|
|
965
|
-
"list_jobs"
|
|
966
|
-
)
|
|
967
|
-
if response.status_code != 200:
|
|
968
|
-
raise ResponseStatusException("Failed to list jobs.", response)
|
|
969
|
-
response_content = response.json()
|
|
970
|
-
if not response_content:
|
|
971
|
-
return []
|
|
972
|
-
jobs = [
|
|
973
|
-
{
|
|
974
|
-
"id": job["id"],
|
|
975
|
-
"state": job["state"],
|
|
976
|
-
"created_by": job["created_by"],
|
|
977
|
-
"created_on": job["created_on"],
|
|
978
|
-
"finished_at": job.get("finished_at", None),
|
|
979
|
-
"duration": job["duration"] if "duration" in job else 0,
|
|
980
|
-
"solver": json.loads(job["payload"]).get("solver", ""),
|
|
981
|
-
"engine": job.get("engine_name", job["worker_name"]),
|
|
982
|
-
}
|
|
983
|
-
for job in response_content.get("jobs", [])
|
|
984
|
-
if state is None or job.get("state") == state
|
|
985
|
-
]
|
|
986
|
-
return sorted(jobs, key=lambda x: x["created_on"], reverse=True)
|
|
987
|
-
else:
|
|
988
|
-
state_clause = f"AND STATE = '{state.upper()}'" if state else ""
|
|
989
|
-
limit_clause = f"LIMIT {limit}" if limit else ""
|
|
990
|
-
results = self.resources._exec_sql(
|
|
991
|
-
f"SELECT ID,STATE,CREATED_BY,CREATED_ON,FINISHED_AT,DURATION,PAYLOAD,ENGINE_NAME FROM {APP_NAME}.experimental.jobs where type='{ENGINE_TYPE_SOLVER}' {state_clause} ORDER BY created_on DESC {limit_clause};",
|
|
992
|
-
None
|
|
993
|
-
)
|
|
994
|
-
return job_list_to_dicts(results)
|
|
995
|
-
|
|
996
|
-
def get_job(self, id: str):
|
|
997
|
-
if self.direct_access_client is not None:
|
|
998
|
-
response = self.direct_access_client.request(
|
|
999
|
-
"get_job", path_params = {"job_type": ENGINE_TYPE_SOLVER, "job_id": id}
|
|
1000
|
-
)
|
|
1001
|
-
if response.status_code != 200:
|
|
1002
|
-
raise ResponseStatusException("Failed to get job.", response)
|
|
1003
|
-
response_content = response.json()
|
|
1004
|
-
return response_content["job"]
|
|
1005
|
-
else:
|
|
1006
|
-
results = self.resources._exec_sql(
|
|
1007
|
-
f"CALL {APP_NAME}.experimental.get_job('{ENGINE_TYPE_SOLVER}', '{id}');",
|
|
1008
|
-
None
|
|
1009
|
-
)
|
|
1010
|
-
return job_list_to_dicts(results)[0]
|
|
1011
|
-
|
|
1012
|
-
def get_job_events(self, job_id: str, continuation_token: str = ""):
|
|
1013
|
-
if self.direct_access_client is not None:
|
|
1014
|
-
response = self.direct_access_client.request(
|
|
1015
|
-
"get_job_events",
|
|
1016
|
-
path_params = {"job_type": ENGINE_TYPE_SOLVER, "job_id": job_id, "stream_name": "progress"},
|
|
1017
|
-
query_params={"continuation_token": continuation_token},
|
|
1018
|
-
)
|
|
1019
|
-
if response.status_code != 200:
|
|
1020
|
-
raise ResponseStatusException("Failed to get job events.", response)
|
|
1021
|
-
response_content = response.json()
|
|
1022
|
-
if not response_content:
|
|
1023
|
-
return {
|
|
1024
|
-
"events": [],
|
|
1025
|
-
"continuation_token": None
|
|
1026
|
-
}
|
|
1027
|
-
return response_content
|
|
1028
|
-
else:
|
|
1029
|
-
results = self.resources._exec_sql(
|
|
1030
|
-
f"SELECT {APP_NAME}.experimental.get_job_events('{ENGINE_TYPE_SOLVER}', '{job_id}', '{continuation_token}');",
|
|
1031
|
-
None
|
|
1032
|
-
)
|
|
1033
|
-
if not results:
|
|
1034
|
-
return {"events": [], "continuation_token": None}
|
|
1035
|
-
row = results[0][0]
|
|
1036
|
-
if not isinstance(row, str):
|
|
1037
|
-
row = ""
|
|
1038
|
-
return json.loads(row)
|
|
1039
|
-
|
|
1040
|
-
def cancel_job(self, id: str):
|
|
1041
|
-
if self.direct_access_client is not None:
|
|
1042
|
-
response = self.direct_access_client.request(
|
|
1043
|
-
"cancel_job", path_params = {"job_type": ENGINE_TYPE_SOLVER, "job_id": id}
|
|
1044
|
-
)
|
|
1045
|
-
if response.status_code != 200:
|
|
1046
|
-
raise ResponseStatusException("Failed to cancel job.", response)
|
|
1047
|
-
return None
|
|
1048
|
-
else:
|
|
1049
|
-
self.resources._exec_sql(
|
|
1050
|
-
f"CALL {APP_NAME}.experimental.cancel_job('{ENGINE_TYPE_SOLVER}', '{id}');",
|
|
1051
|
-
None
|
|
1052
|
-
)
|
|
1053
|
-
return None
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
def solver_list_to_dicts(results):
|
|
1057
|
-
if not results:
|
|
1058
|
-
return []
|
|
1059
|
-
return [
|
|
1060
|
-
{
|
|
1061
|
-
"name": row["NAME"],
|
|
1062
|
-
"id": row["ID"],
|
|
1063
|
-
"size": row["SIZE"],
|
|
1064
|
-
"state": row["STATUS"], # callers are expecting 'state'
|
|
1065
|
-
"created_by": row["CREATED_BY"],
|
|
1066
|
-
"created_on": row["CREATED_ON"],
|
|
1067
|
-
"updated_on": row["UPDATED_ON"],
|
|
1068
|
-
"auto_suspend_mins": row["AUTO_SUSPEND_MINS"],
|
|
1069
|
-
"solvers": []
|
|
1070
|
-
if row["SETTINGS"] == ""
|
|
1071
|
-
else [
|
|
1072
|
-
k
|
|
1073
|
-
for (k, v) in json.loads(row["SETTINGS"]).items()
|
|
1074
|
-
if isinstance(v, dict) and v.get("enabled", False)
|
|
1075
|
-
],
|
|
1076
|
-
}
|
|
1077
|
-
for row in results
|
|
1078
|
-
]
|
|
1079
|
-
|
|
1080
|
-
def job_list_to_dicts(results):
|
|
1081
|
-
if not results:
|
|
1082
|
-
return []
|
|
1083
|
-
return [
|
|
1084
|
-
{
|
|
1085
|
-
"id": row["ID"],
|
|
1086
|
-
"state": row["STATE"],
|
|
1087
|
-
"created_by": row["CREATED_BY"],
|
|
1088
|
-
"created_on": row["CREATED_ON"],
|
|
1089
|
-
"finished_at": row["FINISHED_AT"],
|
|
1090
|
-
"duration": row["DURATION"] if "DURATION" in row else 0,
|
|
1091
|
-
"solver": json.loads(row["PAYLOAD"])["solver"],
|
|
1092
|
-
"engine": row["ENGINE_NAME"],
|
|
1093
|
-
}
|
|
1094
|
-
for row in results
|
|
1095
|
-
]
|