API Quick Reference

Cheat sheet for common SolverForge APIs

Domain Model

DomainModel

DomainModel::builder()
    .add_class(class)
    .build()                    // Build without validation
    .build_validated()?         // Build with validation

DomainClass

DomainClass::new("ClassName")
    .with_annotation(PlanningAnnotation::PlanningEntity)
    .with_field(field)

FieldDescriptor

FieldDescriptor::new("fieldName", FieldType::...)
    .with_planning_annotation(PlanningAnnotation::...)

Field Types

TypeRust
PrimitivesFieldType::Primitive(PrimitiveType::String)
ObjectFieldType::object("ClassName")
ListFieldType::list(element_type)
SetFieldType::set(element_type)
ArrayFieldType::array(element_type)
MapFieldType::map(key_type, value_type)
ScoreFieldType::Score(ScoreType::HardSoft)

Primitive Types

TypeRust
BooleanPrimitiveType::Bool
Int (32-bit)PrimitiveType::Int
Long (64-bit)PrimitiveType::Long
FloatPrimitiveType::Float
DoublePrimitiveType::Double
StringPrimitiveType::String
DatePrimitiveType::Date
DateTimePrimitiveType::DateTime

Planning Annotations

AnnotationRust
PlanningIdPlanningAnnotation::PlanningId
PlanningEntityPlanningAnnotation::PlanningEntity
PlanningSolutionPlanningAnnotation::PlanningSolution
PlanningVariablePlanningAnnotation::planning_variable(vec!["id"])
PlanningVariable (nullable)PlanningAnnotation::planning_variable_unassigned(vec![])
PlanningListVariablePlanningAnnotation::planning_list_variable(vec![])
PlanningScorePlanningAnnotation::planning_score()
PlanningScore (bendable)PlanningAnnotation::planning_score_bendable(2, 3)
ValueRangeProviderPlanningAnnotation::value_range_provider("id")
ProblemFactCollectionPropertyPlanningAnnotation::ProblemFactCollectionProperty
PlanningEntityCollectionPropertyPlanningAnnotation::PlanningEntityCollectionProperty
PlanningPinPlanningAnnotation::PlanningPin
InverseRelationShadowPlanningAnnotation::inverse_relation_shadow("var")

Constraint Streams

StreamComponent

OperationRust
forEachStreamComponent::for_each("Class")
forEach (unassigned)StreamComponent::for_each_including_unassigned("Class")
forEachUniquePairStreamComponent::for_each_unique_pair("Class")
forEachUniquePair (joiners)StreamComponent::for_each_unique_pair_with_joiners("Class", joiners)
filterStreamComponent::filter(WasmFunction::new("pred"))
joinStreamComponent::join("Class")
join (joiners)StreamComponent::join_with_joiners("Class", joiners)
ifExistsStreamComponent::if_exists("Class")
ifNotExistsStreamComponent::if_not_exists("Class")
groupByStreamComponent::group_by(keys, collectors)
groupBy (key only)StreamComponent::group_by_key(key)
groupBy (collect only)StreamComponent::group_by_collector(collector)
mapStreamComponent::map(mappers)
map (single)StreamComponent::map_single(mapper)
flattenLastStreamComponent::flatten_last()
expandStreamComponent::expand(mappers)
complementStreamComponent::complement("Class")
penalizeStreamComponent::penalize("1hard/0soft")
penalize (weigher)StreamComponent::penalize_with_weigher("1hard", weigher)
rewardStreamComponent::reward("1soft")

Joiners

JoinerRust
equalJoiner::equal(map)
equal (separate)Joiner::equal_with_mappings(left, right)
lessThanJoiner::less_than(map, comparator)
greaterThanJoiner::greater_than(map, comparator)
overlappingJoiner::overlapping(start, end)
filteringJoiner::filtering(filter)

Collectors

CollectorRust
countCollector::count()
countDistinctCollector::count_distinct()
sumCollector::sum(map)
averageCollector::average(map)
minCollector::min(map, comparator)
maxCollector::max(map, comparator)
toListCollector::to_list()
toSetCollector::to_set()
loadBalanceCollector::load_balance(map)
loadBalance (with load)Collector::load_balance_with_load(map, load)
composeCollector::compose(collectors, combiner)
conditionallyCollector::conditionally(pred, collector)
collectAndThenCollector::collect_and_then(collector, mapper)

Scores

Score Types

TypeCreateParse
SimpleScoreSimpleScore::of(-5)SimpleScore::parse("-5")
HardSoftScoreHardSoftScore::of(-2, 10)HardSoftScore::parse("-2hard/10soft")
HardMediumSoftScoreHardMediumSoftScore::of(-1, 5, 10)HardMediumSoftScore::parse(...)
BendableScoreBendableScore::of(hard_vec, soft_vec)N/A

Score Methods

score.is_feasible()     // hard >= 0
score + other           // Addition
score - other           // Subtraction
-score                  // Negation

Solver Configuration

SolverConfig

SolverConfig::new()
    .with_solution_class("Schedule")
    .with_entity_class("Shift")
    .with_environment_mode(EnvironmentMode::Reproducible)
    .with_random_seed(42)
    .with_move_thread_count(MoveThreadCount::Auto)
    .with_termination(termination)

TerminationConfig

TerminationConfig::new()
    .with_spent_limit("PT5M")
    .with_unimproved_spent_limit("PT30S")
    .with_best_score_feasible(true)
    .with_best_score_limit("0hard/-100soft")
    .with_step_count_limit(1000)
    .with_move_count_limit(10000)

WASM Expressions

Expr Builder

ExpressionRust
IntegerExpr::int(42)
BooleanExpr::bool(true)
NullExpr::null()
ParameterExpr::param(0)
Field accessexpr.get("Class", "field")
EqualExpr::eq(left, right)
Not equalExpr::ne(left, right)
Less thanExpr::lt(left, right)
Greater thanExpr::gt(left, right)
ANDExpr::and(left, right)
ORExpr::or(left, right)
NOTExpr::not(expr)
Is nullExpr::is_null(expr)
Is not nullExpr::is_not_null(expr)
AddExpr::add(left, right)
SubtractExpr::sub(left, right)
MultiplyExpr::mul(left, right)
DivideExpr::div(left, right)
List containsExpr::list_contains(list, elem)
String equalsExpr::string_equals(left, right)
Ranges overlapExpr::ranges_overlap(s1, e1, s2, e2)
If-then-elseExpr::if_then_else(cond, then, else)

WasmModuleBuilder

WasmModuleBuilder::new()
    .with_domain_model(model)
    .with_host_functions(HostFunctionRegistry::with_standard_functions())
    .with_initial_memory(16)
    .with_max_memory(Some(256))
    .add_predicate(PredicateDefinition::from_expression(name, arity, expr))
    .build()?                    // Vec<u8>
    .build_base64()?            // String