User guide · 2.0 development

Quadratic Problems

SHOT can handle quadratic objectives and constraints (QCQP):

\[\begin{split} \begin{aligned} \text{minimize} \quad & x^2 + y^2 \\ \text{subject to} \quad & x + y \geq 2 \\ & x, y \geq 0 \end{aligned} \end{split}\]
# Create problem
solver = SHOTpy.Solver()
problem = SHOTpy.Problem(solver)

# Variables
x = problem.addVariable("x", SHOTpy.VariableType.Real, 0.0, 10.0)
y = problem.addVariable("y", SHOTpy.VariableType.Real, 0.0, 10.0)

# Quadratic objective: x^2 + y^2
problem.setObjective(x**2 + y**2, SHOTpy.ObjectiveDirection.Minimize)

# Linear constraint: x + y >= 2
problem.addConstraint(x + y >= 2, "sum_constraint")

# Solve
problem.finalize()
assert solver.setProblem(problem)
assert solver.solveProblem()
assert solver.getModelReturnStatus() == SHOTpy.ModelReturnStatus.OptimalGlobal

sol = solver.getPrimalSolution()
print(f"Optimal objective value: {sol.objValue:.4f}")
print(f"Optimal solution: x = {sol.point[0]:.4f}, y = {sol.point[1]:.4f}")

# The optimum is x = 1, y = 1
assert abs(sol.objValue - 2.0) < 1e-3

Quadratic Constraints

You can also add quadratic constraints, such as circles or ellipses:

# Problem: minimize x + y subject to x^2 + y^2 <= 4 (inside a circle)
solver = SHOTpy.Solver()
problem = SHOTpy.Problem(solver)

x = problem.addVariable("x", SHOTpy.VariableType.Real, -10.0, 10.0)
y = problem.addVariable("y", SHOTpy.VariableType.Real, -10.0, 10.0)

# Linear objective
problem.setObjective(x + y, SHOTpy.ObjectiveDirection.Minimize)

# Quadratic constraint: x^2 + y^2 <= 4
problem.addConstraint(x**2 + y**2 <= 4, "circle")

# Solve
problem.finalize()
assert solver.setProblem(problem)
assert solver.solveProblem()
assert solver.getModelReturnStatus() == SHOTpy.ModelReturnStatus.OptimalGlobal

sol = solver.getPrimalSolution()
print(f"Optimal objective value: {sol.objValue:.4f}")
print(f"Optimal solution: x = {sol.point[0]:.4f}, y = {sol.point[1]:.4f}")
print(f"Distance from origin: {(sol.point[0]**2 + sol.point[1]**2)**0.5:.4f}")

# The optimum is x = y = -sqrt(2), on the circle
assert abs(sol.objValue + 2 * math.sqrt(2)) < 1e-3