Skip to content

Problem

relationalai.semantics.reasoners.prescriptive.problem
Problem(model: b.Model, numeric_type: b.Concept)

Define and solve a decision problem on a model.

Use Problem.solve_for to declare decision variables, Problem.minimize/ Problem.maximize to add objectives, and Problem.satisfy to add constraints. Then call Problem.solve and read results via Problem.variable_values or Problem.load_point.

Declare a variable and objective:

>>> from relationalai.semantics import Float, Model
>>> from relationalai.semantics.reasoners.prescriptive import Problem
>>> m = Model("demo")
>>> x = m.Relationship(f"{Float:x}")
>>> p = Problem(m, Float)
>>> p.solve_for(x, name="x", lower=0)
>>> p.minimize(x)
Problem.Variable: Concept

Concept for the declared solver variables (useful for inspection via Problem.display).

Problem.Expression: Concept

Concept for objectives and constraints (useful for inspection via Problem.display).

Problem.solve_for(
expr: b.Relationship | b.Chain | b.Expression,
where: Optional[list[Any]] = None,
populate: bool = True,
name: Optional[Any | list[Any]] = None,
type: Optional[str] = None,
lower: Optional[std.NumberValue] = None,
upper: Optional[std.NumberValue] = None,
start: Optional[std.NumberValue] = None,
) -> b.Concept

Declare decision variables for the problem.

Call this before adding objectives or constraints. The returned concept can be passed to Problem.display to inspect the generated variables.

Parameters:

  • expr

    (Relationship or Chain or Expression) - Expression describing the variable(s) to create (for example, a scalar relationship like x or an indexed property like Item.cost).
  • where

    (list[Any], default: None) - Optional conditions restricting which variable instances are created.
  • populate

    (bool, default: True) - If True (default), write solved values back to the original relationship/property after Problem.solve. Set to False when you create multiple Problem instances that solve for the same relationship on the same model.
  • name

    (Any or list[Any], default: None) - Display name for variables. Use a string for scalars or a list pattern for indexed variables (for example, ["x", Item.i]).
  • type

    (str, default: None) - Variable type: "cont" (default for Float), "int" (default for Integer), or "bin" (binary 0/1).
  • lower

    (Variable or float or int or Decimal, default: None) - Lower/upper bounds and an optional initial value hint.
  • upper

    (Variable or float or int or Decimal, default: None) - Lower/upper bounds and an optional initial value hint.
  • start

    (Variable or float or int or Decimal, default: None) - Lower/upper bounds and an optional initial value hint.

Returns:

  • Concept - A Variable subconcept representing the declared decision variables.

Raises:

  • ValueError - If variables are already defined for this relationship, or if an argument has an invalid value (for example, an unknown type).
  • TypeError - If an argument has an invalid type.

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning > Solve a decision problem
        ├──  Overview
        │   └──  How solving a decision problem works
        ├──  Create a Problem object
        │   └──  Choose a default numeric type
        ├──  Add decision variables
        │   ├──  Declare decision variables
        │   └──  Choose variable types and bounds
        ├──  Solve a decision problem
        │   └──  Avoid common pitfalls
        └──  Work with solutions
            └──  Determine how to access results
Problem.minimize(
expr: b.Variable | float | int | b.Fragment, name: Optional[Any | list[Any]] = None
) -> b.Concept

Add a minimization objective.

The expression must reference at least one decision variable declared via Problem.solve_for.

Parameters:

  • expr

    (Variable or float or int or Fragment) - Objective expression to minimize.
  • name

    (Any or list[Any], default: None) - Optional objective name (string for scalar, or a list pattern for indexed objectives).

Returns:

Raises:

  • ValueError - If the objective does not reference any declared decision variables.

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning > Solve a decision problem
        └──  Solve a decision problem
            └──  Solve optimally
Problem.maximize(
expr: b.Variable | float | int | b.Fragment, name: Optional[Any | list[Any]] = None
) -> b.Concept

Add a maximization objective.

The expression must reference at least one decision variable declared via Problem.solve_for.

Parameters:

  • expr

    (Variable or float or int or Fragment) - Objective expression to maximize.
  • name

    (Any or list[Any], default: None) - Optional objective name (string for scalar, or a list pattern for indexed objectives).

Returns:

Raises:

  • ValueError - If the objective does not reference any declared decision variables.

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning > Solve a decision problem
        └──  Solve a decision problem
            └──  Solve optimally
Problem.satisfy(expr: b.Fragment, name: Optional[Any | list[Any]] = None) -> b.Concept

Add constraints from a model.require(...) fragment.

Use this to turn a require-clause fragment into solver constraints. The returned concept can be passed to Problem.display to inspect.

Parameters:

  • expr

    (Fragment) - A fragment created by Model.require (optionally scoped with Model.where).
  • name

    (Any or list[Any], default: None) - Optional constraint name (string for scalar, or a list pattern for indexed constraints).

Returns:

  • Concept - An Expression subconcept representing the added constraints.

Raises:

  • TypeError - If expr is not a fragment.
  • ValueError - If the fragment has no require clause, or if it includes select/define clauses.

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning > Solve a decision problem
        ├──  Overview
        └──  Add constraints
            ├──  Add constraints with Problem.satisfy()
            └──  Avoid common pitfalls
Problem.display(part: Optional[b.Concept] = None) -> str

Print and return a human-readable summary of the problem.

With no arguments, this shows all declared variables, objectives, and constraints. Pass a subconcept returned by Problem.solve_for, Problem.minimize, Problem.maximize, or Problem.satisfy to display only that part.

Parameters:

  • part

    (Concept, default: None) - Specific variable/objective/constraint subconcept to display.

Returns:

  • str - The formatted summary (also printed).

Raises:

Examples:

Display the full problem:

>>> from relationalai.semantics import Float, Model
>>> from relationalai.semantics.reasoners.prescriptive import Problem
>>> m = Model("demo")
>>> x = m.Relationship(f"{Float:x}")
>>> p = Problem(m, Float)
>>> x_vars = p.solve_for(x, name="x", lower=0)
>>> p.minimize(x)
>>> p.display()

Display a single part (a subconcept returned by solve_for/minimize/satisfy):

>>> p.display(x_vars)

Notes:

This method queries the model.

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning > Solve a decision problem
        ├──  Create a Problem object
        │   └──  Inspect a Problem with display()
        ├──  Add constraints
        │   └──  Inspect Problem constraints
        └──  Solve a decision problem
            └──  Avoid common pitfalls
Problem.solve(
solver: str,
*,
time_limit_sec: float | None = None,
silent: bool | None = None,
solution_limit: int | None = None,
relative_gap_tolerance: float | None = None,
absolute_gap_tolerance: float | None = None,
log_to_console: bool = False,
print_only: bool = False,
print_format: str | None = None,
**solver_params: int | float | str | bool
) -> None

Solve the decision problem using a solver backend.

Declare decision variables first with Problem.solve_for. After solving, inspect results via Problem.variable_values and result properties such as termination_status and objective_value.

Parameters:

  • solver

    (str) - Solver name (for example "highs", "minizinc", "ipopt").
  • time_limit_sec

    (float, default: None) - Maximum solve time in seconds. The solver service defaults to 300s if not provided.
  • silent

    (bool, default: None) - Whether to suppress solver output.
  • solution_limit

    (int, default: None) - Maximum number of solutions to return (when supported).
  • relative_gap_tolerance

    (float, default: None) - Relative optimality gap tolerance in [0, 1].
  • absolute_gap_tolerance

    (float, default: None) - Absolute optimality gap tolerance (>= 0).
  • log_to_console

    (bool, default: False) - Whether to stream solver logs to stdout while the job runs.
  • print_only

    (bool, default: False) - If True, request a text representation without solving. Results such as Problem.printed_model are still accessible afterward.
  • print_format

    (str, default: None) - Text format for the printed model. Supported formats: "moi" (MOI text), "latex", "mof" (MOI JSON), "lp", "mps", "nl" (AMPL).
  • **solver_params

    (int or float or str or bool, default: {}) - Raw solver-specific parameters passed through to the solver service.

Raises:

  • ValueError - If no decision variables have been declared via Problem.solve_for.
  • TypeError - If any solver-specific parameter value is not an int, float, str, or bool.
  • RuntimeError - If the solver job fails.
  • TimeoutError - If the solver job does not reach a terminal state in time.

Notes:

Passing **solver_params emits a warning because options may not be portable across solvers.

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning
        ├──  Choose a backend
        │   ├──  Use Gurobi
        │   │   └──  Example
        │   ├──  Use Ipopt
        │   │   └──  Example
        │   └──  Use MiniZinc
        │       └──  Example
        └──  Solve a decision problem
            ├──  Overview
            ├──  Solve a decision problem
            │   ├──  What happens when you solve a problem
            │   ├──  Solve for feasibility
            │   ├──  Solve optimally
            │   ├──  Set a time limit
            │   ├──  Accept a near-optimal solution
            │   ├──  Tune solver backend behavior
            │   ├──  Print the translated solver model
            │   ├──  Check error details when termination status is not OPTIMAL
            │   └──  Handle solve failures
            └──  Work with solutions
Problem.variable_values(multiple: bool = False) -> b.Fragment

Return decision variable values from the active solution.

Use this after Problem.solve (and optionally Problem.load_point) to read variable values as a fragment you can materialize with .to_df() or print with .inspect().

Parameters:

  • multiple

    (bool, default: False) - If True, return values for all solutions from the most recent Problem.solve call and include a 0-based sol_index column.

Returns:

  • Fragment - A fragment with columns name and value (and sol_index if multiple is True).

Raises:

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning > Solve a decision problem
        ├──  Add decision variables
        │   └──  Declare decision variables
        └──  Work with solutions
            ├──  Determine how to access results
            └──  Read solver-level variable values
Problem.load_point(point_index: int) -> None

Make a specific solution point the active solution.

After calling this, Problem.variable_values and populated properties reflect the selected solution.

Parameters:

  • point_index

    (int) - 0-based solution index (0 selects the first solution).

Raises:

  • ValueError - Raised in the following cases:

Notes:

Each call records a new selection via model.define(...). The next query may be slower because the model needs to re-evaluate.

Problem.display_solve_info() -> str

Print and return a summary of solve metadata.

This includes solver metadata fields such as termination_status and solve_time_sec.

Returns:

  • str - A formatted summary string (also printed).

Raises:

Notes:

The objective value is not included; use Problem.objective_value.

Referenced By:

RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning > Solve a decision problem
        └──  Solve a decision problem
            └──  Inspect solve metadata
RelationalAI Documentation
└──  Build With RelationalAI
    └──  Understand how PyRel works > Use advanced reasoning > Prescriptive reasoning
        ├──  Choose a backend
        │   ├──  Use HiGHS
        │   │   └──  Example
        │   ├──  Use Gurobi
        │   │   └──  Example
        │   ├──  Use Ipopt
        │   │   └──  Example
        │   └──  Use MiniZinc
        │       └──  Example
        └──  Solve a decision problem
            ├──  Overview
            │   ├──  How PyRel represents a decision problem
            │   └──  How solving a decision problem works
            ├──  Create a Problem object
            │   ├──  Choose a default numeric type
            │   ├──  Create a Problem object
            │   └──  Inspect a Problem with display()
            ├──  Add decision variables
            │   ├──  Declare decision variables
            │   ├──  Choose variable types and bounds
            │   └──  Inspect Problem variables
            ├──  Add constraints
            │   ├──  Add constraints with Problem.satisfy()
            │   ├──  Inspect Problem constraints
            │   └──  Avoid common pitfalls
            ├──  Solve a decision problem
            │   ├──  What happens when you solve a problem
            │   ├──  Validate before you solve
            │   ├──  Solve for feasibility
            │   ├──  Solve optimally
            │   ├──  Inspect solve metadata
            │   ├──  Set a time limit
            │   ├──  Accept a near-optimal solution
            │   ├──  Tune solver backend behavior
            │   ├──  Print the translated solver model
            │   ├──  Check error details when termination status is not OPTIMAL
            │   ├──  Handle solve failures
            │   └──  Avoid common pitfalls
            └──  Work with solutions
                ├──  Determine how to access results
                └──  Read solver-level variable values