relationalai.experimental.solvers.Solver
class Solver
Represents a solver backend that can be used to solve an optimization problem specified by a SolverModel
object.
Example
Section titled “Example”import relationalai as raifrom relationalai.experimental import solvers
# Create a RAI model.model = rai.Model("WeeklyShiftAssignment")
138 collapsed lines
# Declare entity types and properties.
# Entity types.Employee = model.Type("Employee")Shift = model.Type("Shift")Day = model.Type("Day")Available = model.Type("Available")Scenario = model.Type("Scenario") # All possible employee–shift–day combinations.Assignment = model.Type("Assignment") # A Scenario that is assigned.
# Properties.Employee.name.declare()Shift.name.declare()Shift.capacity.declare()Available.employee.declare()Available.day.declare()Scenario.employee.declare()Scenario.shift.declare()Scenario.day.declare()
# Define sample data.
# Employees.with model.rule(dynamic=True): for name in ["Alice", "Bob", "Carol", "Dave", "Eve"]: Employee.add(name=name)
# Shifts.with model.rule(): Shift.add(name="Morning").set(capacity=2) Shift.add(name="Evening").set(capacity=3)
# Days of the week.with model.rule(dynamic=True): for name in ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]: Day.add(name=name)
# Employee-day availability.with model.rule(dynamic=True): # Alice works weekdays only for name in ["Mon", "Tue", "Wed", "Thu", "Fri"]: Available.add(employee=Employee(name="Alice"), day=Day(name=name)) # Bob works all days Available.add(employee=Employee(name="Bob"), day=Day()) # Carol works weekends only for name in ["Sat", "Sun"]: Available.add(employee=Employee(name="Carol"), day=Day(name=name)) # Dave works Mon/Wed/Fri for name in ["Mon", "Wed", "Fri"]: Available.add(employee=Employee(name="Dave"), day=Day(name=name)) # Eve works Tue/Thu/Sat for name in ["Tue", "Thu", "Sat"]: Available.add(employee=Employee(name="Eve"), day=Day(name=name))
# All possible employee–shift–day combinationswith model.rule(): Scenario.add(employee=Employee(), shift=Shift(), day=Day())
# Create a SolverModel instance from the model.solver_model = solvers.SolverModel(model)
# Define solver variables.
# Scenario assignment: binary variable for each employee–shift–day combination.with model.rule(): scenario = Scenario() solver_model.variable( scenario, type="zero_one", name_args=["assigned", scenario.employee.name, scenario.day.name, scenario.shift.name], )
# Define Solver Constraints
# Unavailable employee–day pairs cannot be assigned.with model.rule(): scenario = Scenario() with model.not_found(): Available(employee=scenario.employee, day=scenario.day) solver_model.constraint( solvers.not_(scenario), name_args=["unavailable", scenario.employee.name, scenario.day.name] )
# If an employee works the morning shift, they can't work the evening shift.with model.rule(): works_morning = Scenario(shift=Shift(name="Morning")) works_evening = Scenario( shift=Shift(name="Evening"), employee=works_morning.employee, day=works_morning.day ) solver_model.constraint( solvers.implies(works_morning, solvers.not_(works_evening)) )
# At least one of Alice or Bob works Morning on Monday.with model.rule(): morning, monday = Shift(name="Morning"), Day(name="Mon") alice_works = Scenario(employee=Employee(name="Alice"), shift=morning, day=monday) bob_works = Scenario(employee=Employee(name="Bob"), shift=morning, day=monday) solver_model.constraint(solvers.or_(alice_works, bob_works))
# If Alice works in the morning, she doesn't work in the evening. Otherwise, she does work in the evening.with model.rule(): alice = Employee(name="Alice") day = Available(employee=alice).day works_morning = Scenario(employee=alice, shift=Shift(name="Morning"), day=day) works_evening = Scenario(employee=alice, shift=Shift(name="Evening"), day=day) solver_model.constraint( solvers.if_then_else(works_morning, solvers.not_(works_evening), works_evening), name_args=["alice_shift", day.name] )
# Limit the number of employees assigned to each shift to its capacity.with solvers.operators(): scenario = Scenario() shift, day = scenario.shift, scenario.day num_shifts_per_day = solvers.count(scenario, per=[shift, day]) solver_model.constraint( num_shifts_per_day <= shift.capacity, name_args=["shift_cap", shift.name, day.name] )
# Define solver objective.
# Maximize total assignments across the week.with model.rule(): scenario = Scenario() solver_model.max_objective(solvers.sum(scenario))
# Solve the solver model.
# Create a Solver instance.solver = solvers.Solver("minizinc")
Methods
Section titled “Methods”The Solver
class has no public methods beyond its constructor.
.__init__()
Section titled “.__init__()”Solver.__init__( self, solver_name: str, engine_name: str | None = None) -> None
Constructs a new Solver
instance.
The solver_name
parameter specifies the name of the solver backend to use and may be one of:
"gurobi"
"highs"
"ipopt"
"minizinc"
For example:
from relationalai.experimental import solvers
# Create a Solver object.solver = solvers.Solver("highs")
The optional engine_name
parameter sets the name of the solver engine used to host the backend.
If engine_name
is None
, the engine name is taken from your raiconfig.toml
file.
If it’s not set there either, your Snowflake user name is used instead.
See Solver Engines for details.
Attributes
Section titled “Attributes”Solver
objects have attributes that provide information about the solver backend and its configuration and access to the associated Provider
instance for managing the solver.
.provider
Section titled “.provider”Solver.provider: Provider
The Provider
instance that this Solver
is associated with.
This is used to manage the solver backend and its resources.
For example, you can use the provider
attribute to cancel a solver job:
from relationalai.experimental import solvers
# Create a Solver object.solver = solvers.Solver("highs")
# Use the `.provider` attribute to cancel a job by its ID.solver.provider.cancel_job("01bd4f7a-0105-c8b9-0003-0acf0aaf4ca6")
.settings
Section titled “.settings”Solver.settings: dict[str, Any]
A dictionary of settings for the solver’s engine.
These settings are currently limited to enabling or disabling particular backends and are set in the [experimental.solvers]
section of your raiconfig.toml
file.
For example:
from relationalai.experimental import solvers
# Create a Solver object.solver = solvers.Solver("highs")
# View the settings for the solver.print(solver.settings)
{}
.solver_name
Section titled “.solver_name”Solver.solver_name: str
The name of the solver backend used by this Solver
instance.
For example:
from relationalai.experimental import solvers
# Create a Solver object.solver = solvers.Solver("highs")
# View the solver backend name.print(solver.solver_name)
highs