relationalai 0.13.0__py3-none-any.whl → 0.13.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- relationalai/__init__.py +1 -256
- relationalai/config/__init__.py +56 -0
- relationalai/config/config.py +289 -0
- relationalai/config/config_fields.py +86 -0
- relationalai/config/connections/__init__.py +46 -0
- relationalai/config/connections/base.py +23 -0
- relationalai/config/connections/duckdb.py +29 -0
- relationalai/config/connections/snowflake.py +243 -0
- relationalai/config/external/__init__.py +17 -0
- relationalai/config/external/dbt_converter.py +101 -0
- relationalai/config/external/dbt_models.py +93 -0
- relationalai/config/external/snowflake_converter.py +41 -0
- relationalai/config/external/snowflake_models.py +85 -0
- relationalai/config/external/utils.py +19 -0
- relationalai/semantics/__init__.py +146 -22
- relationalai/semantics/backends/lqp/annotations.py +11 -0
- relationalai/semantics/backends/sql/sql_compiler.py +327 -0
- relationalai/semantics/frontend/base.py +1707 -0
- relationalai/semantics/frontend/core.py +179 -0
- relationalai/semantics/frontend/front_compiler.py +1313 -0
- relationalai/semantics/frontend/pprint.py +408 -0
- relationalai/semantics/metamodel/__init__.py +6 -40
- relationalai/semantics/metamodel/builtins.py +205 -771
- relationalai/semantics/metamodel/metamodel.py +437 -0
- relationalai/semantics/metamodel/metamodel_analyzer.py +519 -0
- relationalai/semantics/metamodel/pprint.py +412 -0
- relationalai/semantics/metamodel/rewriter.py +266 -0
- relationalai/semantics/metamodel/typer.py +1378 -0
- relationalai/semantics/std/__init__.py +60 -40
- relationalai/semantics/std/aggregates.py +149 -0
- relationalai/semantics/std/common.py +44 -0
- relationalai/semantics/std/constraints.py +37 -43
- relationalai/semantics/std/datetime.py +246 -135
- relationalai/semantics/std/decimals.py +45 -52
- relationalai/semantics/std/floats.py +13 -5
- relationalai/semantics/std/integers.py +26 -11
- relationalai/semantics/std/math.py +183 -112
- relationalai/semantics/std/numbers.py +86 -0
- relationalai/semantics/std/re.py +80 -62
- relationalai/semantics/std/strings.py +117 -60
- relationalai/shims/executor.py +147 -0
- relationalai/shims/helpers.py +126 -0
- relationalai/shims/hoister.py +221 -0
- relationalai/shims/mm2v0.py +1290 -0
- relationalai/tools/cli/__init__.py +6 -0
- relationalai/tools/cli/cli.py +90 -0
- relationalai/tools/cli/components/__init__.py +5 -0
- relationalai/tools/cli/components/progress_reader.py +1524 -0
- relationalai/tools/cli/components/utils.py +58 -0
- relationalai/tools/cli/config_template.py +45 -0
- relationalai/tools/cli/dev.py +19 -0
- relationalai/tools/debugger.py +289 -183
- relationalai/tools/typer_debugger.py +93 -0
- relationalai/util/dataclasses.py +43 -0
- relationalai/util/docutils.py +40 -0
- relationalai/util/error.py +199 -0
- relationalai/util/format.py +48 -106
- relationalai/util/naming.py +145 -0
- relationalai/util/python.py +35 -0
- relationalai/util/runtime.py +156 -0
- relationalai/util/schema.py +197 -0
- relationalai/util/source.py +185 -0
- relationalai/util/structures.py +163 -0
- relationalai/util/tracing.py +261 -0
- relationalai-0.13.0.dev0.dist-info/METADATA +46 -0
- relationalai-0.13.0.dev0.dist-info/RECORD +488 -0
- relationalai-0.13.0.dev0.dist-info/WHEEL +5 -0
- relationalai-0.13.0.dev0.dist-info/entry_points.txt +3 -0
- relationalai-0.13.0.dev0.dist-info/top_level.txt +2 -0
- v0/relationalai/__init__.py +216 -0
- v0/relationalai/clients/__init__.py +5 -0
- v0/relationalai/clients/azure.py +477 -0
- v0/relationalai/clients/client.py +912 -0
- v0/relationalai/clients/config.py +673 -0
- v0/relationalai/clients/direct_access_client.py +118 -0
- v0/relationalai/clients/hash_util.py +31 -0
- v0/relationalai/clients/local.py +571 -0
- v0/relationalai/clients/profile_polling.py +73 -0
- v0/relationalai/clients/result_helpers.py +420 -0
- v0/relationalai/clients/snowflake.py +3869 -0
- v0/relationalai/clients/types.py +113 -0
- v0/relationalai/clients/use_index_poller.py +980 -0
- v0/relationalai/clients/util.py +356 -0
- v0/relationalai/debugging.py +389 -0
- v0/relationalai/dsl.py +1749 -0
- v0/relationalai/early_access/builder/__init__.py +30 -0
- v0/relationalai/early_access/builder/builder/__init__.py +35 -0
- v0/relationalai/early_access/builder/snowflake/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/__init__.py +25 -0
- v0/relationalai/early_access/builder/std/decimals/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/integers/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/math/__init__.py +12 -0
- v0/relationalai/early_access/builder/std/strings/__init__.py +14 -0
- v0/relationalai/early_access/devtools/__init__.py +12 -0
- v0/relationalai/early_access/devtools/benchmark_lqp/__init__.py +12 -0
- v0/relationalai/early_access/devtools/extract_lqp/__init__.py +12 -0
- v0/relationalai/early_access/dsl/adapters/orm/adapter_qb.py +427 -0
- v0/relationalai/early_access/dsl/adapters/orm/parser.py +636 -0
- v0/relationalai/early_access/dsl/adapters/owl/adapter.py +176 -0
- v0/relationalai/early_access/dsl/adapters/owl/parser.py +160 -0
- v0/relationalai/early_access/dsl/bindings/common.py +402 -0
- v0/relationalai/early_access/dsl/bindings/csv.py +170 -0
- v0/relationalai/early_access/dsl/bindings/legacy/binding_models.py +143 -0
- v0/relationalai/early_access/dsl/bindings/snowflake.py +64 -0
- v0/relationalai/early_access/dsl/codegen/binder.py +411 -0
- v0/relationalai/early_access/dsl/codegen/common.py +79 -0
- v0/relationalai/early_access/dsl/codegen/helpers.py +23 -0
- v0/relationalai/early_access/dsl/codegen/relations.py +700 -0
- v0/relationalai/early_access/dsl/codegen/weaver.py +417 -0
- v0/relationalai/early_access/dsl/core/builders/__init__.py +47 -0
- v0/relationalai/early_access/dsl/core/builders/logic.py +19 -0
- v0/relationalai/early_access/dsl/core/builders/scalar_constraint.py +11 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/atomic.py +455 -0
- v0/relationalai/early_access/dsl/core/constraints/predicate/universal.py +73 -0
- v0/relationalai/early_access/dsl/core/constraints/scalar.py +310 -0
- v0/relationalai/early_access/dsl/core/context.py +13 -0
- v0/relationalai/early_access/dsl/core/cset.py +132 -0
- v0/relationalai/early_access/dsl/core/exprs/__init__.py +116 -0
- v0/relationalai/early_access/dsl/core/exprs/relational.py +18 -0
- v0/relationalai/early_access/dsl/core/exprs/scalar.py +412 -0
- v0/relationalai/early_access/dsl/core/instances.py +44 -0
- v0/relationalai/early_access/dsl/core/logic/__init__.py +193 -0
- v0/relationalai/early_access/dsl/core/logic/aggregation.py +98 -0
- v0/relationalai/early_access/dsl/core/logic/exists.py +223 -0
- v0/relationalai/early_access/dsl/core/logic/helper.py +163 -0
- v0/relationalai/early_access/dsl/core/namespaces.py +32 -0
- v0/relationalai/early_access/dsl/core/relations.py +276 -0
- v0/relationalai/early_access/dsl/core/rules.py +112 -0
- v0/relationalai/early_access/dsl/core/std/__init__.py +45 -0
- v0/relationalai/early_access/dsl/core/temporal/recall.py +6 -0
- v0/relationalai/early_access/dsl/core/types/__init__.py +270 -0
- v0/relationalai/early_access/dsl/core/types/concepts.py +128 -0
- v0/relationalai/early_access/dsl/core/types/constrained/__init__.py +267 -0
- v0/relationalai/early_access/dsl/core/types/constrained/nominal.py +143 -0
- v0/relationalai/early_access/dsl/core/types/constrained/subtype.py +124 -0
- v0/relationalai/early_access/dsl/core/types/standard.py +92 -0
- v0/relationalai/early_access/dsl/core/types/unconstrained.py +50 -0
- v0/relationalai/early_access/dsl/core/types/variables.py +203 -0
- v0/relationalai/early_access/dsl/ir/compiler.py +318 -0
- v0/relationalai/early_access/dsl/ir/executor.py +260 -0
- v0/relationalai/early_access/dsl/ontologies/constraints.py +88 -0
- v0/relationalai/early_access/dsl/ontologies/export.py +30 -0
- v0/relationalai/early_access/dsl/ontologies/models.py +453 -0
- v0/relationalai/early_access/dsl/ontologies/python_printer.py +303 -0
- v0/relationalai/early_access/dsl/ontologies/readings.py +60 -0
- v0/relationalai/early_access/dsl/ontologies/relationships.py +322 -0
- v0/relationalai/early_access/dsl/ontologies/roles.py +87 -0
- v0/relationalai/early_access/dsl/ontologies/subtyping.py +55 -0
- v0/relationalai/early_access/dsl/orm/constraints.py +438 -0
- v0/relationalai/early_access/dsl/orm/measures/dimensions.py +200 -0
- v0/relationalai/early_access/dsl/orm/measures/initializer.py +16 -0
- v0/relationalai/early_access/dsl/orm/measures/measure_rules.py +275 -0
- v0/relationalai/early_access/dsl/orm/measures/measures.py +299 -0
- v0/relationalai/early_access/dsl/orm/measures/role_exprs.py +268 -0
- v0/relationalai/early_access/dsl/orm/models.py +256 -0
- v0/relationalai/early_access/dsl/orm/object_oriented_printer.py +344 -0
- v0/relationalai/early_access/dsl/orm/printer.py +469 -0
- v0/relationalai/early_access/dsl/orm/reasoners.py +480 -0
- v0/relationalai/early_access/dsl/orm/relations.py +19 -0
- v0/relationalai/early_access/dsl/orm/relationships.py +251 -0
- v0/relationalai/early_access/dsl/orm/types.py +42 -0
- v0/relationalai/early_access/dsl/orm/utils.py +79 -0
- v0/relationalai/early_access/dsl/orm/verb.py +204 -0
- v0/relationalai/early_access/dsl/physical_metadata/tables.py +133 -0
- v0/relationalai/early_access/dsl/relations.py +170 -0
- v0/relationalai/early_access/dsl/rulesets.py +69 -0
- v0/relationalai/early_access/dsl/schemas/__init__.py +450 -0
- v0/relationalai/early_access/dsl/schemas/builder.py +48 -0
- v0/relationalai/early_access/dsl/schemas/comp_names.py +51 -0
- v0/relationalai/early_access/dsl/schemas/components.py +203 -0
- v0/relationalai/early_access/dsl/schemas/contexts.py +156 -0
- v0/relationalai/early_access/dsl/schemas/exprs.py +89 -0
- v0/relationalai/early_access/dsl/schemas/fragments.py +464 -0
- v0/relationalai/early_access/dsl/serialization.py +79 -0
- v0/relationalai/early_access/dsl/serialize/exporter.py +163 -0
- v0/relationalai/early_access/dsl/snow/api.py +104 -0
- v0/relationalai/early_access/dsl/snow/common.py +76 -0
- v0/relationalai/early_access/dsl/state_mgmt/__init__.py +129 -0
- v0/relationalai/early_access/dsl/state_mgmt/state_charts.py +125 -0
- v0/relationalai/early_access/dsl/state_mgmt/transitions.py +130 -0
- v0/relationalai/early_access/dsl/types/__init__.py +40 -0
- v0/relationalai/early_access/dsl/types/concepts.py +12 -0
- v0/relationalai/early_access/dsl/types/entities.py +135 -0
- v0/relationalai/early_access/dsl/types/values.py +17 -0
- v0/relationalai/early_access/dsl/utils.py +102 -0
- v0/relationalai/early_access/graphs/__init__.py +13 -0
- v0/relationalai/early_access/lqp/__init__.py +12 -0
- v0/relationalai/early_access/lqp/compiler/__init__.py +12 -0
- v0/relationalai/early_access/lqp/constructors/__init__.py +18 -0
- v0/relationalai/early_access/lqp/executor/__init__.py +12 -0
- v0/relationalai/early_access/lqp/ir/__init__.py +12 -0
- v0/relationalai/early_access/lqp/passes/__init__.py +12 -0
- v0/relationalai/early_access/lqp/pragmas/__init__.py +12 -0
- v0/relationalai/early_access/lqp/primitives/__init__.py +12 -0
- v0/relationalai/early_access/lqp/types/__init__.py +12 -0
- v0/relationalai/early_access/lqp/utils/__init__.py +12 -0
- v0/relationalai/early_access/lqp/validators/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/__init__.py +58 -0
- v0/relationalai/early_access/metamodel/builtins/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/compiler/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/dependency/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/factory/__init__.py +17 -0
- v0/relationalai/early_access/metamodel/helpers/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/ir/__init__.py +14 -0
- v0/relationalai/early_access/metamodel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/metamodel/typer/__init__.py +3 -0
- v0/relationalai/early_access/metamodel/typer/typer/__init__.py +12 -0
- v0/relationalai/early_access/metamodel/types/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/util/__init__.py +15 -0
- v0/relationalai/early_access/metamodel/visitor/__init__.py +12 -0
- v0/relationalai/early_access/rel/__init__.py +12 -0
- v0/relationalai/early_access/rel/executor/__init__.py +12 -0
- v0/relationalai/early_access/rel/rel_utils/__init__.py +12 -0
- v0/relationalai/early_access/rel/rewrite/__init__.py +7 -0
- v0/relationalai/early_access/solvers/__init__.py +19 -0
- v0/relationalai/early_access/sql/__init__.py +11 -0
- v0/relationalai/early_access/sql/executor/__init__.py +3 -0
- v0/relationalai/early_access/sql/rewrite/__init__.py +3 -0
- v0/relationalai/early_access/tests/logging/__init__.py +12 -0
- v0/relationalai/early_access/tests/test_snapshot_base/__init__.py +12 -0
- v0/relationalai/early_access/tests/utils/__init__.py +12 -0
- v0/relationalai/environments/__init__.py +35 -0
- v0/relationalai/environments/base.py +381 -0
- v0/relationalai/environments/colab.py +14 -0
- v0/relationalai/environments/generic.py +71 -0
- v0/relationalai/environments/ipython.py +68 -0
- v0/relationalai/environments/jupyter.py +9 -0
- v0/relationalai/environments/snowbook.py +169 -0
- v0/relationalai/errors.py +2455 -0
- v0/relationalai/experimental/SF.py +38 -0
- v0/relationalai/experimental/inspect.py +47 -0
- v0/relationalai/experimental/pathfinder/__init__.py +158 -0
- v0/relationalai/experimental/pathfinder/api.py +160 -0
- v0/relationalai/experimental/pathfinder/automaton.py +584 -0
- v0/relationalai/experimental/pathfinder/bridge.py +226 -0
- v0/relationalai/experimental/pathfinder/compiler.py +416 -0
- v0/relationalai/experimental/pathfinder/datalog.py +214 -0
- v0/relationalai/experimental/pathfinder/diagnostics.py +56 -0
- v0/relationalai/experimental/pathfinder/filter.py +236 -0
- v0/relationalai/experimental/pathfinder/glushkov.py +439 -0
- v0/relationalai/experimental/pathfinder/options.py +265 -0
- v0/relationalai/experimental/pathfinder/rpq.py +344 -0
- v0/relationalai/experimental/pathfinder/transition.py +200 -0
- v0/relationalai/experimental/pathfinder/utils.py +26 -0
- v0/relationalai/experimental/paths/api.py +143 -0
- v0/relationalai/experimental/paths/benchmarks/grid_graph.py +37 -0
- v0/relationalai/experimental/paths/examples/basic_example.py +40 -0
- v0/relationalai/experimental/paths/examples/minimal_engine_warmup.py +3 -0
- v0/relationalai/experimental/paths/examples/movie_example.py +77 -0
- v0/relationalai/experimental/paths/examples/paths_benchmark.py +115 -0
- v0/relationalai/experimental/paths/examples/paths_example.py +116 -0
- v0/relationalai/experimental/paths/examples/pattern_to_automaton.py +28 -0
- v0/relationalai/experimental/paths/find_paths_via_automaton.py +85 -0
- v0/relationalai/experimental/paths/graph.py +185 -0
- v0/relationalai/experimental/paths/path_algorithms/find_paths.py +280 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +26 -0
- v0/relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +111 -0
- v0/relationalai/experimental/paths/path_algorithms/single.py +59 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +39 -0
- v0/relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +103 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-old.py +130 -0
- v0/relationalai/experimental/paths/path_algorithms/usp-tuple.py +183 -0
- v0/relationalai/experimental/paths/path_algorithms/usp.py +150 -0
- v0/relationalai/experimental/paths/product_graph.py +93 -0
- v0/relationalai/experimental/paths/rpq/automaton.py +584 -0
- v0/relationalai/experimental/paths/rpq/diagnostics.py +56 -0
- v0/relationalai/experimental/paths/rpq/rpq.py +378 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +90 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +119 -0
- v0/relationalai/experimental/paths/tests/tests_limit_sp_single.py +104 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +113 -0
- v0/relationalai/experimental/paths/tests/tests_limit_walks_single.py +149 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +70 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +64 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +115 -0
- v0/relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +75 -0
- v0/relationalai/experimental/paths/tests/tests_single_paths.py +152 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks.py +208 -0
- v0/relationalai/experimental/paths/tests/tests_single_walks_undirected.py +297 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +107 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +76 -0
- v0/relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +110 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +229 -0
- v0/relationalai/experimental/paths/tests/tests_usp_nsp_single.py +108 -0
- v0/relationalai/experimental/paths/tree_agg.py +168 -0
- v0/relationalai/experimental/paths/utilities/iterators.py +27 -0
- v0/relationalai/experimental/paths/utilities/prefix_sum.py +91 -0
- v0/relationalai/experimental/solvers.py +1087 -0
- v0/relationalai/loaders/__init__.py +0 -0
- v0/relationalai/loaders/csv.py +195 -0
- v0/relationalai/loaders/loader.py +177 -0
- v0/relationalai/loaders/types.py +23 -0
- v0/relationalai/rel_emitter.py +373 -0
- v0/relationalai/rel_utils.py +185 -0
- v0/relationalai/semantics/__init__.py +29 -0
- v0/relationalai/semantics/devtools/benchmark_lqp.py +536 -0
- v0/relationalai/semantics/devtools/compilation_manager.py +294 -0
- v0/relationalai/semantics/devtools/extract_lqp.py +110 -0
- v0/relationalai/semantics/internal/internal.py +3785 -0
- v0/relationalai/semantics/internal/snowflake.py +324 -0
- v0/relationalai/semantics/lqp/builtins.py +16 -0
- v0/relationalai/semantics/lqp/compiler.py +22 -0
- v0/relationalai/semantics/lqp/constructors.py +68 -0
- v0/relationalai/semantics/lqp/executor.py +469 -0
- v0/relationalai/semantics/lqp/intrinsics.py +24 -0
- v0/relationalai/semantics/lqp/model2lqp.py +839 -0
- v0/relationalai/semantics/lqp/passes.py +680 -0
- v0/relationalai/semantics/lqp/primitives.py +252 -0
- v0/relationalai/semantics/lqp/result_helpers.py +202 -0
- v0/relationalai/semantics/lqp/rewrite/annotate_constraints.py +57 -0
- v0/relationalai/semantics/lqp/rewrite/cdc.py +216 -0
- v0/relationalai/semantics/lqp/rewrite/extract_common.py +338 -0
- v0/relationalai/semantics/lqp/rewrite/extract_keys.py +449 -0
- v0/relationalai/semantics/lqp/rewrite/function_annotations.py +114 -0
- v0/relationalai/semantics/lqp/rewrite/functional_dependencies.py +314 -0
- v0/relationalai/semantics/lqp/rewrite/quantify_vars.py +296 -0
- v0/relationalai/semantics/lqp/rewrite/splinter.py +76 -0
- v0/relationalai/semantics/lqp/types.py +101 -0
- v0/relationalai/semantics/lqp/utils.py +160 -0
- v0/relationalai/semantics/lqp/validators.py +57 -0
- v0/relationalai/semantics/metamodel/__init__.py +40 -0
- v0/relationalai/semantics/metamodel/builtins.py +774 -0
- v0/relationalai/semantics/metamodel/compiler.py +133 -0
- v0/relationalai/semantics/metamodel/dependency.py +862 -0
- v0/relationalai/semantics/metamodel/executor.py +61 -0
- v0/relationalai/semantics/metamodel/factory.py +287 -0
- v0/relationalai/semantics/metamodel/helpers.py +361 -0
- v0/relationalai/semantics/metamodel/rewrite/discharge_constraints.py +39 -0
- v0/relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +210 -0
- v0/relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +78 -0
- v0/relationalai/semantics/metamodel/rewrite/flatten.py +549 -0
- v0/relationalai/semantics/metamodel/rewrite/format_outputs.py +165 -0
- v0/relationalai/semantics/metamodel/typer/checker.py +353 -0
- v0/relationalai/semantics/metamodel/typer/typer.py +1395 -0
- v0/relationalai/semantics/metamodel/util.py +505 -0
- v0/relationalai/semantics/reasoners/__init__.py +10 -0
- v0/relationalai/semantics/reasoners/graph/__init__.py +37 -0
- v0/relationalai/semantics/reasoners/graph/core.py +9020 -0
- v0/relationalai/semantics/reasoners/optimization/__init__.py +68 -0
- v0/relationalai/semantics/reasoners/optimization/common.py +88 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_dev.py +568 -0
- v0/relationalai/semantics/reasoners/optimization/solvers_pb.py +1163 -0
- v0/relationalai/semantics/rel/builtins.py +40 -0
- v0/relationalai/semantics/rel/compiler.py +989 -0
- v0/relationalai/semantics/rel/executor.py +359 -0
- v0/relationalai/semantics/rel/rel.py +482 -0
- v0/relationalai/semantics/rel/rel_utils.py +276 -0
- v0/relationalai/semantics/snowflake/__init__.py +3 -0
- v0/relationalai/semantics/sql/compiler.py +2503 -0
- v0/relationalai/semantics/sql/executor/duck_db.py +52 -0
- v0/relationalai/semantics/sql/executor/result_helpers.py +64 -0
- v0/relationalai/semantics/sql/executor/snowflake.py +145 -0
- v0/relationalai/semantics/sql/rewrite/denormalize.py +222 -0
- v0/relationalai/semantics/sql/rewrite/double_negation.py +49 -0
- v0/relationalai/semantics/sql/rewrite/recursive_union.py +127 -0
- v0/relationalai/semantics/sql/rewrite/sort_output_query.py +246 -0
- v0/relationalai/semantics/sql/sql.py +504 -0
- v0/relationalai/semantics/std/__init__.py +54 -0
- v0/relationalai/semantics/std/constraints.py +43 -0
- v0/relationalai/semantics/std/datetime.py +363 -0
- v0/relationalai/semantics/std/decimals.py +62 -0
- v0/relationalai/semantics/std/floats.py +7 -0
- v0/relationalai/semantics/std/integers.py +22 -0
- v0/relationalai/semantics/std/math.py +141 -0
- v0/relationalai/semantics/std/pragmas.py +11 -0
- v0/relationalai/semantics/std/re.py +83 -0
- v0/relationalai/semantics/std/std.py +14 -0
- v0/relationalai/semantics/std/strings.py +63 -0
- v0/relationalai/semantics/tests/__init__.py +0 -0
- v0/relationalai/semantics/tests/test_snapshot_abstract.py +143 -0
- v0/relationalai/semantics/tests/test_snapshot_base.py +9 -0
- v0/relationalai/semantics/tests/utils.py +46 -0
- v0/relationalai/std/__init__.py +70 -0
- v0/relationalai/tools/__init__.py +0 -0
- v0/relationalai/tools/cli.py +1940 -0
- v0/relationalai/tools/cli_controls.py +1826 -0
- v0/relationalai/tools/cli_helpers.py +390 -0
- v0/relationalai/tools/debugger.py +183 -0
- v0/relationalai/tools/debugger_client.py +109 -0
- v0/relationalai/tools/debugger_server.py +302 -0
- v0/relationalai/tools/dev.py +685 -0
- v0/relationalai/tools/qb_debugger.py +425 -0
- v0/relationalai/util/clean_up_databases.py +95 -0
- v0/relationalai/util/format.py +123 -0
- v0/relationalai/util/list_databases.py +9 -0
- v0/relationalai/util/otel_configuration.py +25 -0
- v0/relationalai/util/otel_handler.py +484 -0
- v0/relationalai/util/snowflake_handler.py +88 -0
- v0/relationalai/util/span_format_test.py +43 -0
- v0/relationalai/util/span_tracker.py +207 -0
- v0/relationalai/util/spans_file_handler.py +72 -0
- v0/relationalai/util/tracing_handler.py +34 -0
- frontend/debugger/dist/.gitignore +0 -2
- frontend/debugger/dist/assets/favicon-Dy0ZgA6N.png +0 -0
- frontend/debugger/dist/assets/index-Cssla-O7.js +0 -208
- frontend/debugger/dist/assets/index-DlHsYx1V.css +0 -9
- frontend/debugger/dist/index.html +0 -17
- relationalai/clients/__init__.py +0 -18
- relationalai/clients/client.py +0 -912
- relationalai/clients/config.py +0 -673
- relationalai/clients/direct_access_client.py +0 -118
- relationalai/clients/hash_util.py +0 -31
- relationalai/clients/local.py +0 -571
- relationalai/clients/profile_polling.py +0 -73
- relationalai/clients/resources/__init__.py +0 -8
- relationalai/clients/resources/azure/azure.py +0 -477
- relationalai/clients/resources/snowflake/__init__.py +0 -20
- relationalai/clients/resources/snowflake/cli_resources.py +0 -87
- relationalai/clients/resources/snowflake/direct_access_resources.py +0 -711
- relationalai/clients/resources/snowflake/engine_state_handlers.py +0 -309
- relationalai/clients/resources/snowflake/error_handlers.py +0 -199
- relationalai/clients/resources/snowflake/export_procedure.py.jinja +0 -249
- relationalai/clients/resources/snowflake/resources_factory.py +0 -99
- relationalai/clients/resources/snowflake/snowflake.py +0 -3083
- relationalai/clients/resources/snowflake/use_index_poller.py +0 -1011
- relationalai/clients/resources/snowflake/use_index_resources.py +0 -188
- relationalai/clients/resources/snowflake/util.py +0 -387
- relationalai/clients/result_helpers.py +0 -420
- relationalai/clients/types.py +0 -113
- relationalai/clients/util.py +0 -356
- relationalai/debugging.py +0 -389
- relationalai/dsl.py +0 -1749
- relationalai/early_access/builder/__init__.py +0 -30
- relationalai/early_access/builder/builder/__init__.py +0 -35
- relationalai/early_access/builder/snowflake/__init__.py +0 -12
- relationalai/early_access/builder/std/__init__.py +0 -25
- relationalai/early_access/builder/std/decimals/__init__.py +0 -12
- relationalai/early_access/builder/std/integers/__init__.py +0 -12
- relationalai/early_access/builder/std/math/__init__.py +0 -12
- relationalai/early_access/builder/std/strings/__init__.py +0 -14
- relationalai/early_access/devtools/__init__.py +0 -12
- relationalai/early_access/devtools/benchmark_lqp/__init__.py +0 -12
- relationalai/early_access/devtools/extract_lqp/__init__.py +0 -12
- relationalai/early_access/dsl/adapters/orm/adapter_qb.py +0 -427
- relationalai/early_access/dsl/adapters/orm/parser.py +0 -636
- relationalai/early_access/dsl/adapters/owl/adapter.py +0 -176
- relationalai/early_access/dsl/adapters/owl/parser.py +0 -160
- relationalai/early_access/dsl/bindings/common.py +0 -402
- relationalai/early_access/dsl/bindings/csv.py +0 -170
- relationalai/early_access/dsl/bindings/legacy/binding_models.py +0 -143
- relationalai/early_access/dsl/bindings/snowflake.py +0 -64
- relationalai/early_access/dsl/codegen/binder.py +0 -411
- relationalai/early_access/dsl/codegen/common.py +0 -79
- relationalai/early_access/dsl/codegen/helpers.py +0 -23
- relationalai/early_access/dsl/codegen/relations.py +0 -700
- relationalai/early_access/dsl/codegen/weaver.py +0 -417
- relationalai/early_access/dsl/core/builders/__init__.py +0 -47
- relationalai/early_access/dsl/core/builders/logic.py +0 -19
- relationalai/early_access/dsl/core/builders/scalar_constraint.py +0 -11
- relationalai/early_access/dsl/core/constraints/predicate/atomic.py +0 -455
- relationalai/early_access/dsl/core/constraints/predicate/universal.py +0 -73
- relationalai/early_access/dsl/core/constraints/scalar.py +0 -310
- relationalai/early_access/dsl/core/context.py +0 -13
- relationalai/early_access/dsl/core/cset.py +0 -132
- relationalai/early_access/dsl/core/exprs/__init__.py +0 -116
- relationalai/early_access/dsl/core/exprs/relational.py +0 -18
- relationalai/early_access/dsl/core/exprs/scalar.py +0 -412
- relationalai/early_access/dsl/core/instances.py +0 -44
- relationalai/early_access/dsl/core/logic/__init__.py +0 -193
- relationalai/early_access/dsl/core/logic/aggregation.py +0 -98
- relationalai/early_access/dsl/core/logic/exists.py +0 -223
- relationalai/early_access/dsl/core/logic/helper.py +0 -163
- relationalai/early_access/dsl/core/namespaces.py +0 -32
- relationalai/early_access/dsl/core/relations.py +0 -276
- relationalai/early_access/dsl/core/rules.py +0 -112
- relationalai/early_access/dsl/core/std/__init__.py +0 -45
- relationalai/early_access/dsl/core/temporal/recall.py +0 -6
- relationalai/early_access/dsl/core/types/__init__.py +0 -270
- relationalai/early_access/dsl/core/types/concepts.py +0 -128
- relationalai/early_access/dsl/core/types/constrained/__init__.py +0 -267
- relationalai/early_access/dsl/core/types/constrained/nominal.py +0 -143
- relationalai/early_access/dsl/core/types/constrained/subtype.py +0 -124
- relationalai/early_access/dsl/core/types/standard.py +0 -92
- relationalai/early_access/dsl/core/types/unconstrained.py +0 -50
- relationalai/early_access/dsl/core/types/variables.py +0 -203
- relationalai/early_access/dsl/ir/compiler.py +0 -318
- relationalai/early_access/dsl/ir/executor.py +0 -260
- relationalai/early_access/dsl/ontologies/constraints.py +0 -88
- relationalai/early_access/dsl/ontologies/export.py +0 -30
- relationalai/early_access/dsl/ontologies/models.py +0 -453
- relationalai/early_access/dsl/ontologies/python_printer.py +0 -303
- relationalai/early_access/dsl/ontologies/readings.py +0 -60
- relationalai/early_access/dsl/ontologies/relationships.py +0 -322
- relationalai/early_access/dsl/ontologies/roles.py +0 -87
- relationalai/early_access/dsl/ontologies/subtyping.py +0 -55
- relationalai/early_access/dsl/orm/constraints.py +0 -438
- relationalai/early_access/dsl/orm/measures/dimensions.py +0 -200
- relationalai/early_access/dsl/orm/measures/initializer.py +0 -16
- relationalai/early_access/dsl/orm/measures/measure_rules.py +0 -275
- relationalai/early_access/dsl/orm/measures/measures.py +0 -299
- relationalai/early_access/dsl/orm/measures/role_exprs.py +0 -268
- relationalai/early_access/dsl/orm/models.py +0 -256
- relationalai/early_access/dsl/orm/object_oriented_printer.py +0 -344
- relationalai/early_access/dsl/orm/printer.py +0 -469
- relationalai/early_access/dsl/orm/reasoners.py +0 -480
- relationalai/early_access/dsl/orm/relations.py +0 -19
- relationalai/early_access/dsl/orm/relationships.py +0 -251
- relationalai/early_access/dsl/orm/types.py +0 -42
- relationalai/early_access/dsl/orm/utils.py +0 -79
- relationalai/early_access/dsl/orm/verb.py +0 -204
- relationalai/early_access/dsl/physical_metadata/tables.py +0 -133
- relationalai/early_access/dsl/relations.py +0 -170
- relationalai/early_access/dsl/rulesets.py +0 -69
- relationalai/early_access/dsl/schemas/__init__.py +0 -450
- relationalai/early_access/dsl/schemas/builder.py +0 -48
- relationalai/early_access/dsl/schemas/comp_names.py +0 -51
- relationalai/early_access/dsl/schemas/components.py +0 -203
- relationalai/early_access/dsl/schemas/contexts.py +0 -156
- relationalai/early_access/dsl/schemas/exprs.py +0 -89
- relationalai/early_access/dsl/schemas/fragments.py +0 -464
- relationalai/early_access/dsl/serialization.py +0 -79
- relationalai/early_access/dsl/serialize/exporter.py +0 -163
- relationalai/early_access/dsl/snow/api.py +0 -105
- relationalai/early_access/dsl/snow/common.py +0 -76
- relationalai/early_access/dsl/state_mgmt/__init__.py +0 -129
- relationalai/early_access/dsl/state_mgmt/state_charts.py +0 -125
- relationalai/early_access/dsl/state_mgmt/transitions.py +0 -130
- relationalai/early_access/dsl/types/__init__.py +0 -40
- relationalai/early_access/dsl/types/concepts.py +0 -12
- relationalai/early_access/dsl/types/entities.py +0 -135
- relationalai/early_access/dsl/types/values.py +0 -17
- relationalai/early_access/dsl/utils.py +0 -102
- relationalai/early_access/graphs/__init__.py +0 -13
- relationalai/early_access/lqp/__init__.py +0 -12
- relationalai/early_access/lqp/compiler/__init__.py +0 -12
- relationalai/early_access/lqp/constructors/__init__.py +0 -18
- relationalai/early_access/lqp/executor/__init__.py +0 -12
- relationalai/early_access/lqp/ir/__init__.py +0 -12
- relationalai/early_access/lqp/passes/__init__.py +0 -12
- relationalai/early_access/lqp/pragmas/__init__.py +0 -12
- relationalai/early_access/lqp/primitives/__init__.py +0 -12
- relationalai/early_access/lqp/types/__init__.py +0 -12
- relationalai/early_access/lqp/utils/__init__.py +0 -12
- relationalai/early_access/lqp/validators/__init__.py +0 -12
- relationalai/early_access/metamodel/__init__.py +0 -58
- relationalai/early_access/metamodel/builtins/__init__.py +0 -12
- relationalai/early_access/metamodel/compiler/__init__.py +0 -12
- relationalai/early_access/metamodel/dependency/__init__.py +0 -12
- relationalai/early_access/metamodel/factory/__init__.py +0 -17
- relationalai/early_access/metamodel/helpers/__init__.py +0 -12
- relationalai/early_access/metamodel/ir/__init__.py +0 -14
- relationalai/early_access/metamodel/rewrite/__init__.py +0 -7
- relationalai/early_access/metamodel/typer/__init__.py +0 -3
- relationalai/early_access/metamodel/typer/typer/__init__.py +0 -12
- relationalai/early_access/metamodel/types/__init__.py +0 -15
- relationalai/early_access/metamodel/util/__init__.py +0 -15
- relationalai/early_access/metamodel/visitor/__init__.py +0 -12
- relationalai/early_access/rel/__init__.py +0 -12
- relationalai/early_access/rel/executor/__init__.py +0 -12
- relationalai/early_access/rel/rel_utils/__init__.py +0 -12
- relationalai/early_access/rel/rewrite/__init__.py +0 -7
- relationalai/early_access/solvers/__init__.py +0 -19
- relationalai/early_access/sql/__init__.py +0 -11
- relationalai/early_access/sql/executor/__init__.py +0 -3
- relationalai/early_access/sql/rewrite/__init__.py +0 -3
- relationalai/early_access/tests/logging/__init__.py +0 -12
- relationalai/early_access/tests/test_snapshot_base/__init__.py +0 -12
- relationalai/early_access/tests/utils/__init__.py +0 -12
- relationalai/environments/__init__.py +0 -35
- relationalai/environments/base.py +0 -381
- relationalai/environments/colab.py +0 -14
- relationalai/environments/generic.py +0 -71
- relationalai/environments/ipython.py +0 -68
- relationalai/environments/jupyter.py +0 -9
- relationalai/environments/snowbook.py +0 -169
- relationalai/errors.py +0 -2478
- relationalai/experimental/SF.py +0 -38
- relationalai/experimental/inspect.py +0 -47
- relationalai/experimental/pathfinder/__init__.py +0 -158
- relationalai/experimental/pathfinder/api.py +0 -160
- relationalai/experimental/pathfinder/automaton.py +0 -584
- relationalai/experimental/pathfinder/bridge.py +0 -226
- relationalai/experimental/pathfinder/compiler.py +0 -416
- relationalai/experimental/pathfinder/datalog.py +0 -214
- relationalai/experimental/pathfinder/diagnostics.py +0 -56
- relationalai/experimental/pathfinder/filter.py +0 -236
- relationalai/experimental/pathfinder/glushkov.py +0 -439
- relationalai/experimental/pathfinder/options.py +0 -265
- relationalai/experimental/pathfinder/pathfinder-v0.7.0.rel +0 -1951
- relationalai/experimental/pathfinder/rpq.py +0 -344
- relationalai/experimental/pathfinder/transition.py +0 -200
- relationalai/experimental/pathfinder/utils.py +0 -26
- relationalai/experimental/paths/README.md +0 -107
- relationalai/experimental/paths/api.py +0 -143
- relationalai/experimental/paths/benchmarks/grid_graph.py +0 -37
- relationalai/experimental/paths/code_organization.md +0 -2
- relationalai/experimental/paths/examples/Movies.ipynb +0 -16328
- relationalai/experimental/paths/examples/basic_example.py +0 -40
- relationalai/experimental/paths/examples/minimal_engine_warmup.py +0 -3
- relationalai/experimental/paths/examples/movie_example.py +0 -77
- relationalai/experimental/paths/examples/movies_data/actedin.csv +0 -193
- relationalai/experimental/paths/examples/movies_data/directed.csv +0 -45
- relationalai/experimental/paths/examples/movies_data/follows.csv +0 -7
- relationalai/experimental/paths/examples/movies_data/movies.csv +0 -39
- relationalai/experimental/paths/examples/movies_data/person.csv +0 -134
- relationalai/experimental/paths/examples/movies_data/produced.csv +0 -16
- relationalai/experimental/paths/examples/movies_data/ratings.csv +0 -10
- relationalai/experimental/paths/examples/movies_data/wrote.csv +0 -11
- relationalai/experimental/paths/examples/paths_benchmark.py +0 -115
- relationalai/experimental/paths/examples/paths_example.py +0 -116
- relationalai/experimental/paths/examples/pattern_to_automaton.py +0 -28
- relationalai/experimental/paths/find_paths_via_automaton.py +0 -85
- relationalai/experimental/paths/graph.py +0 -185
- relationalai/experimental/paths/path_algorithms/find_paths.py +0 -280
- relationalai/experimental/paths/path_algorithms/one_sided_ball_repetition.py +0 -26
- relationalai/experimental/paths/path_algorithms/one_sided_ball_upto.py +0 -111
- relationalai/experimental/paths/path_algorithms/single.py +0 -59
- relationalai/experimental/paths/path_algorithms/two_sided_balls_repetition.py +0 -39
- relationalai/experimental/paths/path_algorithms/two_sided_balls_upto.py +0 -103
- relationalai/experimental/paths/path_algorithms/usp-old.py +0 -130
- relationalai/experimental/paths/path_algorithms/usp-tuple.py +0 -183
- relationalai/experimental/paths/path_algorithms/usp.py +0 -150
- relationalai/experimental/paths/product_graph.py +0 -93
- relationalai/experimental/paths/rpq/automaton.py +0 -584
- relationalai/experimental/paths/rpq/diagnostics.py +0 -56
- relationalai/experimental/paths/rpq/rpq.py +0 -378
- relationalai/experimental/paths/tests/tests_limit_sp_max_length.py +0 -90
- relationalai/experimental/paths/tests/tests_limit_sp_multiple.py +0 -119
- relationalai/experimental/paths/tests/tests_limit_sp_single.py +0 -104
- relationalai/experimental/paths/tests/tests_limit_walks_multiple.py +0 -113
- relationalai/experimental/paths/tests/tests_limit_walks_single.py +0 -149
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_multiple.py +0 -70
- relationalai/experimental/paths/tests/tests_one_sided_ball_repetition_single.py +0 -64
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_multiple.py +0 -115
- relationalai/experimental/paths/tests/tests_one_sided_ball_upto_single.py +0 -75
- relationalai/experimental/paths/tests/tests_single_paths.py +0 -152
- relationalai/experimental/paths/tests/tests_single_walks.py +0 -208
- relationalai/experimental/paths/tests/tests_single_walks_undirected.py +0 -297
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_multiple.py +0 -107
- relationalai/experimental/paths/tests/tests_two_sided_balls_repetition_single.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_multiple.py +0 -76
- relationalai/experimental/paths/tests/tests_two_sided_balls_upto_single.py +0 -110
- relationalai/experimental/paths/tests/tests_usp_nsp_multiple.py +0 -229
- relationalai/experimental/paths/tests/tests_usp_nsp_single.py +0 -108
- relationalai/experimental/paths/tree_agg.py +0 -168
- relationalai/experimental/paths/utilities/iterators.py +0 -27
- relationalai/experimental/paths/utilities/prefix_sum.py +0 -91
- relationalai/experimental/solvers.py +0 -1087
- relationalai/loaders/csv.py +0 -195
- relationalai/loaders/loader.py +0 -177
- relationalai/loaders/types.py +0 -23
- relationalai/rel_emitter.py +0 -373
- relationalai/rel_utils.py +0 -185
- relationalai/semantics/designs/query_builder/identify_by.md +0 -106
- relationalai/semantics/devtools/benchmark_lqp.py +0 -535
- relationalai/semantics/devtools/compilation_manager.py +0 -294
- relationalai/semantics/devtools/extract_lqp.py +0 -110
- relationalai/semantics/internal/internal.py +0 -3785
- relationalai/semantics/internal/snowflake.py +0 -325
- relationalai/semantics/lqp/README.md +0 -34
- relationalai/semantics/lqp/builtins.py +0 -16
- relationalai/semantics/lqp/compiler.py +0 -22
- relationalai/semantics/lqp/constructors.py +0 -68
- relationalai/semantics/lqp/executor.py +0 -469
- relationalai/semantics/lqp/intrinsics.py +0 -24
- relationalai/semantics/lqp/model2lqp.py +0 -877
- relationalai/semantics/lqp/passes.py +0 -680
- relationalai/semantics/lqp/primitives.py +0 -252
- relationalai/semantics/lqp/result_helpers.py +0 -202
- relationalai/semantics/lqp/rewrite/annotate_constraints.py +0 -57
- relationalai/semantics/lqp/rewrite/cdc.py +0 -216
- relationalai/semantics/lqp/rewrite/extract_common.py +0 -338
- relationalai/semantics/lqp/rewrite/extract_keys.py +0 -506
- relationalai/semantics/lqp/rewrite/function_annotations.py +0 -114
- relationalai/semantics/lqp/rewrite/functional_dependencies.py +0 -314
- relationalai/semantics/lqp/rewrite/quantify_vars.py +0 -296
- relationalai/semantics/lqp/rewrite/splinter.py +0 -76
- relationalai/semantics/lqp/types.py +0 -101
- relationalai/semantics/lqp/utils.py +0 -160
- relationalai/semantics/lqp/validators.py +0 -57
- relationalai/semantics/metamodel/compiler.py +0 -133
- relationalai/semantics/metamodel/dependency.py +0 -862
- relationalai/semantics/metamodel/executor.py +0 -61
- relationalai/semantics/metamodel/factory.py +0 -287
- relationalai/semantics/metamodel/helpers.py +0 -361
- relationalai/semantics/metamodel/rewrite/discharge_constraints.py +0 -39
- relationalai/semantics/metamodel/rewrite/dnf_union_splitter.py +0 -210
- relationalai/semantics/metamodel/rewrite/extract_nested_logicals.py +0 -78
- relationalai/semantics/metamodel/rewrite/flatten.py +0 -554
- relationalai/semantics/metamodel/rewrite/format_outputs.py +0 -165
- relationalai/semantics/metamodel/typer/checker.py +0 -353
- relationalai/semantics/metamodel/typer/typer.py +0 -1395
- relationalai/semantics/metamodel/util.py +0 -506
- relationalai/semantics/reasoners/__init__.py +0 -10
- relationalai/semantics/reasoners/graph/README.md +0 -620
- relationalai/semantics/reasoners/graph/__init__.py +0 -37
- relationalai/semantics/reasoners/graph/core.py +0 -9019
- relationalai/semantics/reasoners/graph/design/beyond_demand_transform.md +0 -797
- relationalai/semantics/reasoners/graph/tests/README.md +0 -21
- relationalai/semantics/reasoners/optimization/__init__.py +0 -68
- relationalai/semantics/reasoners/optimization/common.py +0 -88
- relationalai/semantics/reasoners/optimization/solvers_dev.py +0 -568
- relationalai/semantics/reasoners/optimization/solvers_pb.py +0 -1163
- relationalai/semantics/rel/builtins.py +0 -40
- relationalai/semantics/rel/compiler.py +0 -989
- relationalai/semantics/rel/executor.py +0 -362
- relationalai/semantics/rel/rel.py +0 -482
- relationalai/semantics/rel/rel_utils.py +0 -276
- relationalai/semantics/snowflake/__init__.py +0 -3
- relationalai/semantics/sql/compiler.py +0 -2503
- relationalai/semantics/sql/executor/duck_db.py +0 -52
- relationalai/semantics/sql/executor/result_helpers.py +0 -64
- relationalai/semantics/sql/executor/snowflake.py +0 -149
- relationalai/semantics/sql/rewrite/denormalize.py +0 -222
- relationalai/semantics/sql/rewrite/double_negation.py +0 -49
- relationalai/semantics/sql/rewrite/recursive_union.py +0 -127
- relationalai/semantics/sql/rewrite/sort_output_query.py +0 -246
- relationalai/semantics/sql/sql.py +0 -504
- relationalai/semantics/std/pragmas.py +0 -11
- relationalai/semantics/std/std.py +0 -14
- relationalai/semantics/tests/test_snapshot_abstract.py +0 -143
- relationalai/semantics/tests/test_snapshot_base.py +0 -9
- relationalai/semantics/tests/utils.py +0 -46
- relationalai/std/__init__.py +0 -70
- relationalai/tools/cli.py +0 -1936
- relationalai/tools/cli_controls.py +0 -1826
- relationalai/tools/cli_helpers.py +0 -398
- relationalai/tools/debugger_client.py +0 -109
- relationalai/tools/debugger_server.py +0 -302
- relationalai/tools/dev.py +0 -685
- relationalai/tools/notes +0 -7
- relationalai/tools/qb_debugger.py +0 -425
- relationalai/util/clean_up_databases.py +0 -95
- relationalai/util/list_databases.py +0 -9
- relationalai/util/otel_configuration.py +0 -26
- relationalai/util/otel_handler.py +0 -484
- relationalai/util/snowflake_handler.py +0 -88
- relationalai/util/span_format_test.py +0 -43
- relationalai/util/span_tracker.py +0 -207
- relationalai/util/spans_file_handler.py +0 -72
- relationalai/util/tracing_handler.py +0 -34
- relationalai-0.13.0.dist-info/METADATA +0 -74
- relationalai-0.13.0.dist-info/RECORD +0 -458
- relationalai-0.13.0.dist-info/WHEEL +0 -4
- relationalai-0.13.0.dist-info/entry_points.txt +0 -3
- relationalai-0.13.0.dist-info/licenses/LICENSE +0 -202
- relationalai_test_util/__init__.py +0 -4
- relationalai_test_util/fixtures.py +0 -229
- relationalai_test_util/snapshot.py +0 -252
- relationalai_test_util/traceback.py +0 -118
- /relationalai/{analysis → semantics/frontend}/__init__.py +0 -0
- /relationalai/{auth/__init__.py → semantics/metamodel/metamodel_compiler.py} +0 -0
- /relationalai/{early_access → shims}/__init__.py +0 -0
- {relationalai/early_access/dsl/adapters → v0/relationalai/analysis}/__init__.py +0 -0
- {relationalai → v0/relationalai}/analysis/mechanistic.py +0 -0
- {relationalai → v0/relationalai}/analysis/whynot.py +0 -0
- {relationalai/early_access/dsl/adapters/orm → v0/relationalai/auth}/__init__.py +0 -0
- {relationalai → v0/relationalai}/auth/jwt_generator.py +0 -0
- {relationalai → v0/relationalai}/auth/oauth_callback_server.py +0 -0
- {relationalai → v0/relationalai}/auth/token_handler.py +0 -0
- {relationalai → v0/relationalai}/auth/util.py +0 -0
- {relationalai/clients/resources/snowflake → v0/relationalai/clients}/cache_store.py +0 -0
- {relationalai → v0/relationalai}/compiler.py +0 -0
- {relationalai → v0/relationalai}/dependencies.py +0 -0
- {relationalai → v0/relationalai}/docutils.py +0 -0
- {relationalai/early_access/dsl/adapters/owl → v0/relationalai/early_access}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings → v0/relationalai/early_access/dsl/adapters}/__init__.py +0 -0
- {relationalai/early_access/dsl/bindings/legacy → v0/relationalai/early_access/dsl/adapters/orm}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/orm/model.py +0 -0
- {relationalai/early_access/dsl/codegen → v0/relationalai/early_access/dsl/adapters/owl}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/adapters/owl/model.py +0 -0
- {relationalai/early_access/dsl/core/temporal → v0/relationalai/early_access/dsl/bindings}/__init__.py +0 -0
- {relationalai/early_access/dsl/ir → v0/relationalai/early_access/dsl/bindings/legacy}/__init__.py +0 -0
- {relationalai/early_access/dsl/ontologies → v0/relationalai/early_access/dsl/codegen}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/constants.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/constraints/predicate/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/stack.py +0 -0
- {relationalai/early_access/dsl/orm → v0/relationalai/early_access/dsl/core/temporal}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/core/utils.py +0 -0
- {relationalai/early_access/dsl/orm/measures → v0/relationalai/early_access/dsl/ir}/__init__.py +0 -0
- {relationalai/early_access/dsl/physical_metadata → v0/relationalai/early_access/dsl/ontologies}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/ontologies/raw_source.py +0 -0
- {relationalai/early_access/dsl/serialize → v0/relationalai/early_access/dsl/orm}/__init__.py +0 -0
- {relationalai/early_access/dsl/snow → v0/relationalai/early_access/dsl/orm/measures}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/orm/reasoner_errors.py +0 -0
- {relationalai/loaders → v0/relationalai/early_access/dsl/physical_metadata}/__init__.py +0 -0
- {relationalai/semantics/tests → v0/relationalai/early_access/dsl/serialize}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/binding_model.py +0 -0
- {relationalai → v0/relationalai}/early_access/dsl/serialize/model.py +0 -0
- {relationalai/tools → v0/relationalai/early_access/dsl/snow}/__init__.py +0 -0
- {relationalai → v0/relationalai}/early_access/tests/__init__.py +0 -0
- {relationalai → v0/relationalai}/environments/ci.py +0 -0
- {relationalai → v0/relationalai}/environments/hex.py +0 -0
- {relationalai → v0/relationalai}/environments/terminal.py +0 -0
- {relationalai → v0/relationalai}/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/graphs.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/benchmarks/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/path_algorithms/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/filter.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/glushkov.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/rpq/transition.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/__init__.py +0 -0
- {relationalai → v0/relationalai}/experimental/paths/utilities/utilities.py +0 -0
- {relationalai → v0/relationalai}/metagen.py +0 -0
- {relationalai → v0/relationalai}/metamodel.py +0 -0
- {relationalai → v0/relationalai}/rel.py +0 -0
- {relationalai → v0/relationalai}/semantics/devtools/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/internal/annotations.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/ir.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/pragmas.py +0 -0
- {relationalai → v0/relationalai}/semantics/lqp/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/dataflow.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/ir.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/typer/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/types.py +0 -0
- {relationalai → v0/relationalai}/semantics/metamodel/visitor.py +0 -0
- {relationalai → v0/relationalai}/semantics/reasoners/experimental/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/rel/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/executor/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/sql/rewrite/__init__.py +0 -0
- {relationalai → v0/relationalai}/semantics/tests/logging.py +0 -0
- {relationalai → v0/relationalai}/std/aggregates.py +0 -0
- {relationalai → v0/relationalai}/std/dates.py +0 -0
- {relationalai → v0/relationalai}/std/graphs.py +0 -0
- {relationalai → v0/relationalai}/std/inspect.py +0 -0
- {relationalai → v0/relationalai}/std/math.py +0 -0
- {relationalai → v0/relationalai}/std/re.py +0 -0
- {relationalai → v0/relationalai}/std/strings.py +0 -0
- {relationalai → v0/relationalai}/tools/cleanup_snapshots.py +0 -0
- {relationalai → v0/relationalai}/tools/constants.py +0 -0
- {relationalai → v0/relationalai}/tools/query_utils.py +0 -0
- {relationalai → v0/relationalai}/tools/snapshot_viewer.py +0 -0
- {relationalai → v0/relationalai}/util/__init__.py +0 -0
- {relationalai → v0/relationalai}/util/constants.py +0 -0
- {relationalai → v0/relationalai}/util/graph.py +0 -0
- {relationalai → v0/relationalai}/util/timeout.py +0 -0
|
@@ -1,1163 +0,0 @@
|
|
|
1
|
-
"""Solver model implementation using protobuf format.
|
|
2
|
-
|
|
3
|
-
This module provides the SolverModelPB class for defining optimization and
|
|
4
|
-
constraint programming problems that are serialized to protobuf format and
|
|
5
|
-
solved by external solver engines.
|
|
6
|
-
|
|
7
|
-
Note: This protobuf-based implementation will be deprecated in favor of the
|
|
8
|
-
development version (solvers_dev.py) in future releases.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from __future__ import annotations
|
|
12
|
-
|
|
13
|
-
import textwrap
|
|
14
|
-
import time
|
|
15
|
-
import uuid
|
|
16
|
-
from typing import Any, Optional
|
|
17
|
-
|
|
18
|
-
from relationalai.experimental.solvers import Solver
|
|
19
|
-
from relationalai.semantics.internal import internal as b
|
|
20
|
-
from relationalai.semantics.rel.executor import RelExecutor
|
|
21
|
-
from relationalai.tools.constants import DEFAULT_QUERY_TIMEOUT_MINS
|
|
22
|
-
from relationalai.util.timeout import calc_remaining_timeout_minutes
|
|
23
|
-
|
|
24
|
-
from .common import make_name
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# =============================================================================
|
|
28
|
-
# Solver ProtoBuf Format Constants and Helpers
|
|
29
|
-
# =============================================================================
|
|
30
|
-
|
|
31
|
-
# Variable type codes for the solver protobuf format
|
|
32
|
-
# cont: continuous (real-valued), int: integer, bin: binary (0/1)
|
|
33
|
-
_VARIABLE_TYPE_CODES: dict[str, int] = {
|
|
34
|
-
"cont": 40,
|
|
35
|
-
"int": 41,
|
|
36
|
-
"bin": 42,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
# First-order operators: arithmetic and mathematical functions
|
|
40
|
-
_FIRST_ORDER_OPERATOR_CODES: dict[str, int] = {
|
|
41
|
-
"+": 10,
|
|
42
|
-
"-": 11,
|
|
43
|
-
"*": 12,
|
|
44
|
-
"/": 13,
|
|
45
|
-
"^": 14,
|
|
46
|
-
"abs": 20,
|
|
47
|
-
"exp": 21,
|
|
48
|
-
"log": 22,
|
|
49
|
-
"range": 50,
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# First-order comparison operators: relational constraints
|
|
53
|
-
_FIRST_ORDER_COMPARISON_CODES: dict[str, int] = {
|
|
54
|
-
"=": 30,
|
|
55
|
-
"!=": 31,
|
|
56
|
-
"<=": 32,
|
|
57
|
-
">=": 33,
|
|
58
|
-
"<": 34,
|
|
59
|
-
">": 35,
|
|
60
|
-
"implies": 62,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
# Higher-order operators: aggregation and global constraints
|
|
64
|
-
_HIGHER_ORDER_OPERATOR_CODES: dict[str, int] = {
|
|
65
|
-
"sum": 80,
|
|
66
|
-
"min": 82,
|
|
67
|
-
"max": 83,
|
|
68
|
-
"count": 84,
|
|
69
|
-
"all_different": 90,
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
# Mapping from bound type keywords to comparison operators
|
|
73
|
-
_BOUND_TO_COMPARISON_OPERATOR: dict[str, str] = {
|
|
74
|
-
"lower": ">=",
|
|
75
|
-
"upper": "<=",
|
|
76
|
-
"fixed": "=",
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def _make_first_order_application_with_result(
|
|
81
|
-
operator_code: int, *args: Any
|
|
82
|
-
) -> b.Expression:
|
|
83
|
-
"""Create a first-order application with a result variable."""
|
|
84
|
-
return _make_first_order_application(operator_code, *args, b.String.ref("res"))
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _make_first_order_application(operator_code: int, *args: Any) -> b.Expression:
|
|
88
|
-
"""Create a first-order application expression."""
|
|
89
|
-
if not (2 <= len(args) <= 4):
|
|
90
|
-
raise ValueError(
|
|
91
|
-
f"First-order application requires 2-4 arguments, but got {len(args)}."
|
|
92
|
-
)
|
|
93
|
-
result_ref = args[-1]
|
|
94
|
-
if not isinstance(result_ref, b.Ref):
|
|
95
|
-
raise TypeError(
|
|
96
|
-
f"Last argument must be a Ref, got {type(result_ref).__name__}."
|
|
97
|
-
)
|
|
98
|
-
if result_ref._thing != b.String:
|
|
99
|
-
result_ref = b.String.ref("res")
|
|
100
|
-
application_builtin = b.Relationship.builtins["rel_primitive_solverlib_fo_appl"]
|
|
101
|
-
# Wrap operands in TupleArg for the vararg solverlib_fo_appl primitive:
|
|
102
|
-
# fo_appl(op, (operands...), result)
|
|
103
|
-
return b.Expression(
|
|
104
|
-
application_builtin, operator_code, b.TupleArg(args[:-1]), result_ref
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
# =============================================================================
|
|
109
|
-
# Main Solver Model Class
|
|
110
|
-
# =============================================================================
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
class SolverModelPB:
|
|
114
|
-
"""Solver model interface using protobuf format for optimization problems."""
|
|
115
|
-
|
|
116
|
-
def __init__(self, model: b.Model, num_type: str) -> None:
|
|
117
|
-
"""Initialize solver model.
|
|
118
|
-
|
|
119
|
-
Args:
|
|
120
|
-
model: The RelationalAI model.
|
|
121
|
-
num_type: Variable type - 'cont' or 'int'.
|
|
122
|
-
"""
|
|
123
|
-
if num_type not in ["cont", "int"]:
|
|
124
|
-
raise ValueError(
|
|
125
|
-
f"Invalid numerical type '{num_type}'. Must be 'cont' or 'int'."
|
|
126
|
-
)
|
|
127
|
-
self._model = model
|
|
128
|
-
self._num_type = num_type
|
|
129
|
-
self._id = next(b._global_id)
|
|
130
|
-
# Maps relationships to their corresponding variable concepts
|
|
131
|
-
self._variable_relationships: dict[b.Relationship, b.Concept] = {}
|
|
132
|
-
prefix_uppercase = f"SolverModel_{self._id}_"
|
|
133
|
-
prefix_lowercase = prefix_uppercase.lower()
|
|
134
|
-
|
|
135
|
-
# Create core concepts for model components
|
|
136
|
-
self.Variable = Variable = model.Concept(prefix_uppercase + "Variable")
|
|
137
|
-
self.MinObjective = model.Concept(prefix_uppercase + "MinObjective")
|
|
138
|
-
self.MaxObjective = model.Concept(prefix_uppercase + "MaxObjective")
|
|
139
|
-
self.Constraint = model.Concept(prefix_uppercase + "Constraint")
|
|
140
|
-
self._model_info = {
|
|
141
|
-
"num_variables": Variable,
|
|
142
|
-
"num_min_objectives": self.MinObjective,
|
|
143
|
-
"num_max_objectives": self.MaxObjective,
|
|
144
|
-
"num_constraints": self.Constraint,
|
|
145
|
-
}
|
|
146
|
-
# Add printed_expr property to objectives and constraints for human-readable output
|
|
147
|
-
for concept in [self.MinObjective, self.MaxObjective, self.Constraint]:
|
|
148
|
-
concept.printed_expr = model.Property(
|
|
149
|
-
f"{{{concept._name}}} has {{printed_expr:str}}"
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
# Create relationships for result extraction
|
|
153
|
-
result_type = "int" if num_type == "int" else "float"
|
|
154
|
-
self.result_info = model.Relationship(
|
|
155
|
-
"{key:str} has {value:str}", short_name=(prefix_lowercase + "result_info")
|
|
156
|
-
)
|
|
157
|
-
# TODO(coey) PyRel is not able to handle "Variable._name" instead of "var" below due
|
|
158
|
-
# to some internal naming bug; this leads to a "Unresolved Type" warning that we
|
|
159
|
-
# will have to live with for now
|
|
160
|
-
self.point = model.Property(
|
|
161
|
-
f"{{var}} has {{value:{result_type}}}",
|
|
162
|
-
short_name=(prefix_lowercase + "point"),
|
|
163
|
-
)
|
|
164
|
-
self.points = model.Property(
|
|
165
|
-
f"point {{i:int}} for {{var}} has {{value:{result_type}}}",
|
|
166
|
-
short_name=(prefix_lowercase + "points"),
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
# Install raw rel to work around lack of support for rel_primitive_solverlib_print_expr
|
|
170
|
-
install_rel = f"""
|
|
171
|
-
declare {self.MinObjective._name}
|
|
172
|
-
declare {self.MaxObjective._name}
|
|
173
|
-
declare {self.Constraint._name}
|
|
174
|
-
|
|
175
|
-
declare {prefix_lowercase}variable_name
|
|
176
|
-
declare {prefix_lowercase}minobjective_name
|
|
177
|
-
declare {prefix_lowercase}maxobjective_name
|
|
178
|
-
declare {prefix_lowercase}constraint_name
|
|
179
|
-
declare {prefix_lowercase}minobjective_serialized
|
|
180
|
-
declare {prefix_lowercase}maxobjective_serialized
|
|
181
|
-
declare {prefix_lowercase}constraint_serialized
|
|
182
|
-
|
|
183
|
-
def {prefix_lowercase}minobjective_printed_expr(h, s):
|
|
184
|
-
rel_primitive_solverlib_print_expr({prefix_lowercase}minobjective_serialized[h], {prefix_lowercase}variable_name, s)
|
|
185
|
-
|
|
186
|
-
def {prefix_lowercase}maxobjective_printed_expr(h, s):
|
|
187
|
-
rel_primitive_solverlib_print_expr({prefix_lowercase}maxobjective_serialized[h], {prefix_lowercase}variable_name, s)
|
|
188
|
-
|
|
189
|
-
def {prefix_lowercase}constraint_printed_expr(h, s):
|
|
190
|
-
rel_primitive_solverlib_print_expr({prefix_lowercase}constraint_serialized[h], {prefix_lowercase}variable_name, s)
|
|
191
|
-
"""
|
|
192
|
-
b.define(b.RawSource("rel", textwrap.dedent(install_rel)))
|
|
193
|
-
|
|
194
|
-
# -------------------------------------------------------------------------
|
|
195
|
-
# Variable Handling
|
|
196
|
-
# -------------------------------------------------------------------------
|
|
197
|
-
|
|
198
|
-
def solve_for(
|
|
199
|
-
self,
|
|
200
|
-
expr,
|
|
201
|
-
where: Optional[list[Any]] = None,
|
|
202
|
-
populate: bool = True,
|
|
203
|
-
**kwargs: Any,
|
|
204
|
-
) -> b.Concept:
|
|
205
|
-
"""Define decision variables.
|
|
206
|
-
|
|
207
|
-
Args:
|
|
208
|
-
expr: Relationship or expression defining variables.
|
|
209
|
-
where: Optional grounding conditions.
|
|
210
|
-
populate: Whether to populate relationship with solver results.
|
|
211
|
-
**kwargs: Optional properties (name, type, lower, upper, fixed).
|
|
212
|
-
|
|
213
|
-
Returns:
|
|
214
|
-
Variable concept.
|
|
215
|
-
"""
|
|
216
|
-
if where is None:
|
|
217
|
-
where = []
|
|
218
|
-
if isinstance(expr, b.Fragment):
|
|
219
|
-
# TODO(coey): Remove in future
|
|
220
|
-
raise ValueError(
|
|
221
|
-
"The select fragment argument to `solve_for` is deprecated. "
|
|
222
|
-
"Instead, use the `where = [conditions...]` kwarg to specify optional grounding conditions."
|
|
223
|
-
)
|
|
224
|
-
elif isinstance(expr, b.Expression):
|
|
225
|
-
relationship = expr._op
|
|
226
|
-
if not isinstance(relationship, b.Relationship):
|
|
227
|
-
raise TypeError(
|
|
228
|
-
f"Expression operator must be a Relationship, got {type(relationship).__name__}."
|
|
229
|
-
)
|
|
230
|
-
params = expr._params
|
|
231
|
-
elif isinstance(expr, b.Relationship):
|
|
232
|
-
relationship = expr
|
|
233
|
-
params = [
|
|
234
|
-
b.field_to_type(self._model, field) for field in relationship._fields
|
|
235
|
-
]
|
|
236
|
-
else:
|
|
237
|
-
raise TypeError(
|
|
238
|
-
f"Invalid expression type for solve_for: {type(expr).__name__}. "
|
|
239
|
-
f"Expected Relationship or Expression."
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
if len(params) != len(relationship._fields):
|
|
243
|
-
raise ValueError(
|
|
244
|
-
f"Parameter count mismatch: Got {len(params)} params "
|
|
245
|
-
f"but relationship has {len(relationship._fields)} fields."
|
|
246
|
-
)
|
|
247
|
-
if relationship in self._variable_relationships:
|
|
248
|
-
raise ValueError(
|
|
249
|
-
f"Variables are already defined for relationship {relationship}."
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
# Create a specialized Variable concept for this relationship
|
|
253
|
-
# Each decision variable gets its own concept subtype
|
|
254
|
-
Var = self._model.Concept(
|
|
255
|
-
f"{self.Variable._name}_{str(relationship).replace('.', '_')}",
|
|
256
|
-
extends=[self.Variable],
|
|
257
|
-
)
|
|
258
|
-
self._variable_relationships[relationship] = Var
|
|
259
|
-
|
|
260
|
-
# Build field dict from relationship parameters (excluding the value field)
|
|
261
|
-
fields = {}
|
|
262
|
-
for i in range(len(params) - 1):
|
|
263
|
-
if i == 0 and relationship._parent is not None:
|
|
264
|
-
concept = relationship._parent
|
|
265
|
-
if not isinstance(concept, b.Concept):
|
|
266
|
-
raise TypeError(
|
|
267
|
-
f"Relationship parent must be a Concept, got {type(concept).__name__}."
|
|
268
|
-
)
|
|
269
|
-
else:
|
|
270
|
-
concept = params[i]
|
|
271
|
-
field_name = relationship._field_names[i]
|
|
272
|
-
# Prevent "Implicit Subtype Relationship" warnings by explicitly registering
|
|
273
|
-
# the relationship on the parent Variable concept before using it on subtypes
|
|
274
|
-
self.Variable._relationships[field_name] = self.Variable._get_relationship(
|
|
275
|
-
field_name
|
|
276
|
-
)
|
|
277
|
-
fields[field_name] = concept
|
|
278
|
-
var = Var.new(**fields)
|
|
279
|
-
b.define(var).where(*where)
|
|
280
|
-
|
|
281
|
-
# Handle optional variable properties
|
|
282
|
-
for key, value in kwargs.items():
|
|
283
|
-
if key == "name":
|
|
284
|
-
definition = self.Variable.name(var, make_name(value))
|
|
285
|
-
elif key == "type":
|
|
286
|
-
if not isinstance(value, str):
|
|
287
|
-
raise TypeError(
|
|
288
|
-
f"Variable 'type' must be a string, but got {type(value).__name__}."
|
|
289
|
-
)
|
|
290
|
-
if value not in _VARIABLE_TYPE_CODES:
|
|
291
|
-
valid_types = ", ".join(_VARIABLE_TYPE_CODES.keys())
|
|
292
|
-
raise ValueError(
|
|
293
|
-
f"Invalid variable type '{value}'. Valid types are: {valid_types}."
|
|
294
|
-
)
|
|
295
|
-
serialized_expr = _make_first_order_application_with_result(
|
|
296
|
-
_VARIABLE_TYPE_CODES[value], var
|
|
297
|
-
)
|
|
298
|
-
definition = self.Constraint.new(serialized=serialized_expr)
|
|
299
|
-
elif key in ("lower", "upper", "fixed"):
|
|
300
|
-
if not isinstance(value, (b.Producer, float, int)):
|
|
301
|
-
raise TypeError(
|
|
302
|
-
f"Variable '{key}' must be a number, but got {type(value).__name__}."
|
|
303
|
-
)
|
|
304
|
-
# Map bound types to comparison operators
|
|
305
|
-
operator = _BOUND_TO_COMPARISON_OPERATOR[key]
|
|
306
|
-
serialized_expr = _make_first_order_application_with_result(
|
|
307
|
-
_FIRST_ORDER_COMPARISON_CODES[operator], var, value
|
|
308
|
-
)
|
|
309
|
-
definition = self.Constraint.new(serialized=serialized_expr)
|
|
310
|
-
else:
|
|
311
|
-
raise ValueError(f"Invalid keyword argument '{key}' for solve_for.")
|
|
312
|
-
b.define(definition).where(*where)
|
|
313
|
-
|
|
314
|
-
if populate:
|
|
315
|
-
# Automatically populate the variable relationship with solver results
|
|
316
|
-
# This defines the original relationship to pull values from self.point after solving
|
|
317
|
-
value_ref = (b.Integer if self._num_type == "int" else b.Float).ref()
|
|
318
|
-
b.define(
|
|
319
|
-
relationship(
|
|
320
|
-
*[getattr(Var, field_name) for field_name in fields], value_ref
|
|
321
|
-
)
|
|
322
|
-
).where(self.point(Var, value_ref))
|
|
323
|
-
|
|
324
|
-
return Var
|
|
325
|
-
|
|
326
|
-
# -------------------------------------------------------------------------
|
|
327
|
-
# Objective Functions
|
|
328
|
-
# -------------------------------------------------------------------------
|
|
329
|
-
|
|
330
|
-
def minimize(
|
|
331
|
-
self,
|
|
332
|
-
expr: b.Producer | float | int | b.Fragment,
|
|
333
|
-
name: Optional[str | list[str]] = None,
|
|
334
|
-
) -> None:
|
|
335
|
-
"""Add minimization objective.
|
|
336
|
-
|
|
337
|
-
Args:
|
|
338
|
-
expr: Expression to minimize.
|
|
339
|
-
name: Optional objective name.
|
|
340
|
-
"""
|
|
341
|
-
return self._add_objective(self.MinObjective, expr, name)
|
|
342
|
-
|
|
343
|
-
def maximize(
|
|
344
|
-
self,
|
|
345
|
-
expr: b.Producer | float | int | b.Fragment,
|
|
346
|
-
name: Optional[str | list[str]] = None,
|
|
347
|
-
) -> None:
|
|
348
|
-
"""Add maximization objective.
|
|
349
|
-
|
|
350
|
-
Args:
|
|
351
|
-
expr: Expression to maximize.
|
|
352
|
-
name: Optional objective name.
|
|
353
|
-
"""
|
|
354
|
-
return self._add_objective(self.MaxObjective, expr, name)
|
|
355
|
-
|
|
356
|
-
def _add_objective(
|
|
357
|
-
self,
|
|
358
|
-
objective_concept: b.Concept,
|
|
359
|
-
expr: b.Producer | float | int | b.Fragment,
|
|
360
|
-
name: Optional[str | list[str]],
|
|
361
|
-
) -> None:
|
|
362
|
-
context = SymbolifyContext(self)
|
|
363
|
-
symbolic_expr = context.rewrite(expr)
|
|
364
|
-
if not isinstance(symbolic_expr, Symbolic):
|
|
365
|
-
# Expr is not symbolic (a constant) - wrap it as a trivial expression
|
|
366
|
-
symbolic_expr = _make_first_order_application_with_result(0, expr)
|
|
367
|
-
else:
|
|
368
|
-
# Unwrap the symbolic expression
|
|
369
|
-
unwrapped_expr = symbolic_expr.expr
|
|
370
|
-
# Check if it's a bare variable (needs wrapping for protobuf)
|
|
371
|
-
is_bare_variable = isinstance(unwrapped_expr, b.ConceptMember)
|
|
372
|
-
is_fragment_with_variable = (
|
|
373
|
-
isinstance(unwrapped_expr, b.Fragment)
|
|
374
|
-
and unwrapped_expr._select
|
|
375
|
-
and isinstance(unwrapped_expr._select[0], b.ConceptMember)
|
|
376
|
-
)
|
|
377
|
-
if is_bare_variable or is_fragment_with_variable:
|
|
378
|
-
# The protobuf format requires all objectives to be expressions, not bare variables
|
|
379
|
-
symbolic_expr = _make_first_order_application_with_result(
|
|
380
|
-
0, unwrapped_expr
|
|
381
|
-
)
|
|
382
|
-
else:
|
|
383
|
-
symbolic_expr = unwrapped_expr
|
|
384
|
-
|
|
385
|
-
if isinstance(symbolic_expr, Symbolic):
|
|
386
|
-
raise ValueError(
|
|
387
|
-
"Internal error. Expression is still Symbolic after unwrapping."
|
|
388
|
-
)
|
|
389
|
-
|
|
390
|
-
objective = objective_concept.new(serialized=symbolic_expr)
|
|
391
|
-
definitions = [objective]
|
|
392
|
-
if name is not None:
|
|
393
|
-
definitions.append(objective.name(make_name(name)))
|
|
394
|
-
b.define(*definitions)
|
|
395
|
-
|
|
396
|
-
def satisfy(
|
|
397
|
-
self,
|
|
398
|
-
expr: b.Fragment,
|
|
399
|
-
check: bool = False,
|
|
400
|
-
name: Optional[str | list[str]] = None,
|
|
401
|
-
) -> None:
|
|
402
|
-
"""Add constraints.
|
|
403
|
-
|
|
404
|
-
Args:
|
|
405
|
-
expr: Fragment with require clause.
|
|
406
|
-
check: Whether to keep require in model validation.
|
|
407
|
-
name: Optional constraint name.
|
|
408
|
-
"""
|
|
409
|
-
if not isinstance(expr, b.Fragment):
|
|
410
|
-
raise TypeError(
|
|
411
|
-
f"The satisfy method expects a Fragment, but got {type(expr).__name__}."
|
|
412
|
-
)
|
|
413
|
-
if not expr._require:
|
|
414
|
-
raise ValueError("Fragment for satisfy must have a require clause.")
|
|
415
|
-
if expr._select or expr._define:
|
|
416
|
-
raise ValueError(
|
|
417
|
-
"Fragment for satisfy must not have select or define clauses."
|
|
418
|
-
)
|
|
419
|
-
if not check:
|
|
420
|
-
# Remove the `require` from the model roots so it is not checked as an integrity constraint
|
|
421
|
-
b._remove_roots([expr])
|
|
422
|
-
context = SymbolifyContext(self)
|
|
423
|
-
|
|
424
|
-
symbolic_where_clauses = context.rewrite_where(*expr._where)
|
|
425
|
-
definitions = []
|
|
426
|
-
for requirement in expr._require:
|
|
427
|
-
symbolic_requirement = context.rewrite(requirement)
|
|
428
|
-
if not isinstance(symbolic_requirement, Symbolic):
|
|
429
|
-
raise ValueError(
|
|
430
|
-
f"Cannot symbolify requirement {requirement} in satisfy. "
|
|
431
|
-
f"The requirement must contain solver variables or expressions."
|
|
432
|
-
)
|
|
433
|
-
constraint = self.Constraint.new(serialized=symbolic_requirement.expr)
|
|
434
|
-
definitions.append(constraint)
|
|
435
|
-
if name is not None:
|
|
436
|
-
definitions.append(constraint.name(make_name(name)))
|
|
437
|
-
b.define(*definitions).where(*symbolic_where_clauses)
|
|
438
|
-
|
|
439
|
-
# -------------------------------------------------------------------------
|
|
440
|
-
# Model Inspection and Display
|
|
441
|
-
# -------------------------------------------------------------------------
|
|
442
|
-
|
|
443
|
-
@staticmethod
|
|
444
|
-
def _print_dataframe(df: Any) -> None:
|
|
445
|
-
"""Print dataframe with consistent formatting for long strings."""
|
|
446
|
-
for row in df.itertuples(index=False):
|
|
447
|
-
print(" ".join(str(val) for val in row))
|
|
448
|
-
print()
|
|
449
|
-
|
|
450
|
-
def summarize(self) -> None:
|
|
451
|
-
"""Print counts of variables, objectives, and constraints in the model."""
|
|
452
|
-
counts_df = b.select(
|
|
453
|
-
*[(b.count(item) | 0) for (_, item) in self._model_info.items()]
|
|
454
|
-
).to_df()
|
|
455
|
-
if counts_df.shape != (1, 4):
|
|
456
|
-
raise ValueError("Unexpected counts dataframe shape.")
|
|
457
|
-
num_vars, num_min_objs, num_max_objs, num_constraints = counts_df.iloc[0]
|
|
458
|
-
print(
|
|
459
|
-
f"Solver model has {num_vars} variables, {num_min_objs} minimization objectives, {num_max_objs} maximization objectives, and {num_constraints} constraints."
|
|
460
|
-
)
|
|
461
|
-
|
|
462
|
-
def print(self, with_names: bool = False) -> None:
|
|
463
|
-
"""Print model components.
|
|
464
|
-
|
|
465
|
-
Args:
|
|
466
|
-
with_names: Whether to print expression string names (if available).
|
|
467
|
-
"""
|
|
468
|
-
# Print variables
|
|
469
|
-
var_df = b.select(self.Variable.name | "_").where(self.Variable).to_df()
|
|
470
|
-
if var_df.empty:
|
|
471
|
-
print("No variables defined.")
|
|
472
|
-
return
|
|
473
|
-
print("Solver model:")
|
|
474
|
-
print()
|
|
475
|
-
print(f"Variables ({var_df.shape[0]}):")
|
|
476
|
-
self._print_dataframe(var_df)
|
|
477
|
-
|
|
478
|
-
# Print components
|
|
479
|
-
components = [
|
|
480
|
-
(self.MinObjective, "Min objectives"),
|
|
481
|
-
(self.MaxObjective, "Max objectives"),
|
|
482
|
-
(self.Constraint, "Constraints"),
|
|
483
|
-
]
|
|
484
|
-
printed_expr_ref = b.String.ref()
|
|
485
|
-
for component_concept, component_label in components:
|
|
486
|
-
selection = (
|
|
487
|
-
[component_concept.name | "", printed_expr_ref]
|
|
488
|
-
if with_names
|
|
489
|
-
else [printed_expr_ref]
|
|
490
|
-
)
|
|
491
|
-
component_df = (
|
|
492
|
-
b.select(*selection)
|
|
493
|
-
.where(component_concept.printed_expr(printed_expr_ref))
|
|
494
|
-
.to_df()
|
|
495
|
-
)
|
|
496
|
-
if not component_df.empty:
|
|
497
|
-
print(f"{component_label} ({component_df.shape[0]}):")
|
|
498
|
-
self._print_dataframe(component_df)
|
|
499
|
-
|
|
500
|
-
# -------------------------------------------------------------------------
|
|
501
|
-
# Solving and Result Handling
|
|
502
|
-
# -------------------------------------------------------------------------
|
|
503
|
-
|
|
504
|
-
def solve(
|
|
505
|
-
self, solver: Solver, log_to_console: bool = False, **kwargs: Any
|
|
506
|
-
) -> None:
|
|
507
|
-
"""Solve the model.
|
|
508
|
-
|
|
509
|
-
Args:
|
|
510
|
-
solver: Solver instance.
|
|
511
|
-
log_to_console: Whether to show solver output.
|
|
512
|
-
**kwargs: Solver options and parameters.
|
|
513
|
-
"""
|
|
514
|
-
options = {**kwargs, "version": 1}
|
|
515
|
-
|
|
516
|
-
# Validate solver options
|
|
517
|
-
for option_key, option_value in options.items():
|
|
518
|
-
if not isinstance(option_key, str):
|
|
519
|
-
raise TypeError(
|
|
520
|
-
f"Solver option keys must be strings, but got {type(option_key).__name__} for key {option_key!r}."
|
|
521
|
-
)
|
|
522
|
-
if not isinstance(option_value, (int, float, str, bool)):
|
|
523
|
-
raise TypeError(
|
|
524
|
-
f"Solver option values must be int, float, str, or bool, "
|
|
525
|
-
f"but got {type(option_value).__name__} for option {option_key!r}."
|
|
526
|
-
)
|
|
527
|
-
|
|
528
|
-
# Three-phase solve process:
|
|
529
|
-
# 1. Export model to Snowflake as protobuf
|
|
530
|
-
# 2. Execute solver job (external solver reads from Snowflake)
|
|
531
|
-
# 3. Extract and load results back into the model
|
|
532
|
-
input_id = uuid.uuid4()
|
|
533
|
-
model_uri = f"snowflake://APP_STATE.RAI_INTERNAL_STAGE/job-inputs/solver/{input_id}/model.binpb"
|
|
534
|
-
sf_input_uri = f"snowflake://job-inputs/solver/{input_id}/model.binpb"
|
|
535
|
-
payload: dict[str, Any] = {"solver": solver.solver_name.lower()}
|
|
536
|
-
payload["options"] = options
|
|
537
|
-
payload["model_uri"] = sf_input_uri
|
|
538
|
-
|
|
539
|
-
executor = self._model._to_executor()
|
|
540
|
-
if not isinstance(executor, RelExecutor):
|
|
541
|
-
raise ValueError(f"Expected RelExecutor, got {type(executor).__name__}.")
|
|
542
|
-
prefix_lowercase = f"solvermodel_{self._id}_"
|
|
543
|
-
|
|
544
|
-
query_timeout_mins = kwargs.get("query_timeout_mins", None)
|
|
545
|
-
config = self._model._config
|
|
546
|
-
if (
|
|
547
|
-
query_timeout_mins is None
|
|
548
|
-
and (
|
|
549
|
-
timeout_value := config.get(
|
|
550
|
-
"query_timeout_mins", DEFAULT_QUERY_TIMEOUT_MINS
|
|
551
|
-
)
|
|
552
|
-
)
|
|
553
|
-
is not None
|
|
554
|
-
):
|
|
555
|
-
query_timeout_mins = int(timeout_value)
|
|
556
|
-
config_file_path = getattr(config, "file_path", None)
|
|
557
|
-
start_time = time.monotonic()
|
|
558
|
-
remaining_timeout_minutes = query_timeout_mins
|
|
559
|
-
|
|
560
|
-
# Step 1: Materialize the model and store it in Snowflake
|
|
561
|
-
print("export model")
|
|
562
|
-
# TODO(coey): Weird hack to avoid uninitialized properties error
|
|
563
|
-
# This forces evaluation of the Variable concept before export
|
|
564
|
-
b.select(b.count(self.Variable)).to_df()
|
|
565
|
-
export_model_relation = f"""
|
|
566
|
-
// TODO maybe only want to pass names if printing - like in old setup
|
|
567
|
-
// Collect all model components into a relation for serialization
|
|
568
|
-
def model_relation {{
|
|
569
|
-
(:variable, {self.Variable._name});
|
|
570
|
-
(:variable_name, {prefix_lowercase}variable_name);
|
|
571
|
-
(:min_objective, {prefix_lowercase}minobjective_serialized);
|
|
572
|
-
(:max_objective, {prefix_lowercase}maxobjective_serialized);
|
|
573
|
-
(:constraint, {prefix_lowercase}constraint_serialized);
|
|
574
|
-
}}
|
|
575
|
-
|
|
576
|
-
@no_diagnostics(:EXPERIMENTAL)
|
|
577
|
-
def model_string {{ rel_primitive_solverlib_model_string[model_relation] }}
|
|
578
|
-
|
|
579
|
-
ic model_not_empty("Solver model is empty.") requires not empty(model_string)
|
|
580
|
-
|
|
581
|
-
def config[:envelope, :content_type]: "application/octet-stream"
|
|
582
|
-
def config[:envelope, :payload, :data]: model_string
|
|
583
|
-
def config[:envelope, :payload, :path]: "{model_uri}"
|
|
584
|
-
def export {{ config }}
|
|
585
|
-
"""
|
|
586
|
-
executor.execute_raw(
|
|
587
|
-
textwrap.dedent(export_model_relation),
|
|
588
|
-
query_timeout_mins=remaining_timeout_minutes,
|
|
589
|
-
)
|
|
590
|
-
|
|
591
|
-
# Step 2: Execute solver job and wait for completion
|
|
592
|
-
print("execute solver job")
|
|
593
|
-
remaining_timeout_minutes = calc_remaining_timeout_minutes(
|
|
594
|
-
start_time,
|
|
595
|
-
query_timeout_mins,
|
|
596
|
-
config_file_path=config_file_path,
|
|
597
|
-
)
|
|
598
|
-
job_id = solver._exec_job(
|
|
599
|
-
payload,
|
|
600
|
-
log_to_console=log_to_console,
|
|
601
|
-
query_timeout_mins=remaining_timeout_minutes,
|
|
602
|
-
)
|
|
603
|
-
|
|
604
|
-
# Step 3: Extract and insert solver results into the model
|
|
605
|
-
print("extract result")
|
|
606
|
-
remaining_timeout_minutes = calc_remaining_timeout_minutes(
|
|
607
|
-
start_time,
|
|
608
|
-
query_timeout_mins,
|
|
609
|
-
config_file_path=config_file_path,
|
|
610
|
-
)
|
|
611
|
-
extract_results_relation = f"""
|
|
612
|
-
def raw_result {{
|
|
613
|
-
load_binary["snowflake://APP_STATE.RAI_INTERNAL_STAGE/job-results/{job_id}/result.binpb"]
|
|
614
|
-
}}
|
|
615
|
-
|
|
616
|
-
ic result_not_empty("Solver result is empty.") requires not empty(raw_result)
|
|
617
|
-
|
|
618
|
-
@no_diagnostics(:EXPERIMENTAL)
|
|
619
|
-
def extracted {{ rel_primitive_solverlib_extract[raw_result] }}
|
|
620
|
-
|
|
621
|
-
def delete[:{self.result_info._name}]: {self.result_info._name}
|
|
622
|
-
def delete[:{self.point._name}]: {self.point._name}
|
|
623
|
-
def delete[:{self.points._name}]: {self.points._name}
|
|
624
|
-
|
|
625
|
-
def insert(:{self.result_info._name}, key, value):
|
|
626
|
-
exists((original_key) | string(extracted[original_key], value) and ::std::mirror::lower(original_key, key))
|
|
627
|
-
"""
|
|
628
|
-
if self._num_type == "int":
|
|
629
|
-
insert_points_relation = f"""
|
|
630
|
-
def insert(:{self.point._name}, variable, value):
|
|
631
|
-
exists((float_value) | extracted(:point, variable, float_value) and
|
|
632
|
-
::std::mirror::convert(std::mirror::typeof[Int128], float_value, value)
|
|
633
|
-
)
|
|
634
|
-
def insert(:{self.points._name}, point_index, variable, value):
|
|
635
|
-
exists((float_index, float_value) | extracted(:points, variable, float_index, float_value) and
|
|
636
|
-
::std::mirror::convert(std::mirror::typeof[Int128], float_index, point_index) and
|
|
637
|
-
::std::mirror::convert(std::mirror::typeof[Int128], float_value, value)
|
|
638
|
-
)
|
|
639
|
-
"""
|
|
640
|
-
else:
|
|
641
|
-
insert_points_relation = f"""
|
|
642
|
-
def insert(:{self.point._name}, variable, value): extracted(:point, variable, value)
|
|
643
|
-
def insert(:{self.points._name}, point_index, variable, value):
|
|
644
|
-
exists((float_index) | extracted(:points, variable, float_index, value) and
|
|
645
|
-
::std::mirror::convert(std::mirror::typeof[Int128], float_index, point_index)
|
|
646
|
-
)
|
|
647
|
-
"""
|
|
648
|
-
executor.execute_raw(
|
|
649
|
-
textwrap.dedent(extract_results_relation)
|
|
650
|
-
+ textwrap.dedent(insert_points_relation),
|
|
651
|
-
readonly=False,
|
|
652
|
-
query_timeout_mins=remaining_timeout_minutes,
|
|
653
|
-
)
|
|
654
|
-
|
|
655
|
-
print("finished solve")
|
|
656
|
-
print()
|
|
657
|
-
|
|
658
|
-
def load_point(self, point_index: int) -> None:
|
|
659
|
-
"""Load a solution point.
|
|
660
|
-
|
|
661
|
-
Args:
|
|
662
|
-
point_index: Solution point index (0-based).
|
|
663
|
-
"""
|
|
664
|
-
if not isinstance(point_index, int):
|
|
665
|
-
raise TypeError(
|
|
666
|
-
f"Point index must be an integer, but got {type(point_index).__name__}."
|
|
667
|
-
)
|
|
668
|
-
if point_index < 0:
|
|
669
|
-
raise ValueError(
|
|
670
|
-
f"Point index must be non-negative, but got {point_index}."
|
|
671
|
-
)
|
|
672
|
-
executor = self._model._to_executor()
|
|
673
|
-
if not isinstance(executor, RelExecutor):
|
|
674
|
-
raise ValueError(
|
|
675
|
-
f"Expected RelExecutor, but got {type(executor).__name__}."
|
|
676
|
-
)
|
|
677
|
-
load_point_relation = f"""
|
|
678
|
-
def delete[:{self.point._name}]: {self.point._name}
|
|
679
|
-
def insert(:{self.point._name}, variable, value): {self.points._name}(int128[{point_index}], variable, value)
|
|
680
|
-
"""
|
|
681
|
-
executor.execute_raw(textwrap.dedent(load_point_relation), readonly=False)
|
|
682
|
-
|
|
683
|
-
def summarize_result(self) -> Any:
|
|
684
|
-
"""Print solver result summary.
|
|
685
|
-
|
|
686
|
-
Returns:
|
|
687
|
-
DataFrame with result information.
|
|
688
|
-
"""
|
|
689
|
-
info_keys_to_retrieve = [
|
|
690
|
-
"error",
|
|
691
|
-
"termination_status",
|
|
692
|
-
"solve_time_sec",
|
|
693
|
-
"objective_value",
|
|
694
|
-
"solver_version",
|
|
695
|
-
"result_count",
|
|
696
|
-
]
|
|
697
|
-
key, value_ref = b.String.ref(), b.String.ref()
|
|
698
|
-
result_df = (
|
|
699
|
-
b.select(key, value_ref)
|
|
700
|
-
.where(self.result_info(key, value_ref), key.in_(info_keys_to_retrieve))
|
|
701
|
-
.to_df()
|
|
702
|
-
)
|
|
703
|
-
if result_df.empty:
|
|
704
|
-
raise ValueError(
|
|
705
|
-
"No result information is available. Has the model been solved?"
|
|
706
|
-
)
|
|
707
|
-
print("Solver result:")
|
|
708
|
-
print(result_df.to_string(index=False, header=False))
|
|
709
|
-
print()
|
|
710
|
-
return result_df
|
|
711
|
-
|
|
712
|
-
def variable_values(self, multiple: bool = False) -> b.Fragment:
|
|
713
|
-
"""Retrieve variable values.
|
|
714
|
-
|
|
715
|
-
Args:
|
|
716
|
-
multiple: Whether to return all solution points.
|
|
717
|
-
|
|
718
|
-
Returns:
|
|
719
|
-
Fragment for selecting values.
|
|
720
|
-
"""
|
|
721
|
-
variable_ref = self.Variable.ref()
|
|
722
|
-
value_ref = (b.Integer if self._num_type == "int" else b.Float).ref()
|
|
723
|
-
if multiple:
|
|
724
|
-
point_index = b.Integer.ref()
|
|
725
|
-
return b.select(point_index, variable_ref.name, value_ref).where(
|
|
726
|
-
self.points(point_index, variable_ref, value_ref)
|
|
727
|
-
)
|
|
728
|
-
return b.select(variable_ref.name, value_ref).where(
|
|
729
|
-
self.point(variable_ref, value_ref)
|
|
730
|
-
)
|
|
731
|
-
|
|
732
|
-
# Valid result info keys that can be accessed as attributes
|
|
733
|
-
_RESULT_INFO_KEYS = frozenset(
|
|
734
|
-
[
|
|
735
|
-
"error",
|
|
736
|
-
"termination_status",
|
|
737
|
-
"solver_version",
|
|
738
|
-
"printed_model",
|
|
739
|
-
"solve_time_sec",
|
|
740
|
-
"objective_value",
|
|
741
|
-
"result_count",
|
|
742
|
-
]
|
|
743
|
-
)
|
|
744
|
-
|
|
745
|
-
def __getattr__(self, name: str) -> Any:
|
|
746
|
-
"""Get result attribute (e.g., num_variables, termination_status, objective_value).
|
|
747
|
-
|
|
748
|
-
Args:
|
|
749
|
-
name: Attribute name.
|
|
750
|
-
|
|
751
|
-
Returns:
|
|
752
|
-
Attribute value or None.
|
|
753
|
-
"""
|
|
754
|
-
# Try to get dataframe from model info or result info
|
|
755
|
-
if name in self._model_info:
|
|
756
|
-
result_df = b.select(b.count(self._model_info[name]) | 0).to_df()
|
|
757
|
-
elif name in self._RESULT_INFO_KEYS:
|
|
758
|
-
value_ref = b.String.ref()
|
|
759
|
-
result_df = (
|
|
760
|
-
b.select(value_ref).where(self.result_info(name, value_ref)).to_df()
|
|
761
|
-
)
|
|
762
|
-
else:
|
|
763
|
-
return None
|
|
764
|
-
|
|
765
|
-
# Extract and convert scalar value
|
|
766
|
-
if result_df.shape != (1, 1):
|
|
767
|
-
raise ValueError(
|
|
768
|
-
f"Expected exactly one value for attribute '{name}', "
|
|
769
|
-
f"but got dataframe with shape {result_df.shape}."
|
|
770
|
-
)
|
|
771
|
-
|
|
772
|
-
result_value = result_df.iloc[0, 0]
|
|
773
|
-
if not isinstance(result_value, str):
|
|
774
|
-
return result_value
|
|
775
|
-
|
|
776
|
-
# Convert string results to appropriate types
|
|
777
|
-
if name == "solve_time_sec":
|
|
778
|
-
return float(result_value)
|
|
779
|
-
if name == "objective_value":
|
|
780
|
-
return int(result_value) if self._num_type == "int" else float(result_value)
|
|
781
|
-
if name == "result_count":
|
|
782
|
-
return int(result_value)
|
|
783
|
-
return result_value
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
# =============================================================================
|
|
787
|
-
# Symbolic Expression Classes
|
|
788
|
-
# =============================================================================
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
class Symbolic:
|
|
792
|
-
"""Wrapper for symbolified solver expressions."""
|
|
793
|
-
|
|
794
|
-
def __init__(self, expr: Any) -> None:
|
|
795
|
-
if isinstance(expr, Symbolic):
|
|
796
|
-
raise TypeError("Cannot wrap a Symbolic expression in another Symbolic.")
|
|
797
|
-
self.expr = expr
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
class SymbolifyContext:
|
|
801
|
-
"""Context for rewriting expressions into solver-compatible symbolic form."""
|
|
802
|
-
|
|
803
|
-
def __init__(self, solver_model: SolverModelPB) -> None:
|
|
804
|
-
self.model = solver_model._model
|
|
805
|
-
self.solver_model = solver_model
|
|
806
|
-
# Maps original variables (or refs) to symbolic variables bound in where clauses
|
|
807
|
-
self.variable_map: dict[Any, Any] = {}
|
|
808
|
-
|
|
809
|
-
# -------------------------------------------------------------------------
|
|
810
|
-
# Public Rewriting Methods
|
|
811
|
-
# -------------------------------------------------------------------------
|
|
812
|
-
|
|
813
|
-
def rewrite_where(self, *exprs: Any) -> list[Any]:
|
|
814
|
-
"""Rewrite where clause expressions.
|
|
815
|
-
|
|
816
|
-
Args:
|
|
817
|
-
*exprs: Where clause expressions.
|
|
818
|
-
|
|
819
|
-
Returns:
|
|
820
|
-
Rewritten expressions.
|
|
821
|
-
"""
|
|
822
|
-
rewritten_expressions: list[Any] = []
|
|
823
|
-
# Two-pass strategy: first handle variable relationships to populate variable_map,
|
|
824
|
-
# then rewrite other expressions that may reference those variables
|
|
825
|
-
# First pass: identify and handle variable relationship expressions
|
|
826
|
-
for expression in exprs:
|
|
827
|
-
if (
|
|
828
|
-
isinstance(expression, b.Expression)
|
|
829
|
-
and isinstance(expression._op, b.Relationship)
|
|
830
|
-
and expression._op in self.solver_model._variable_relationships
|
|
831
|
-
):
|
|
832
|
-
rewritten_expressions.append(
|
|
833
|
-
self._handle_variable_relationship(expression)
|
|
834
|
-
)
|
|
835
|
-
else:
|
|
836
|
-
rewritten_expressions.append(None)
|
|
837
|
-
# Second pass: rewrite remaining non-variable expressions
|
|
838
|
-
for i, expr in enumerate(exprs):
|
|
839
|
-
if rewritten_expressions[i] is None:
|
|
840
|
-
rewritten_expressions[i] = (
|
|
841
|
-
expr
|
|
842
|
-
if expr in self.variable_map
|
|
843
|
-
else self._rewrite_nonsymbolic(expr)
|
|
844
|
-
)
|
|
845
|
-
return rewritten_expressions
|
|
846
|
-
|
|
847
|
-
def rewrite(self, expr: Any) -> Optional[Symbolic | Any]:
|
|
848
|
-
"""Rewrite expressions to symbolify solver variables."""
|
|
849
|
-
if expr is None:
|
|
850
|
-
return None
|
|
851
|
-
|
|
852
|
-
elif isinstance(expr, (int, float, str)):
|
|
853
|
-
return None
|
|
854
|
-
|
|
855
|
-
elif isinstance(expr, b.ConceptFilter):
|
|
856
|
-
concept = expr._op
|
|
857
|
-
assert isinstance(concept, b.Concept)
|
|
858
|
-
(ident, kwargs) = expr._params
|
|
859
|
-
assert ident is None
|
|
860
|
-
assert isinstance(kwargs, dict)
|
|
861
|
-
new_kwargs = {}
|
|
862
|
-
values_were_rewritten = False
|
|
863
|
-
for key, value in kwargs.items():
|
|
864
|
-
rewritten_value = self.rewrite(value)
|
|
865
|
-
if isinstance(rewritten_value, Symbolic):
|
|
866
|
-
raise ValueError(
|
|
867
|
-
f"Cannot symbolify ConceptFilter argument {key} with symbolic value."
|
|
868
|
-
)
|
|
869
|
-
if rewritten_value is not None:
|
|
870
|
-
values_were_rewritten = True
|
|
871
|
-
new_kwargs[key] = rewritten_value
|
|
872
|
-
else:
|
|
873
|
-
new_kwargs[key] = value
|
|
874
|
-
if values_were_rewritten:
|
|
875
|
-
return b.ConceptFilter(concept, ident, new_kwargs)
|
|
876
|
-
return None
|
|
877
|
-
|
|
878
|
-
elif isinstance(expr, (b.DataColumn, b.TypeRef, b.Concept)):
|
|
879
|
-
return None
|
|
880
|
-
|
|
881
|
-
elif isinstance(expr, b.Alias):
|
|
882
|
-
return self.rewrite(expr._thing)
|
|
883
|
-
|
|
884
|
-
elif isinstance(expr, b.Ref):
|
|
885
|
-
if expr in self.variable_map:
|
|
886
|
-
return Symbolic(self.variable_map[expr])
|
|
887
|
-
thing = self.rewrite(expr._thing)
|
|
888
|
-
if thing is not None:
|
|
889
|
-
raise ValueError(
|
|
890
|
-
f"Internal error. Ref._thing rewrite unexpectedly returned {thing}."
|
|
891
|
-
)
|
|
892
|
-
return None
|
|
893
|
-
|
|
894
|
-
elif isinstance(expr, b.Relationship):
|
|
895
|
-
if expr in self.variable_map:
|
|
896
|
-
return Symbolic(self.variable_map[expr])
|
|
897
|
-
variable_result = self._get_variable_ref(expr, expr._parent)
|
|
898
|
-
if variable_result is not None:
|
|
899
|
-
self.variable_map[expr] = variable_result
|
|
900
|
-
return Symbolic(variable_result)
|
|
901
|
-
return None
|
|
902
|
-
|
|
903
|
-
elif isinstance(expr, b.RelationshipRef):
|
|
904
|
-
if expr in self.variable_map:
|
|
905
|
-
return Symbolic(self.variable_map[expr])
|
|
906
|
-
relationship = expr._relationship
|
|
907
|
-
if isinstance(relationship, b.Relationship):
|
|
908
|
-
variable_result = self._get_variable_ref(relationship, expr._parent)
|
|
909
|
-
if variable_result is not None:
|
|
910
|
-
self.variable_map[expr] = variable_result
|
|
911
|
-
return Symbolic(variable_result)
|
|
912
|
-
rewritten_parent = self.rewrite(expr._parent)
|
|
913
|
-
if isinstance(rewritten_parent, Symbolic):
|
|
914
|
-
raise ValueError(
|
|
915
|
-
"Internal error. RelationshipRef parent rewrite returned Symbolic."
|
|
916
|
-
)
|
|
917
|
-
if rewritten_parent is not None:
|
|
918
|
-
return b.RelationshipRef(rewritten_parent, relationship)
|
|
919
|
-
return None
|
|
920
|
-
|
|
921
|
-
elif isinstance(expr, b.RelationshipFieldRef):
|
|
922
|
-
relationship = expr._relationship
|
|
923
|
-
if not isinstance(relationship, b.Relationship):
|
|
924
|
-
# TODO(coey): Handle relationship:RelationshipReading
|
|
925
|
-
return None
|
|
926
|
-
|
|
927
|
-
# Rewrite the relationship reference
|
|
928
|
-
relationship_expression = (
|
|
929
|
-
relationship
|
|
930
|
-
if expr._parent is None
|
|
931
|
-
else b.RelationshipRef(expr._parent, relationship)
|
|
932
|
-
)
|
|
933
|
-
variable_result = self.rewrite(relationship_expression)
|
|
934
|
-
if variable_result is None:
|
|
935
|
-
return None
|
|
936
|
-
|
|
937
|
-
# Handle symbolic result - return as-is if it's the last field
|
|
938
|
-
if isinstance(variable_result, Symbolic):
|
|
939
|
-
if expr._field_ix == len(relationship._fields) - 1:
|
|
940
|
-
return variable_result
|
|
941
|
-
variable_result = variable_result.expr
|
|
942
|
-
|
|
943
|
-
return getattr(variable_result, relationship._field_names[expr._field_ix])
|
|
944
|
-
|
|
945
|
-
elif isinstance(expr, b.Expression):
|
|
946
|
-
operator = self.rewrite(expr._op)
|
|
947
|
-
if isinstance(operator, Symbolic):
|
|
948
|
-
raise ValueError(
|
|
949
|
-
"Internal error: Expression operator rewrite returned Symbolic."
|
|
950
|
-
)
|
|
951
|
-
params_were_rewritten = False
|
|
952
|
-
has_symbolic_params = False
|
|
953
|
-
params = []
|
|
954
|
-
for param in expr._params:
|
|
955
|
-
rewritten_param = self.rewrite(param)
|
|
956
|
-
if isinstance(rewritten_param, Symbolic):
|
|
957
|
-
has_symbolic_params = True
|
|
958
|
-
params_were_rewritten = True
|
|
959
|
-
params.append(rewritten_param.expr)
|
|
960
|
-
elif rewritten_param is not None:
|
|
961
|
-
params_were_rewritten = True
|
|
962
|
-
params.append(rewritten_param)
|
|
963
|
-
else:
|
|
964
|
-
params.append(param)
|
|
965
|
-
if operator is not None:
|
|
966
|
-
if has_symbolic_params:
|
|
967
|
-
raise NotImplementedError(
|
|
968
|
-
f"Solver rewrites cannot handle expression {expr} "
|
|
969
|
-
f"with both a symbolic operator and symbolic parameters."
|
|
970
|
-
)
|
|
971
|
-
return b.Expression(operator, *params)
|
|
972
|
-
if not has_symbolic_params:
|
|
973
|
-
return b.Expression(expr._op, *params)
|
|
974
|
-
if not params_were_rewritten:
|
|
975
|
-
return None
|
|
976
|
-
|
|
977
|
-
# Some arguments involve solver variables, so rewrite into solver protobuf format
|
|
978
|
-
# This converts operations like x + y into fo_appl(ADD_OP, (x, y), res)
|
|
979
|
-
if not has_symbolic_params:
|
|
980
|
-
raise ValueError(
|
|
981
|
-
"Internal error. Expected symbolic parameters but none were found."
|
|
982
|
-
)
|
|
983
|
-
if not isinstance(expr._op, b.Relationship):
|
|
984
|
-
raise NotImplementedError(
|
|
985
|
-
f"Solver rewrites cannot handle expression {expr} "
|
|
986
|
-
f"with operator type {type(expr._op).__name__}."
|
|
987
|
-
)
|
|
988
|
-
operator_name = expr._op._name
|
|
989
|
-
if not isinstance(operator_name, str):
|
|
990
|
-
raise ValueError(
|
|
991
|
-
f"Internal error. Operator name is {type(operator_name).__name__}, expected str."
|
|
992
|
-
)
|
|
993
|
-
if operator_name in _FIRST_ORDER_OPERATOR_CODES:
|
|
994
|
-
return Symbolic(
|
|
995
|
-
_make_first_order_application(
|
|
996
|
-
_FIRST_ORDER_OPERATOR_CODES[operator_name], *params
|
|
997
|
-
)
|
|
998
|
-
)
|
|
999
|
-
elif operator_name in _FIRST_ORDER_COMPARISON_CODES:
|
|
1000
|
-
return Symbolic(
|
|
1001
|
-
_make_first_order_application_with_result(
|
|
1002
|
-
_FIRST_ORDER_COMPARISON_CODES[operator_name], *params
|
|
1003
|
-
)
|
|
1004
|
-
)
|
|
1005
|
-
else:
|
|
1006
|
-
raise NotImplementedError(
|
|
1007
|
-
f"Solver rewrites cannot handle operator '{operator_name}'."
|
|
1008
|
-
)
|
|
1009
|
-
|
|
1010
|
-
elif isinstance(expr, b.Aggregate):
|
|
1011
|
-
# Only the last argument can be symbolic
|
|
1012
|
-
preceding_args = [self._rewrite_nonsymbolic(arg) for arg in expr._args[:-1]]
|
|
1013
|
-
group = [self._rewrite_nonsymbolic(arg) for arg in expr._group]
|
|
1014
|
-
# TODO(coey): Should this be done with a subcontext (for variable_map)?
|
|
1015
|
-
where = self.rewrite_where(*expr._where._where)
|
|
1016
|
-
rewritten = (
|
|
1017
|
-
preceding_args != expr._args[:-1]
|
|
1018
|
-
or group != expr._group
|
|
1019
|
-
or where != expr._where
|
|
1020
|
-
)
|
|
1021
|
-
symbolic_arg = self.rewrite(expr._args[-1])
|
|
1022
|
-
if symbolic_arg is None and not rewritten:
|
|
1023
|
-
return None
|
|
1024
|
-
if not isinstance(symbolic_arg, Symbolic):
|
|
1025
|
-
if symbolic_arg is None:
|
|
1026
|
-
symbolic_arg = expr._args[-1]
|
|
1027
|
-
aggregate_expr = b.Aggregate(expr._op, *preceding_args, symbolic_arg)
|
|
1028
|
-
return aggregate_expr.per(*group).where(*where)
|
|
1029
|
-
|
|
1030
|
-
# The last argument is symbolic - convert to higher-order application
|
|
1031
|
-
# Example: sum(x for x in variables) becomes ho_appl(..., x, SUM_OP)
|
|
1032
|
-
operator_name = expr._op._name
|
|
1033
|
-
if not isinstance(operator_name, str):
|
|
1034
|
-
raise ValueError(
|
|
1035
|
-
f"Internal error. Aggregate operator name is {type(operator_name).__name__}, expected str."
|
|
1036
|
-
)
|
|
1037
|
-
if operator_name not in _HIGHER_ORDER_OPERATOR_CODES:
|
|
1038
|
-
raise NotImplementedError(
|
|
1039
|
-
f"Solver rewrites cannot handle aggregate operator '{operator_name}'. "
|
|
1040
|
-
f"Supported operators: {', '.join(_HIGHER_ORDER_OPERATOR_CODES.keys())}"
|
|
1041
|
-
)
|
|
1042
|
-
higher_order_application_builtin = b.Relationship.builtins[
|
|
1043
|
-
"rel_primitive_solverlib_ho_appl"
|
|
1044
|
-
]
|
|
1045
|
-
aggregate_expr = b.Aggregate(
|
|
1046
|
-
higher_order_application_builtin,
|
|
1047
|
-
*preceding_args,
|
|
1048
|
-
symbolic_arg.expr,
|
|
1049
|
-
_HIGHER_ORDER_OPERATOR_CODES[operator_name],
|
|
1050
|
-
)
|
|
1051
|
-
return Symbolic(aggregate_expr.per(*group).where(*where))
|
|
1052
|
-
|
|
1053
|
-
elif isinstance(expr, b.Union):
|
|
1054
|
-
# Return union of the symbolified expressions, if any are symbolic
|
|
1055
|
-
args_were_rewritten = False
|
|
1056
|
-
has_symbolic_args = False
|
|
1057
|
-
args = []
|
|
1058
|
-
for union_arg in expr._args:
|
|
1059
|
-
rewritten_arg = self.rewrite(union_arg)
|
|
1060
|
-
if isinstance(rewritten_arg, Symbolic):
|
|
1061
|
-
has_symbolic_args = True
|
|
1062
|
-
args.append(rewritten_arg.expr)
|
|
1063
|
-
elif rewritten_arg is not None:
|
|
1064
|
-
args_were_rewritten = True
|
|
1065
|
-
args.append(rewritten_arg)
|
|
1066
|
-
else:
|
|
1067
|
-
args.append(union_arg)
|
|
1068
|
-
if has_symbolic_args:
|
|
1069
|
-
return Symbolic(b.union(*args))
|
|
1070
|
-
elif args_were_rewritten:
|
|
1071
|
-
return b.union(*args)
|
|
1072
|
-
return None
|
|
1073
|
-
|
|
1074
|
-
elif isinstance(expr, b.Fragment):
|
|
1075
|
-
# Only support selects with one item
|
|
1076
|
-
if expr._define or expr._require:
|
|
1077
|
-
raise ValueError(
|
|
1078
|
-
"Solver rewrites do not support fragments with define or require clauses."
|
|
1079
|
-
)
|
|
1080
|
-
if len(expr._select) != 1:
|
|
1081
|
-
raise ValueError(
|
|
1082
|
-
f"Solver rewrites require fragments with exactly one select item, "
|
|
1083
|
-
f"but got {len(expr._select)}."
|
|
1084
|
-
)
|
|
1085
|
-
# TODO(coey): Should this be done with a subcontext (for variable_map)?
|
|
1086
|
-
where = self.rewrite_where(*expr._where)
|
|
1087
|
-
symbolic_select = self.rewrite(expr._select[0])
|
|
1088
|
-
if isinstance(symbolic_select, Symbolic):
|
|
1089
|
-
return Symbolic(b.select(symbolic_select.expr).where(*where))
|
|
1090
|
-
elif symbolic_select is not None:
|
|
1091
|
-
return b.select(symbolic_select).where(*where)
|
|
1092
|
-
return None
|
|
1093
|
-
|
|
1094
|
-
raise NotImplementedError(
|
|
1095
|
-
f"Solver rewrites cannot handle {expr} of type {type(expr).__name__}."
|
|
1096
|
-
)
|
|
1097
|
-
|
|
1098
|
-
# -------------------------------------------------------------------------
|
|
1099
|
-
# Private Helper Methods
|
|
1100
|
-
# -------------------------------------------------------------------------
|
|
1101
|
-
|
|
1102
|
-
def _handle_variable_relationship(self, expr: b.Expression) -> Any:
|
|
1103
|
-
"""Create symbolic reference for variable relationship expression."""
|
|
1104
|
-
relationship = expr._op
|
|
1105
|
-
if not isinstance(relationship, b.Relationship):
|
|
1106
|
-
raise TypeError(
|
|
1107
|
-
f"Expected Relationship in variable expression, but got {type(relationship).__name__}."
|
|
1108
|
-
)
|
|
1109
|
-
params = expr._params
|
|
1110
|
-
if len(params) != len(relationship._fields):
|
|
1111
|
-
raise ValueError(
|
|
1112
|
-
f"Parameter count mismatch: Got {len(params)} params "
|
|
1113
|
-
f"but relationship has {len(relationship._fields)} fields."
|
|
1114
|
-
)
|
|
1115
|
-
last_param = params[-1]
|
|
1116
|
-
if isinstance(last_param, b.Alias):
|
|
1117
|
-
last_param = last_param._thing
|
|
1118
|
-
if not isinstance(last_param, (b.Concept, b.Ref)):
|
|
1119
|
-
raise TypeError(
|
|
1120
|
-
f"Last parameter must be a Concept or Ref, but got {type(last_param).__name__}."
|
|
1121
|
-
)
|
|
1122
|
-
# Extract and rewrite field parameters to build the symbolic variable reference
|
|
1123
|
-
# This maps the relationship fields to their grounding values
|
|
1124
|
-
fields = {}
|
|
1125
|
-
for i in range(len(params) - 1):
|
|
1126
|
-
rewritten_param = self.rewrite(params[i])
|
|
1127
|
-
assert not isinstance(rewritten_param, Symbolic)
|
|
1128
|
-
fields[relationship._field_names[i]] = (
|
|
1129
|
-
rewritten_param if rewritten_param is not None else params[i]
|
|
1130
|
-
)
|
|
1131
|
-
# Create new ref corresponding to the decision variable
|
|
1132
|
-
variable_ref = self.solver_model._variable_relationships[relationship].ref()
|
|
1133
|
-
self.variable_map[last_param] = variable_ref
|
|
1134
|
-
# Return new condition to ground the variable
|
|
1135
|
-
return b.where(
|
|
1136
|
-
*[
|
|
1137
|
-
getattr(variable_ref, field_name) == field_value
|
|
1138
|
-
for field_name, field_value in fields.items()
|
|
1139
|
-
]
|
|
1140
|
-
)
|
|
1141
|
-
|
|
1142
|
-
def _rewrite_nonsymbolic(self, expr: Any) -> Any:
|
|
1143
|
-
"""Rewrite expression ensuring non-symbolic result."""
|
|
1144
|
-
new_expr = self.rewrite(expr)
|
|
1145
|
-
if isinstance(new_expr, Symbolic):
|
|
1146
|
-
raise ValueError(
|
|
1147
|
-
f"Internal error. Non-symbolic rewrite unexpectedly returned Symbolic for {expr}."
|
|
1148
|
-
)
|
|
1149
|
-
return expr if new_expr is None else new_expr
|
|
1150
|
-
|
|
1151
|
-
def _get_variable_ref(
|
|
1152
|
-
self, relationship: b.Relationship, parent_producer: b.Producer | None
|
|
1153
|
-
) -> Optional[Any]:
|
|
1154
|
-
"""Get variable reference for relationship, or None if not a solver variable."""
|
|
1155
|
-
# Check if this relationship corresponds to a decision variable
|
|
1156
|
-
VariableConcept = self.solver_model._variable_relationships.get(relationship)
|
|
1157
|
-
if VariableConcept is None:
|
|
1158
|
-
return None
|
|
1159
|
-
|
|
1160
|
-
properties = {}
|
|
1161
|
-
if parent_producer is not None:
|
|
1162
|
-
properties[relationship._field_names[0]] = parent_producer
|
|
1163
|
-
return VariableConcept(VariableConcept.ref(), **properties)
|