Skip to content

relationalai.experimental.solvers.Solver

Signature
class Solver

Represents a solver backend that can be used to solve an optimization problem specified by a SolverModel object.

support_tickets_routing.py
import relationalai as rai
from 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 combinations
with 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")

The Solver class has no public methods beyond its constructor.

Signature
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.

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.

Signature
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")
Signature
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)
output
{}
Signature
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)
output
highs