Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions crates/solverforge-core/WIREFRAME.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ src/
├── domain/
│ ├── mod.rs — Module declarations and re-exports for domain types
│ ├── traits.rs — PlanningSolution, PlanningEntity, ProblemFact, PlanningId, ListVariableSolution
│ ├── entity_ref.rs — EntityRef, EntityExtractor trait, TypedEntityExtractor
│ ├── entity_ref.rs — EntityRef, EntityExtractor trait, EntityCollectionExtractor
│ ├── variable.rs — VariableType, ShadowVariableKind, ValueRangeType, ChainedVariableInfo
│ ├── value_range.rs — ValueRangeProvider trait, FieldValueRangeProvider, ComputedValueRangeProvider, StaticValueRange, IntegerRange
│ ├── descriptor/
Expand All @@ -65,7 +65,7 @@ src/
│ │ └── tests.rs — Supply tests (inverse, anchor, list_state)
│ └── tests/
│ ├── mod.rs — Test module declarations
│ ├── entity_ref_tests.rs — TypedEntityExtractor tests
│ ├── entity_ref_tests.rs — EntityCollectionExtractor tests
│ ├── value_range_tests.rs — ValueRangeProvider tests
│ └── variable_tests.rs — VariableType, ShadowVariableKind, ChainedVariableInfo tests
```
Expand Down Expand Up @@ -318,10 +318,10 @@ pub struct EntityRef {

Derives: `Debug, Clone`

#### `TypedEntityExtractor<S, E>`
#### `EntityCollectionExtractor<S, E>`

```rust
pub struct TypedEntityExtractor<S, E> {
pub struct EntityCollectionExtractor<S, E> {
type_name: &'static str, // private
collection_field: &'static str, // private
get_collection: fn(&S) -> &Vec<E>, // private
Expand Down Expand Up @@ -606,7 +606,7 @@ All three supply types (InverseSupply, AnchorSupply, ListStateSupply) follow str

### EntityExtractor as Intentional dyn Boundary

`EntityExtractor` is a `dyn` trait object — this is an **intentional type-erasure boundary**. Descriptors need to work with entities of unknown concrete type at runtime. The `TypedEntityExtractor<S, E>` provides the concrete implementation that downcasts via `Any`. `Box<dyn EntityExtractor>` appears in `EntityDescriptor` and `ProblemFactDescriptor`.
`EntityExtractor` is a `dyn` trait object — this is an **intentional type-erasure boundary**. Descriptors need to work with entities of unknown concrete type at runtime. The `EntityCollectionExtractor<S, E>` provides the concrete implementation that downcasts via `Any`. `Box<dyn EntityExtractor>` appears in `EntityDescriptor` and `ProblemFactDescriptor`.

### PhantomData Pattern

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::any::TypeId;

#[test]
fn test_with_extractor() {
let extractor = Box::new(TypedEntityExtractor::new(
let extractor = Box::new(EntityCollectionExtractor::new(
"TestEntity",
"entities",
get_entities,
Expand Down
4 changes: 2 additions & 2 deletions crates/solverforge-core/src/domain/descriptor/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod solution_descriptor;
mod variable_descriptor;

use crate::domain::descriptor::*;
use crate::domain::TypedEntityExtractor;
use crate::domain::EntityCollectionExtractor;
use std::any::Any;

// Shared test helpers used across descriptor test modules.
Expand All @@ -30,7 +30,7 @@ pub(super) fn get_entities_mut(s: &mut TestSolution) -> &mut Vec<TestEntity> {
}

pub(super) fn create_test_entity_descriptor() -> EntityDescriptor {
let extractor = Box::new(TypedEntityExtractor::new(
let extractor = Box::new(EntityCollectionExtractor::new(
"TestEntity",
"entities",
get_entities,
Expand Down
10 changes: 5 additions & 5 deletions crates/solverforge-core/src/domain/entity_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl Clone for Box<dyn EntityExtractor> {
/// # Type Parameters
/// * `S` - The solution type
/// * `E` - The entity type
pub struct TypedEntityExtractor<S, E> {
pub struct EntityCollectionExtractor<S, E> {
// Name of the entity type.
type_name: &'static str,
// Name of the collection field in the solution.
Expand All @@ -85,7 +85,7 @@ pub struct TypedEntityExtractor<S, E> {
get_collection_mut: fn(&mut S) -> &mut Vec<E>,
}

impl<S, E> TypedEntityExtractor<S, E>
impl<S, E> EntityCollectionExtractor<S, E>
where
S: 'static,
E: 'static,
Expand All @@ -105,7 +105,7 @@ where
}
}

impl<S, E> EntityExtractor for TypedEntityExtractor<S, E>
impl<S, E> EntityExtractor for EntityCollectionExtractor<S, E>
where
S: Send + Sync + 'static,
E: Clone + Send + Sync + 'static,
Expand Down Expand Up @@ -162,9 +162,9 @@ where
}
}

impl<S, E> Debug for TypedEntityExtractor<S, E> {
impl<S, E> Debug for EntityCollectionExtractor<S, E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TypedEntityExtractor")
f.debug_struct("EntityCollectionExtractor")
.field("type_name", &self.type_name)
.field("collection_field", &self.collection_field)
.finish()
Expand Down
2 changes: 1 addition & 1 deletion crates/solverforge-core/src/domain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use descriptor::{
EntityDescriptor, ProblemFactDescriptor, SolutionDescriptor, UsizeEntityValueProvider,
UsizeGetter, UsizeSetter, VariableDescriptor,
};
pub use entity_ref::{EntityExtractor, EntityRef, TypedEntityExtractor};
pub use entity_ref::{EntityCollectionExtractor, EntityExtractor, EntityRef};
pub use listener::{
ListVariableListener, ListVariableNotification, VariableListener, VariableNotification,
};
Expand Down
18 changes: 9 additions & 9 deletions crates/solverforge-core/src/domain/tests/entity_ref_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::any::Any;

use crate::domain::{EntityExtractor, TypedEntityExtractor};
use crate::domain::{EntityCollectionExtractor, EntityExtractor};

#[derive(Clone, Debug)]
struct TestEntity {
Expand All @@ -24,7 +24,7 @@ fn get_entities_mut(s: &mut TestSolution) -> &mut Vec<TestEntity> {
#[test]
fn test_typed_entity_extractor_count() {
let extractor =
TypedEntityExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);
EntityCollectionExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);

let solution = TestSolution {
entities: vec![
Expand All @@ -47,7 +47,7 @@ fn test_typed_entity_extractor_count() {
#[test]
fn test_typed_entity_extractor_get() {
let extractor =
TypedEntityExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);
EntityCollectionExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);

let solution = TestSolution {
entities: vec![
Expand Down Expand Up @@ -76,7 +76,7 @@ fn test_typed_entity_extractor_get() {
#[test]
fn test_typed_entity_extractor_get_mut() {
let extractor =
TypedEntityExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);
EntityCollectionExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);

let mut solution = TestSolution {
entities: vec![TestEntity {
Expand All @@ -96,7 +96,7 @@ fn test_typed_entity_extractor_get_mut() {
#[test]
fn test_typed_entity_extractor_entity_refs() {
let extractor =
TypedEntityExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);
EntityCollectionExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);

let solution = TestSolution {
entities: vec![
Expand All @@ -122,7 +122,7 @@ fn test_typed_entity_extractor_entity_refs() {
#[test]
fn test_extractor_wrong_solution_type() {
let extractor =
TypedEntityExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);
EntityCollectionExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);

let wrong_solution = "not a solution";
let count = extractor.count(&wrong_solution as &dyn Any);
Expand All @@ -131,7 +131,7 @@ fn test_extractor_wrong_solution_type() {

#[test]
fn test_extractor_clone() {
let extractor: Box<dyn EntityExtractor> = Box::new(TypedEntityExtractor::new(
let extractor: Box<dyn EntityExtractor> = Box::new(EntityCollectionExtractor::new(
"TestEntity",
"entities",
get_entities,
Expand All @@ -153,7 +153,7 @@ fn test_extractor_clone() {
#[test]
fn test_clone_entity_boxed() {
let extractor =
TypedEntityExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);
EntityCollectionExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);

let solution = TestSolution {
entities: vec![
Expand Down Expand Up @@ -192,7 +192,7 @@ fn test_clone_entity_boxed() {
#[test]
fn test_entity_type_id() {
let extractor =
TypedEntityExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);
EntityCollectionExtractor::new("TestEntity", "entities", get_entities, get_entities_mut);

assert_eq!(
extractor.entity_type_id(),
Expand Down
2 changes: 1 addition & 1 deletion crates/solverforge-macros/WIREFRAME.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ struct ShadowConfig {
All generated code references types via `::solverforge::__internal::*` paths, meaning the generated code depends on the `solverforge` facade crate re-exporting core types under `__internal`. Key referenced types:
- `PlanningEntity`, `PlanningSolution`, `PlanningId`, `ProblemFact`
- `EntityDescriptor`, `SolutionDescriptor`, `ProblemFactDescriptor`, `VariableDescriptor`
- `TypedEntityExtractor`
- `EntityCollectionExtractor`
- `ShadowVariableKind`, `ShadowVariableSupport`, `SolvableSolution`
- `ScoreDirector`, `Director`

Expand Down
4 changes: 2 additions & 2 deletions crates/solverforge-macros/src/planning_solution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn expand_derive(input: DeriveInput) -> Result<TokenStream, Error> {
let element_type = extract_collection_inner_type(&f.ty)?;
Some(quote! {
.with_entity(#element_type::entity_descriptor(#field_name_str).with_extractor(
Box::new(::solverforge::__internal::TypedEntityExtractor::new(
Box::new(::solverforge::__internal::EntityCollectionExtractor::new(
stringify!(#element_type),
#field_name_str,
|s: &#name| &s.#field_name,
Expand All @@ -125,7 +125,7 @@ pub fn expand_derive(input: DeriveInput) -> Result<TokenStream, Error> {
let element_type = extract_collection_inner_type(&f.ty)?;
Some(quote! {
.with_problem_fact(#element_type::problem_fact_descriptor(#field_name_str).with_extractor(
Box::new(::solverforge::__internal::TypedEntityExtractor::new(
Box::new(::solverforge::__internal::EntityCollectionExtractor::new(
stringify!(#element_type),
#field_name_str,
|s: &#name| &s.#field_name,
Expand Down
2 changes: 1 addition & 1 deletion crates/solverforge-scoring/WIREFRAME.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,4 +485,4 @@ All types use `PhantomData<(fn() -> S, fn() -> A, ...)>` to avoid inheriting bou

## Cross-Crate Dependencies

- **From `solverforge-core`:** `Score`, `PlanningSolution`, `ConstraintRef`, `ImpactType`, `SolutionDescriptor`, `EntityDescriptor`, `ProblemFactDescriptor`, `VariableDescriptor`, `TypedEntityExtractor`
- **From `solverforge-core`:** `Score`, `PlanningSolution`, `ConstraintRef`, `ImpactType`, `SolutionDescriptor`, `EntityDescriptor`, `ProblemFactDescriptor`, `VariableDescriptor`, `EntityCollectionExtractor`
16 changes: 8 additions & 8 deletions crates/solverforge-solver/WIREFRAME.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ src/
│ └── selector/
│ ├── mod.rs — Re-exports
│ ├── entity.rs — EntitySelector trait, FromSolutionEntitySelector, AllEntitiesSelector
│ ├── typed_value.rs — TypedValueSelector trait, StaticTypedValueSelector, FromSolutionTypedValueSelector
│ ├── typed_move_selector.rs — MoveSelector trait, ChangeMoveSelector, SwapMoveSelector, EitherChange/SwapMoveSelector, ListMove* wrappers
│ ├── typed_move_selector_tests.rs — Tests
│ ├── value_selector.rs — ValueSelector trait, StaticValueSelector, FromSolutionValueSelector
│ ├── move_selector.rs — MoveSelector trait, ChangeMoveSelector, SwapMoveSelector, EitherChange/SwapMoveSelector, ListMove* wrappers
│ ├── move_selector_tests.rs — Tests
│ ├── list_change.rs — ListChangeMoveSelector<S, V, ES>
│ ├── list_swap.rs — ListSwapMoveSelector<S, V, ES>, ListMoveListSwapSelector
│ ├── list_reverse.rs — ListReverseMoveSelector<S, V, ES>, ListMoveListReverseSelector
Expand Down Expand Up @@ -128,7 +128,7 @@ src/
│ ├── mimic.rs
│ ├── nearby.rs
│ ├── pillar.rs
│ └── typed_move_selector.rs
│ └── move_selector.rs
├── phase/
│ ├── mod.rs — Phase<S, D> trait, tuple impls
Expand Down Expand Up @@ -274,15 +274,15 @@ Requires: `Send + Debug`.
| `size` | `fn<D: Director<S>>(&self, score_director: &D) -> usize` |
| `is_never_ending` | `fn(&self) -> bool` |

### `MoveSelector<S: PlanningSolution, M: Move<S>>` — `typed_move_selector.rs`
### `MoveSelector<S: PlanningSolution, M: Move<S>>` — `move_selector.rs`

| Method | Signature |
|--------|-----------|
| `iter_moves` | `fn<'a, D: Director<S>>(&'a self, score_director: &'a D) -> impl Iterator<Item = M> + 'a` |
| `size` | `fn<D: Director<S>>(&self, score_director: &D) -> usize` |
| `is_never_ending` | `fn(&self) -> bool` |

### `TypedValueSelector<S: PlanningSolution, V>` — `typed_value.rs`
### `ValueSelector<S: PlanningSolution, V>` — `value_selector.rs`

| Method | Signature |
|--------|-----------|
Expand Down Expand Up @@ -462,8 +462,8 @@ All moves are generic over `S` (solution) and `V` (value). All use typed `fn` po

| Selector | Note |
|----------|------|
| `StaticTypedValueSelector<S, V>` | Fixed value list |
| `FromSolutionTypedValueSelector<S, V>` | Extracts values from solution via `fn(&S) -> Vec<V>` |
| `StaticValueSelector<S, V>` | Fixed value list |
| `FromSolutionValueSelector<S, V>` | Extracts values from solution via `fn(&S) -> Vec<V>` |
| `RangeValueSelector<S>` | Generates 0..count_fn(solution) |

### Move Selectors
Expand Down
4 changes: 2 additions & 2 deletions crates/solverforge-solver/src/builder/list_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ use solverforge_scoring::Director;
use crate::heuristic::r#move::{ListMoveImpl, MoveArena};
use crate::heuristic::selector::decorator::VecUnionSelector;
use crate::heuristic::selector::k_opt::KOptConfig;
use crate::heuristic::selector::nearby_list_change::CrossEntityDistanceMeter;
use crate::heuristic::selector::typed_move_selector::{
use crate::heuristic::selector::move_selector::{
ListMoveKOptSelector, ListMoveListChangeSelector, ListMoveListRuinSelector,
ListMoveNearbyKOptSelector, MoveSelector,
};
use crate::heuristic::selector::nearby_list_change::CrossEntityDistanceMeter;

use super::context::IntraDistanceAdapter;
use crate::heuristic::selector::{
Expand Down
2 changes: 1 addition & 1 deletion crates/solverforge-solver/src/descriptor_standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use solverforge_scoring::Director;

use crate::heuristic::r#move::Move;
use crate::heuristic::selector::decorator::VecUnionSelector;
use crate::heuristic::selector::typed_move_selector::MoveSelector;
use crate::heuristic::selector::move_selector::MoveSelector;
use crate::heuristic::selector::EntityReference;
use crate::phase::construction::{
BestFitForager, ConstructionHeuristicPhase, EntityPlacer, FirstFitForager, Placement,
Expand Down
8 changes: 4 additions & 4 deletions crates/solverforge-solver/src/heuristic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ pub use selector::{
AllEntitiesSelector, ChangeMoveSelector, CrossEntityDistanceMeter,
DefaultCrossEntityDistanceMeter, DefaultDistanceMeter, DefaultPillarSelector,
EitherChangeMoveSelector, EitherSwapMoveSelector, EntityReference, EntitySelector,
FromSolutionEntitySelector, FromSolutionTypedValueSelector, KOptConfig, KOptMoveSelector,
FromSolutionEntitySelector, FromSolutionValueSelector, KOptConfig, KOptMoveSelector,
ListChangeMoveSelector, ListMoveKOptSelector, ListMoveListChangeSelector,
ListMoveListReverseSelector, ListMoveListRuinSelector, ListMoveListSwapSelector,
ListMoveNearbyListChangeSelector, ListMoveNearbyListSwapSelector,
ListMoveSubListChangeSelector, ListMoveSubListSwapSelector, ListPositionDistanceMeter,
ListReverseMoveSelector, ListRuinMoveSelector, ListSwapMoveSelector, MimicRecorder,
MimicRecordingEntitySelector, MimicReplayingEntitySelector, MoveSelector, NearbyDistanceMeter,
NearbyEntitySelector, NearbyKOptMoveSelector, NearbyListChangeMoveSelector,
NearbyListSwapMoveSelector, NearbySelectionConfig, PerEntityTypedValueSelector, Pillar,
PillarSelector, RuinMoveSelector, SelectionOrder, StaticTypedValueSelector,
NearbyListSwapMoveSelector, NearbySelectionConfig, PerEntityValueSelector, Pillar,
PillarSelector, RuinMoveSelector, SelectionOrder, StaticValueSelector,
SubListChangeMoveSelector, SubListSwapMoveSelector, SubPillarConfig, SwapMoveSelector,
TypedValueSelector,
ValueSelector,
};
4 changes: 2 additions & 2 deletions crates/solverforge-solver/src/heuristic/move/k_opt_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use super::*;
use crate::heuristic::r#move::k_opt_reconnection::THREE_OPT_RECONNECTIONS;
use solverforge_core::domain::{
EntityDescriptor, PlanningSolution, SolutionDescriptor, TypedEntityExtractor,
EntityCollectionExtractor, EntityDescriptor, PlanningSolution, SolutionDescriptor,
};
use solverforge_core::score::SoftScore;
use solverforge_scoring::{RecordingDirector, ScoreDirector};
Expand Down Expand Up @@ -56,7 +56,7 @@ fn sublist_insert(s: &mut TspSolution, entity_idx: usize, pos: usize, items: Vec

fn create_director(tours: Vec<Tour>) -> ScoreDirector<TspSolution, ()> {
let solution = TspSolution { tours, score: None };
let extractor = Box::new(TypedEntityExtractor::new(
let extractor = Box::new(EntityCollectionExtractor::new(
"Tour",
"tours",
get_tours,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use super::*;
use solverforge_core::domain::{
EntityDescriptor, PlanningSolution, SolutionDescriptor, TypedEntityExtractor,
EntityCollectionExtractor, EntityDescriptor, PlanningSolution, SolutionDescriptor,
};
use solverforge_core::score::SoftScore;
use solverforge_scoring::{RecordingDirector, ScoreDirector};
Expand Down Expand Up @@ -53,7 +53,7 @@ fn create_director(vehicles: Vec<Vehicle>) -> ScoreDirector<RoutingSolution, ()>
vehicles,
score: None,
};
let extractor = Box::new(TypedEntityExtractor::new(
let extractor = Box::new(EntityCollectionExtractor::new(
"Vehicle",
"vehicles",
get_vehicles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use super::*;
use solverforge_core::domain::{
EntityDescriptor, PlanningSolution, SolutionDescriptor, TypedEntityExtractor,
EntityCollectionExtractor, EntityDescriptor, PlanningSolution, SolutionDescriptor,
};
use solverforge_core::score::SoftScore;
use solverforge_scoring::{RecordingDirector, ScoreDirector};
Expand Down Expand Up @@ -63,7 +63,7 @@ fn create_director(vehicles: Vec<Vehicle>) -> ScoreDirector<RoutingSolution, ()>
vehicles,
score: None,
};
let extractor = Box::new(TypedEntityExtractor::new(
let extractor = Box::new(EntityCollectionExtractor::new(
"Vehicle",
"vehicles",
get_vehicles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use super::*;
use solverforge_core::domain::{
EntityDescriptor, PlanningSolution, SolutionDescriptor, TypedEntityExtractor,
EntityCollectionExtractor, EntityDescriptor, PlanningSolution, SolutionDescriptor,
};
use solverforge_core::score::SoftScore;
use solverforge_scoring::{RecordingDirector, ScoreDirector};
Expand Down Expand Up @@ -63,7 +63,7 @@ fn create_director(vehicles: Vec<Vehicle>) -> ScoreDirector<RoutingSolution, ()>
vehicles,
score: None,
};
let extractor = Box::new(TypedEntityExtractor::new(
let extractor = Box::new(EntityCollectionExtractor::new(
"Vehicle",
"vehicles",
get_vehicles,
Expand Down
Loading
Loading