solverforge 0.6.11__tar.gz → 0.6.13__tar.gz
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.
- {solverforge-0.6.11 → solverforge-0.6.13}/Cargo.lock +13 -13
- {solverforge-0.6.11 → solverforge-0.6.13}/Cargo.toml +8 -8
- {solverforge-0.6.11 → solverforge-0.6.13}/PKG-INFO +7 -7
- {solverforge-0.6.11 → solverforge-0.6.13}/README.md +6 -6
- {solverforge-0.6.11 → solverforge-0.6.13}/pyproject.toml +1 -1
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/__init__.py +1 -1
- {solverforge-0.6.11 → solverforge-0.6.13}/src/runtime/dynamic_assignment_group.rs +102 -8
- {solverforge-0.6.11 → solverforge-0.6.13}/src/state/entity_table.rs +14 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/state/marshal.rs +56 -1
- {solverforge-0.6.11 → solverforge-0.6.13}/LICENSE +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/_native.pyi +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/config.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/console.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/constraints.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/decorators.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/errors.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/events.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/fields.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/groups.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/joiner.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/manager.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/model.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/py.typed +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/score.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/solver.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/typing.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/python/solverforge/ui.py +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/rust-toolchain.toml +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/bindings.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/callbacks/call.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/callbacks/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/callbacks/registry.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/callbacks/threading.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/config.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/compiled.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/evaluate.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/incremental.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/list_precedence.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/matches.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/state.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/constraints/stream_plan.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/descriptor/extractor.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/descriptor/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/descriptor/variable.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/error.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/intern.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/lib.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/manager/candidate_trace.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/manager/events.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/manager/jobs.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/manager/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/manager/provenance.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/proxy/entity.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/proxy/list.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/proxy/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/proxy/solution.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/runtime/candidate_metric.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/runtime/dynamic_provider.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/runtime/list_slots.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/runtime/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/runtime/scalar_slots.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/build.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/compiled.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/parse.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/python.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/runtime_plan.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/types.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/schema/validate.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/score.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/solver/api.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/solver/console.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/solver/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/solver/progress.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/solver/result.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/solver/solvable.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/state/callback_view.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/state/clone.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/state/mod.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/state/solution.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/state/variables.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/ui.rs +0 -0
- {solverforge-0.6.11 → solverforge-0.6.13}/src/value.rs +0 -0
|
@@ -560,9 +560,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
|
|
560
560
|
|
|
561
561
|
[[package]]
|
|
562
562
|
name = "solverforge-bridge"
|
|
563
|
-
version = "0.21.
|
|
563
|
+
version = "0.21.2"
|
|
564
564
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
565
|
-
checksum = "
|
|
565
|
+
checksum = "902722a303b437c7f7e732689e481b38eb6dae0dd374b363316795fb89092d5d"
|
|
566
566
|
dependencies = [
|
|
567
567
|
"solverforge-config",
|
|
568
568
|
"solverforge-core",
|
|
@@ -572,9 +572,9 @@ dependencies = [
|
|
|
572
572
|
|
|
573
573
|
[[package]]
|
|
574
574
|
name = "solverforge-config"
|
|
575
|
-
version = "0.21.
|
|
575
|
+
version = "0.21.2"
|
|
576
576
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
577
|
-
checksum = "
|
|
577
|
+
checksum = "568ae0b66de1bef05e790c47c803a39327281b59fbf4533293ee74282e92ff31"
|
|
578
578
|
dependencies = [
|
|
579
579
|
"serde",
|
|
580
580
|
"serde_yaml",
|
|
@@ -585,9 +585,9 @@ dependencies = [
|
|
|
585
585
|
|
|
586
586
|
[[package]]
|
|
587
587
|
name = "solverforge-console"
|
|
588
|
-
version = "0.21.
|
|
588
|
+
version = "0.21.2"
|
|
589
589
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
590
|
-
checksum = "
|
|
590
|
+
checksum = "5e83d2e0c4841e96df6cd7b6d7fbf1d1e4ad789dd487e1204d9c10c8592467da"
|
|
591
591
|
dependencies = [
|
|
592
592
|
"num-format",
|
|
593
593
|
"owo-colors",
|
|
@@ -597,18 +597,18 @@ dependencies = [
|
|
|
597
597
|
|
|
598
598
|
[[package]]
|
|
599
599
|
name = "solverforge-core"
|
|
600
|
-
version = "0.21.
|
|
600
|
+
version = "0.21.2"
|
|
601
601
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
602
|
-
checksum = "
|
|
602
|
+
checksum = "ec8da3bca3eeac0b6128bcb44caa602b8736ef4a588dcfcebe3f74a23bf0babd"
|
|
603
603
|
dependencies = [
|
|
604
604
|
"thiserror",
|
|
605
605
|
]
|
|
606
606
|
|
|
607
607
|
[[package]]
|
|
608
608
|
name = "solverforge-scoring"
|
|
609
|
-
version = "0.21.
|
|
609
|
+
version = "0.21.2"
|
|
610
610
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
611
|
-
checksum = "
|
|
611
|
+
checksum = "b4266a1b7d20c279e3710501c00f3dbfab3224c2208c09e02365fb622d67b3f7"
|
|
612
612
|
dependencies = [
|
|
613
613
|
"solverforge-core",
|
|
614
614
|
"thiserror",
|
|
@@ -616,9 +616,9 @@ dependencies = [
|
|
|
616
616
|
|
|
617
617
|
[[package]]
|
|
618
618
|
name = "solverforge-solver"
|
|
619
|
-
version = "0.21.
|
|
619
|
+
version = "0.21.2"
|
|
620
620
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
621
|
-
checksum = "
|
|
621
|
+
checksum = "88c84d58da872039900e9deb3191338a5c45f8d983ed3e6690b1de1c96cd3a81"
|
|
622
622
|
dependencies = [
|
|
623
623
|
"rand",
|
|
624
624
|
"rand_chacha",
|
|
@@ -644,7 +644,7 @@ dependencies = [
|
|
|
644
644
|
|
|
645
645
|
[[package]]
|
|
646
646
|
name = "solverforge_py"
|
|
647
|
-
version = "0.6.
|
|
647
|
+
version = "0.6.13"
|
|
648
648
|
dependencies = [
|
|
649
649
|
"indexmap",
|
|
650
650
|
"once_cell",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "solverforge_py"
|
|
3
|
-
version = "0.6.
|
|
3
|
+
version = "0.6.13"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
rust-version = "1.95"
|
|
@@ -26,7 +26,7 @@ name = "solverforge_py"
|
|
|
26
26
|
crate-type = ["cdylib", "rlib"]
|
|
27
27
|
|
|
28
28
|
[package.metadata.solverforge]
|
|
29
|
-
version = "0.21.
|
|
29
|
+
version = "0.21.2"
|
|
30
30
|
|
|
31
31
|
[dependencies]
|
|
32
32
|
indexmap = "2.12.1"
|
|
@@ -42,12 +42,12 @@ toml = "0.9.8"
|
|
|
42
42
|
tracing = "0.1.44"
|
|
43
43
|
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
|
|
44
44
|
|
|
45
|
-
solverforge-config = { version = "=0.21.
|
|
46
|
-
solverforge-bridge = { version = "=0.21.
|
|
47
|
-
solverforge-console = { version = "=0.21.
|
|
48
|
-
solverforge-core = { version = "=0.21.
|
|
49
|
-
solverforge-scoring = { version = "=0.21.
|
|
50
|
-
solverforge-solver = { version = "=0.21.
|
|
45
|
+
solverforge-config = { version = "=0.21.2" }
|
|
46
|
+
solverforge-bridge = { version = "=0.21.2" }
|
|
47
|
+
solverforge-console = { version = "=0.21.2", features = ["verbose-logging"] }
|
|
48
|
+
solverforge-core = { version = "=0.21.2" }
|
|
49
|
+
solverforge-scoring = { version = "=0.21.2" }
|
|
50
|
+
solverforge-solver = { version = "=0.21.2" }
|
|
51
51
|
solverforge-ui = { version = "=0.9.0", default-features = false }
|
|
52
52
|
|
|
53
53
|
[dev-dependencies]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: solverforge
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.13
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -40,7 +40,7 @@ clone, mutate, and snapshot solutions safely. Python callbacks are the single
|
|
|
40
40
|
constraint authoring surface.
|
|
41
41
|
|
|
42
42
|
The package targets CPython 3.14 and Rust 1.95.0. This release-preparation
|
|
43
|
-
checkout pins the six published SolverForge Rust dependencies to `0.21.
|
|
43
|
+
checkout pins the six published SolverForge Rust dependencies to `0.21.2` and
|
|
44
44
|
`solverforge-ui` to `0.9.0` through exact crates.io requirements in
|
|
45
45
|
`Cargo.toml` and registry checksums in `Cargo.lock`. There is no local path or
|
|
46
46
|
Git dependency override. The `solverforge` `0.6.x` line is the current dynamic
|
|
@@ -51,12 +51,12 @@ requirements, and other APIs that are not part of this package.
|
|
|
51
51
|
|
|
52
52
|
## Installation
|
|
53
53
|
|
|
54
|
-
The package version prepared by this checkout is `solverforge` `0.6.
|
|
55
|
-
the published and registry-locked SolverForge Rust `0.21.
|
|
54
|
+
The package version prepared by this checkout is `solverforge` `0.6.13`, targeting
|
|
55
|
+
the published and registry-locked SolverForge Rust `0.21.2` dependency base.
|
|
56
56
|
Install the matching package after its Python release with:
|
|
57
57
|
|
|
58
58
|
```sh
|
|
59
|
-
python3.14 -m pip install "solverforge==0.6.
|
|
59
|
+
python3.14 -m pip install "solverforge==0.6.13"
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
The installable wheel contains the core `solverforge` package, native extension,
|
|
@@ -76,12 +76,12 @@ make deliveries-run PORT=7861
|
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
The same source-checkout examples can be run against the matching published
|
|
79
|
-
package once `0.6.
|
|
79
|
+
package once `0.6.13` is released, without `PYTHONPATH` or an editable checkout:
|
|
80
80
|
|
|
81
81
|
```sh
|
|
82
82
|
python3.14 -m venv .venv-examples
|
|
83
83
|
. .venv-examples/bin/activate
|
|
84
|
-
python -m pip install "solverforge[examples]==0.6.
|
|
84
|
+
python -m pip install "solverforge[examples]==0.6.13"
|
|
85
85
|
python examples/nqueens.py
|
|
86
86
|
python -m examples.solverforge_hospital
|
|
87
87
|
python -m examples.solverforge_deliveries
|
|
@@ -9,7 +9,7 @@ clone, mutate, and snapshot solutions safely. Python callbacks are the single
|
|
|
9
9
|
constraint authoring surface.
|
|
10
10
|
|
|
11
11
|
The package targets CPython 3.14 and Rust 1.95.0. This release-preparation
|
|
12
|
-
checkout pins the six published SolverForge Rust dependencies to `0.21.
|
|
12
|
+
checkout pins the six published SolverForge Rust dependencies to `0.21.2` and
|
|
13
13
|
`solverforge-ui` to `0.9.0` through exact crates.io requirements in
|
|
14
14
|
`Cargo.toml` and registry checksums in `Cargo.lock`. There is no local path or
|
|
15
15
|
Git dependency override. The `solverforge` `0.6.x` line is the current dynamic
|
|
@@ -20,12 +20,12 @@ requirements, and other APIs that are not part of this package.
|
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
23
|
-
The package version prepared by this checkout is `solverforge` `0.6.
|
|
24
|
-
the published and registry-locked SolverForge Rust `0.21.
|
|
23
|
+
The package version prepared by this checkout is `solverforge` `0.6.13`, targeting
|
|
24
|
+
the published and registry-locked SolverForge Rust `0.21.2` dependency base.
|
|
25
25
|
Install the matching package after its Python release with:
|
|
26
26
|
|
|
27
27
|
```sh
|
|
28
|
-
python3.14 -m pip install "solverforge==0.6.
|
|
28
|
+
python3.14 -m pip install "solverforge==0.6.13"
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
The installable wheel contains the core `solverforge` package, native extension,
|
|
@@ -45,12 +45,12 @@ make deliveries-run PORT=7861
|
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
The same source-checkout examples can be run against the matching published
|
|
48
|
-
package once `0.6.
|
|
48
|
+
package once `0.6.13` is released, without `PYTHONPATH` or an editable checkout:
|
|
49
49
|
|
|
50
50
|
```sh
|
|
51
51
|
python3.14 -m venv .venv-examples
|
|
52
52
|
. .venv-examples/bin/activate
|
|
53
|
-
python -m pip install "solverforge[examples]==0.6.
|
|
53
|
+
python -m pip install "solverforge[examples]==0.6.13"
|
|
54
54
|
python examples/nqueens.py
|
|
55
55
|
python -m examples.solverforge_hospital
|
|
56
56
|
python -m examples.solverforge_deliveries
|
|
@@ -123,7 +123,6 @@ fn build_assignment_group(
|
|
|
123
123
|
let metadata = Arc::new(PyDynamicAssignmentMetadata {
|
|
124
124
|
schema,
|
|
125
125
|
group_index,
|
|
126
|
-
entity_index,
|
|
127
126
|
});
|
|
128
127
|
Ok(ScalarGroupBinding::dynamic_assignment(
|
|
129
128
|
intern(group.name.clone()),
|
|
@@ -146,7 +145,6 @@ fn scalar_group_limits(group: &AssignmentScalarGroupSchema) -> ScalarGroupLimits
|
|
|
146
145
|
struct PyDynamicAssignmentMetadata {
|
|
147
146
|
schema: Arc<DynamicSchema>,
|
|
148
147
|
group_index: usize,
|
|
149
|
-
entity_index: usize,
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
impl PyDynamicAssignmentMetadata {
|
|
@@ -182,10 +180,16 @@ impl PyDynamicAssignmentMetadata {
|
|
|
182
180
|
};
|
|
183
181
|
solution
|
|
184
182
|
.state
|
|
185
|
-
.
|
|
186
|
-
.get(self.
|
|
183
|
+
.assignment_group_fields
|
|
184
|
+
.get(self.group_index)
|
|
187
185
|
.and_then(|rows| rows.get(entity_index))
|
|
188
|
-
.and_then(|
|
|
186
|
+
.and_then(|fields| match hook_name {
|
|
187
|
+
"required_entity" => fields.required_entity.as_ref(),
|
|
188
|
+
"capacity_key" => fields.capacity_key.as_ref(),
|
|
189
|
+
"position_key" => fields.position_key.as_ref(),
|
|
190
|
+
"sequence_key" => fields.sequence_key.as_ref(),
|
|
191
|
+
_ => unreachable!("assignment metadata source resolved"),
|
|
192
|
+
})
|
|
189
193
|
.map(Some)
|
|
190
194
|
.ok_or_else(|| {
|
|
191
195
|
py_err(format!(
|
|
@@ -420,10 +424,10 @@ impl PyDynamicAssignmentMetadata {
|
|
|
420
424
|
) -> PyResult<bool> {
|
|
421
425
|
let value = solution
|
|
422
426
|
.state
|
|
423
|
-
.
|
|
424
|
-
.get(self.
|
|
427
|
+
.assignment_group_fields
|
|
428
|
+
.get(self.group_index)
|
|
425
429
|
.and_then(|rows| rows.get(entity_index))
|
|
426
|
-
.and_then(|
|
|
430
|
+
.and_then(|fields| fields.same_value_conflicts.as_ref())
|
|
427
431
|
.ok_or_else(|| {
|
|
428
432
|
py_err(format!(
|
|
429
433
|
"assignment scalar group `{}` field `{field_name}` is missing on row {entity_index}",
|
|
@@ -547,3 +551,93 @@ fn indexed_usize(field_value: &DynamicValue, candidate_value: usize) -> PyResult
|
|
|
547
551
|
)),
|
|
548
552
|
}
|
|
549
553
|
}
|
|
554
|
+
|
|
555
|
+
#[cfg(test)]
|
|
556
|
+
mod tests {
|
|
557
|
+
use pyo3::ffi::c_str;
|
|
558
|
+
|
|
559
|
+
use super::*;
|
|
560
|
+
use crate::schema::parse::parse_schema;
|
|
561
|
+
use crate::schema::runtime_plan::CompiledRuntimePlan;
|
|
562
|
+
use crate::state::callback_view::PythonCallbackView;
|
|
563
|
+
use crate::state::entity_table::{AssignmentRowFields, DynamicEntityRow, DynamicState};
|
|
564
|
+
|
|
565
|
+
#[test]
|
|
566
|
+
fn assignment_access_uses_imported_slots_not_named_row_fields() {
|
|
567
|
+
Python::initialize();
|
|
568
|
+
Python::attach(|py| {
|
|
569
|
+
let raw = py
|
|
570
|
+
.eval(
|
|
571
|
+
c_str!(
|
|
572
|
+
r#"{
|
|
573
|
+
'solution_type': 'Plan', 'score_family': 'hard_soft',
|
|
574
|
+
'entities': [{'type_name': 'Task', 'collection': 'tasks', 'fields': [
|
|
575
|
+
{'name': 'value', 'kind': 'planning_variable', 'allows_unassigned': True}
|
|
576
|
+
]}],
|
|
577
|
+
'constraints': [], 'conflict_repairs': [], 'candidate_metrics': [],
|
|
578
|
+
'scalar_groups': [{'kind': 'assignment', 'name': 'assign',
|
|
579
|
+
'entity_class': 'Task', 'variable_name': 'value',
|
|
580
|
+
'required_entity_field': 'required', 'capacity_key_field': 'capacity',
|
|
581
|
+
'position_key_field': 'position', 'sequence_key_field': 'sequence',
|
|
582
|
+
'same_value_conflict_field': 'conflicts'}]
|
|
583
|
+
}"#
|
|
584
|
+
),
|
|
585
|
+
None,
|
|
586
|
+
None,
|
|
587
|
+
)
|
|
588
|
+
.unwrap();
|
|
589
|
+
let schema = Arc::new(parse_schema(raw.cast().unwrap()).unwrap());
|
|
590
|
+
let plan = Arc::new(CompiledRuntimePlan::from_schema(Arc::clone(&schema)).unwrap());
|
|
591
|
+
let metadata = PyDynamicAssignmentMetadata {
|
|
592
|
+
schema,
|
|
593
|
+
group_index: 0,
|
|
594
|
+
};
|
|
595
|
+
let state = DynamicState {
|
|
596
|
+
entities: vec![vec![DynamicEntityRow::default(); 2]],
|
|
597
|
+
assignment_group_fields: Arc::new(vec![vec![
|
|
598
|
+
AssignmentRowFields {
|
|
599
|
+
required_entity: Some(DynamicValue::Bool(true)),
|
|
600
|
+
capacity_key: Some(DynamicValue::List(vec![
|
|
601
|
+
DynamicValue::Int(7),
|
|
602
|
+
DynamicValue::None,
|
|
603
|
+
])),
|
|
604
|
+
position_key: Some(DynamicValue::Int(13)),
|
|
605
|
+
sequence_key: Some(DynamicValue::Int(5)),
|
|
606
|
+
same_value_conflicts: Some(DynamicValue::List(vec![DynamicValue::Int(1)])),
|
|
607
|
+
},
|
|
608
|
+
AssignmentRowFields {
|
|
609
|
+
required_entity: Some(DynamicValue::Bool(false)),
|
|
610
|
+
same_value_conflicts: Some(DynamicValue::List(Vec::new())),
|
|
611
|
+
..AssignmentRowFields::default()
|
|
612
|
+
},
|
|
613
|
+
]]),
|
|
614
|
+
..DynamicState::default()
|
|
615
|
+
};
|
|
616
|
+
let solution = PyDynamicSolution::from_runtime_plan(
|
|
617
|
+
plan,
|
|
618
|
+
state,
|
|
619
|
+
PythonCallbackView::default(),
|
|
620
|
+
None,
|
|
621
|
+
SolverConfig::default(),
|
|
622
|
+
0,
|
|
623
|
+
);
|
|
624
|
+
let cloned = solution.clone();
|
|
625
|
+
assert!(Arc::ptr_eq(
|
|
626
|
+
&solution.state.assignment_group_fields,
|
|
627
|
+
&cloned.state.assignment_group_fields
|
|
628
|
+
));
|
|
629
|
+
for state in [&solution, &cloned] {
|
|
630
|
+
assert!(state.state.entities[0][0].fields.is_empty());
|
|
631
|
+
assert!(metadata.required_entity(state, 0));
|
|
632
|
+
assert!(!metadata.required_entity(state, 1));
|
|
633
|
+
assert_eq!(metadata.capacity_key(state, 0, 0), Some(7));
|
|
634
|
+
assert_eq!(metadata.capacity_key(state, 0, 1), None);
|
|
635
|
+
assert_eq!(metadata.position_key(state, 0), Some(13));
|
|
636
|
+
assert_eq!(metadata.sequence_key(state, 0, 0), Some(5));
|
|
637
|
+
assert!(!metadata.assignment_edge_allowed(state, 0, 0, 1, 0));
|
|
638
|
+
assert!(!metadata.assignment_edge_allowed(state, 1, 0, 0, 0));
|
|
639
|
+
assert!(metadata.assignment_edge_allowed(state, 0, 0, 1, 1));
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
@@ -3,6 +3,19 @@ use std::sync::Arc;
|
|
|
3
3
|
|
|
4
4
|
use crate::value::DynamicValue;
|
|
5
5
|
|
|
6
|
+
/// Immutable assignment row sources, resolved by group and hook once at import.
|
|
7
|
+
/// State clones share these values; planning-variable changes never rewrite them.
|
|
8
|
+
pub type AssignmentGroupFields = Vec<Vec<AssignmentRowFields>>;
|
|
9
|
+
|
|
10
|
+
#[derive(Debug, Clone, Default)]
|
|
11
|
+
pub struct AssignmentRowFields {
|
|
12
|
+
pub required_entity: Option<DynamicValue>,
|
|
13
|
+
pub capacity_key: Option<DynamicValue>,
|
|
14
|
+
pub position_key: Option<DynamicValue>,
|
|
15
|
+
pub sequence_key: Option<DynamicValue>,
|
|
16
|
+
pub same_value_conflicts: Option<DynamicValue>,
|
|
17
|
+
}
|
|
18
|
+
|
|
6
19
|
#[derive(Debug, Clone, Default)]
|
|
7
20
|
pub struct DynamicState {
|
|
8
21
|
pub entities: Vec<Vec<DynamicEntityRow>>,
|
|
@@ -10,6 +23,7 @@ pub struct DynamicState {
|
|
|
10
23
|
pub scalar_value_ranges: Vec<Vec<Option<Arc<[usize]>>>>,
|
|
11
24
|
pub list_elements: Vec<Vec<Option<Arc<[usize]>>>>,
|
|
12
25
|
pub solution_fields: Arc<BTreeMap<String, DynamicValue>>,
|
|
26
|
+
pub assignment_group_fields: Arc<AssignmentGroupFields>,
|
|
13
27
|
}
|
|
14
28
|
|
|
15
29
|
impl DynamicState {
|
|
@@ -12,7 +12,9 @@ use crate::schema::types::{
|
|
|
12
12
|
};
|
|
13
13
|
use crate::schema::DynamicSchema;
|
|
14
14
|
use crate::state::callback_view::PythonCallbackView;
|
|
15
|
-
use crate::state::entity_table::{
|
|
15
|
+
use crate::state::entity_table::{
|
|
16
|
+
AssignmentGroupFields, AssignmentRowFields, DynamicEntityRow, DynamicState,
|
|
17
|
+
};
|
|
16
18
|
use crate::state::PyDynamicSolution;
|
|
17
19
|
use crate::value::DynamicValue;
|
|
18
20
|
|
|
@@ -148,6 +150,7 @@ pub fn import_solution(
|
|
|
148
150
|
fact_objects.push(objects);
|
|
149
151
|
}
|
|
150
152
|
validate_assignment_group_field_metadata(schema, &entity_tables)?;
|
|
153
|
+
let assignment_group_fields = resolve_assignment_group_fields(schema, &entity_tables)?;
|
|
151
154
|
validate_list_element_metadata_field_sources(
|
|
152
155
|
schema,
|
|
153
156
|
&entity_tables,
|
|
@@ -163,6 +166,7 @@ pub fn import_solution(
|
|
|
163
166
|
scalar_value_ranges,
|
|
164
167
|
list_elements,
|
|
165
168
|
solution_fields: Arc::new(solution_fields),
|
|
169
|
+
assignment_group_fields: Arc::new(assignment_group_fields),
|
|
166
170
|
},
|
|
167
171
|
PythonCallbackView::from_import(
|
|
168
172
|
py_solution.clone().unbind(),
|
|
@@ -484,6 +488,57 @@ fn collect_list_metadata_row_fields(
|
|
|
484
488
|
}
|
|
485
489
|
}
|
|
486
490
|
|
|
491
|
+
fn resolve_assignment_group_fields(
|
|
492
|
+
schema: &DynamicSchema,
|
|
493
|
+
entity_tables: &[Vec<DynamicEntityRow>],
|
|
494
|
+
) -> PyResult<AssignmentGroupFields> {
|
|
495
|
+
schema
|
|
496
|
+
.assignment_scalar_groups
|
|
497
|
+
.iter()
|
|
498
|
+
.map(|group| {
|
|
499
|
+
let entity_index = schema
|
|
500
|
+
.entity_index_by_type(&group.entity_class)
|
|
501
|
+
.expect("assignment group entity validated");
|
|
502
|
+
let fields = [
|
|
503
|
+
group
|
|
504
|
+
.required_entity
|
|
505
|
+
.as_ref()
|
|
506
|
+
.and_then(MetadataSourceSchema::row),
|
|
507
|
+
group
|
|
508
|
+
.capacity_key
|
|
509
|
+
.as_ref()
|
|
510
|
+
.and_then(MetadataSourceSchema::row),
|
|
511
|
+
group
|
|
512
|
+
.position_key
|
|
513
|
+
.as_ref()
|
|
514
|
+
.and_then(MetadataSourceSchema::row),
|
|
515
|
+
group
|
|
516
|
+
.sequence_key
|
|
517
|
+
.as_ref()
|
|
518
|
+
.and_then(MetadataSourceSchema::row),
|
|
519
|
+
group.same_value_conflict_field.as_deref(),
|
|
520
|
+
];
|
|
521
|
+
entity_tables[entity_index]
|
|
522
|
+
.iter()
|
|
523
|
+
.enumerate()
|
|
524
|
+
.map(|(row_index, row)| {
|
|
525
|
+
let mut resolved = std::array::from_fn(|_| None);
|
|
526
|
+
for (index, field) in fields.iter().enumerate() {
|
|
527
|
+
if let Some(field) = field {
|
|
528
|
+
resolved[index] = Some(
|
|
529
|
+
assignment_metadata_field(row, &group.name, row_index, field)?
|
|
530
|
+
.clone(),
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
let [required_entity, capacity_key, position_key, sequence_key, same_value_conflicts] = resolved;
|
|
535
|
+
Ok(AssignmentRowFields { required_entity, capacity_key, position_key, sequence_key, same_value_conflicts })
|
|
536
|
+
})
|
|
537
|
+
.collect()
|
|
538
|
+
})
|
|
539
|
+
.collect()
|
|
540
|
+
}
|
|
541
|
+
|
|
487
542
|
fn validate_assignment_group_field_metadata(
|
|
488
543
|
schema: &DynamicSchema,
|
|
489
544
|
entity_tables: &[Vec<DynamicEntityRow>],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|