Planning Annotations

Configure planning behavior with PlanningAnnotation types

Annotations configure how the solver interprets your domain model.

Class Annotations

PlanningEntity

Marks a class as a planning entity - an object whose planning variables are assigned by the solver.

DomainClass::new("Shift")
    .with_annotation(PlanningAnnotation::PlanningEntity)

PlanningSolution

Marks a class as the planning solution - the container for all problem facts, entities, and the score.

DomainClass::new("Schedule")
    .with_annotation(PlanningAnnotation::PlanningSolution)

Field Annotations

PlanningId

Marks a field as the unique identifier for instances of the class.

FieldDescriptor::new("id", FieldType::Primitive(PrimitiveType::String))
    .with_planning_annotation(PlanningAnnotation::PlanningId)

PlanningVariable

Marks a field whose value is determined by the solver. Must reference value range providers.

// Basic planning variable
FieldDescriptor::new("employee", FieldType::object("Employee"))
    .with_planning_annotation(
        PlanningAnnotation::planning_variable(vec!["employees".to_string()])
    )

// Planning variable that allows null (unassigned)
FieldDescriptor::new("room", FieldType::object("Room"))
    .with_planning_annotation(
        PlanningAnnotation::planning_variable_unassigned(vec!["rooms".to_string()])
    )

Parameters:

  • value_range_provider_refs: List of value range provider IDs that supply valid values
  • allows_unassigned: If true, the variable can remain unassigned (null)

PlanningListVariable

Marks a list field where the solver assigns which elements belong to the list.

FieldDescriptor::new("visits", FieldType::list(FieldType::object("Visit")))
    .with_planning_annotation(
        PlanningAnnotation::planning_list_variable(vec!["visits".to_string()])
    )

PlanningScore

Marks the score field on the solution class.

// Standard score
FieldDescriptor::new("score", FieldType::Score(ScoreType::HardSoft))
    .with_planning_annotation(PlanningAnnotation::planning_score())

// Bendable score with specific levels
FieldDescriptor::new("score", FieldType::Score(ScoreType::Bendable { hard_levels: 2, soft_levels: 3 }))
    .with_planning_annotation(PlanningAnnotation::planning_score_bendable(2, 3))

ValueRangeProvider

Marks a field that provides valid values for planning variables.

FieldDescriptor::new("employees", FieldType::list(FieldType::object("Employee")))
    .with_planning_annotation(PlanningAnnotation::value_range_provider("employees"))

The ID ("employees") must match the value_range_provider_refs in corresponding planning variables.

ProblemFactCollectionProperty

Marks a collection of problem facts (read-only data) on the solution class.

FieldDescriptor::new("employees", FieldType::list(FieldType::object("Employee")))
    .with_planning_annotation(PlanningAnnotation::ProblemFactCollectionProperty)

PlanningEntityCollectionProperty

Marks a collection of planning entities on the solution class.

FieldDescriptor::new("shifts", FieldType::list(FieldType::object("Shift")))
    .with_planning_annotation(PlanningAnnotation::PlanningEntityCollectionProperty)

PlanningPin

Marks a boolean field that pins an entity’s assignment (prevents the solver from changing it).

FieldDescriptor::new("pinned", FieldType::Primitive(PrimitiveType::Bool))
    .with_planning_annotation(PlanningAnnotation::PlanningPin)

InverseRelationShadowVariable

Marks a shadow variable that tracks the inverse of another planning variable.

FieldDescriptor::new("vehicle", FieldType::object("Vehicle"))
    .with_planning_annotation(PlanningAnnotation::inverse_relation_shadow("visits"))

Annotation Summary

AnnotationTargetPurpose
PlanningEntityClassMark as planning entity
PlanningSolutionClassMark as solution container
PlanningIdFieldUnique identifier
PlanningVariableFieldSolver-assigned value
PlanningListVariableFieldSolver-assigned list
PlanningScoreFieldScore field on solution
ValueRangeProviderFieldSource of valid values
ProblemFactCollectionPropertyFieldProblem fact collection
PlanningEntityCollectionPropertyFieldEntity collection
PlanningPinFieldPin entity assignment
InverseRelationShadowVariableFieldShadow inverse relation

Helper Methods

use solverforge_core::domain::PlanningAnnotation;

// Create planning variable
PlanningAnnotation::planning_variable(vec!["rooms".to_string()])
PlanningAnnotation::planning_variable_unassigned(vec!["slots".to_string()])

// Create list variable
PlanningAnnotation::planning_list_variable(vec!["tasks".to_string()])

// Create score annotation
PlanningAnnotation::planning_score()
PlanningAnnotation::planning_score_bendable(2, 3)

// Create value range provider
PlanningAnnotation::value_range_provider("timeslots")

// Create shadow variable
PlanningAnnotation::inverse_relation_shadow("visits")

Multiple Annotations

A field can have multiple annotations:

FieldDescriptor::new("employees", FieldType::list(FieldType::object("Employee")))
    .with_planning_annotation(PlanningAnnotation::ProblemFactCollectionProperty)
    .with_planning_annotation(PlanningAnnotation::value_range_provider("employees"))