Skip to main content
Glama

simple_highs_solver

Solve linear programming problems using a simplified HiGHs interface without complex model structures. Input objective coefficients, constraints, and variables to get optimization solutions.

Instructions

A simplified interface for solving HiGHs linear programming problems.

This tool provides a more straightforward interface for HiGHs problems,
without requiring the full HiGHSProblem model structure.

Args:
    sense: Optimization sense, either "minimize" or "maximize"
    objective_coeffs: List of objective function coefficients
    variables: List of variable definitions with optional bounds and types
    constraint_matrix: 2D list representing the constraint matrix (dense format)
    constraint_senses: List of constraint directions ("<=", ">=", "=")
    rhs_values: List of right-hand side values for constraints
    options: Optional solver options dictionary
    description: Optional description of the problem

Returns:
    A list of TextContent containing the solution or an error message

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
senseYes
objective_coeffsYes
variablesYes
constraint_matrixYes
constraint_sensesYes
rhs_valuesYes
optionsNo
descriptionNo

Implementation Reference

  • MCP tool handler: validates parameters, builds HiGHSProblem from simple inputs using Pydantic models, solves with imported solve_highs_problem, formats result as TextContent.
    @app.tool("simple_highs_solver")
    async def simple_highs_solver(
        sense: str,
        objective_coeffs: list[float],
        variables: list[dict[str, Any]],
        constraint_matrix: list[list[float]],
        constraint_senses: list[str],
        rhs_values: list[float],
        options: dict[str, Any] | None = None,
        description: str = "",
    ) -> list[TextContent]:
        """A simplified interface for solving HiGHs linear programming problems.
    
        This tool provides a more straightforward interface for HiGHs problems,
        without requiring the full HiGHSProblem model structure.
    
        Args:
            sense: Optimization sense, either "minimize" or "maximize"
            objective_coeffs: List of objective function coefficients
            variables: List of variable definitions with optional bounds and types
            constraint_matrix: 2D list representing the constraint matrix (dense format)
            constraint_senses: List of constraint directions ("<=", ">=", "=")
            rhs_values: List of right-hand side values for constraints
            options: Optional solver options dictionary
            description: Optional description of the problem
    
        Returns:
            A list of TextContent containing the solution or an error message
        """
        try:
            # Validate sense
            try:
                problem_sense = HiGHSSense(sense)
            except ValueError:
                return [
                    TextContent(
                        type="text",
                        text=(
                            f"Invalid sense: {sense}. "
                            f"Must be one of: {', '.join([s.value for s in HiGHSSense])}"
                        ),
                    )
                ]
    
            # Create objective
            objective = HiGHSObjective(linear=objective_coeffs)
    
            # Create variables
            problem_variables = []
            for i, var in enumerate(variables):
                var_name = var.get("name", f"x{i+1}")
                var_lb = var.get("lb", 0.0)
                var_ub = var.get("ub", None)
                var_type_str = var.get("type", "cont")
    
                try:
                    var_type = HiGHSVariableType(var_type_str)
                except ValueError:
                    return [
                        TextContent(
                            type="text",
                            text=(
                                f"Invalid variable type: {var_type_str}. "
                                f"Must be one of: {', '.join([t.value for t in HiGHSVariableType])}"
                            ),
                        )
                    ]
    
                problem_variables.append(
                    HiGHSVariable(name=var_name, lb=var_lb, ub=var_ub, type=var_type)
                )
    
            # Create constraints
            constraint_sense_enums = []
            for sense_str in constraint_senses:
                try:
                    constraint_sense_enums.append(HiGHSConstraintSense(sense_str))
                except ValueError:
                    return [
                        TextContent(
                            type="text",
                            text=(
                                f"Invalid constraint sense: {sense_str}. "
                                f"Must be one of: {', '.join([s.value for s in HiGHSConstraintSense])}"
                            ),
                        )
                    ]
    
            constraints = HiGHSConstraints(
                dense=constraint_matrix,
                sparse=None,
                sense=constraint_sense_enums,
                rhs=rhs_values,
            )
    
            # Create problem specification
            problem_spec = HiGHSProblemSpec(
                sense=problem_sense,
                objective=objective,
                variables=problem_variables,
                constraints=constraints,
            )
    
            # Create options if provided
            highs_options = None
            if options:
                highs_options = HiGHSOptions(**options)
    
            # Create full problem
            problem = HiGHSProblem(problem=problem_spec, options=highs_options)
    
            # Solve the problem
            result = solve_highs_problem(problem)
    
            match result:
                case Success(solution):
                    return [
                        TextContent(
                            type="text",
                            text=json.dumps(
                                {
                                    "status": solution.status.value,
                                    "objective_value": solution.objective_value,
                                    "solution": solution.solution,
                                    "dual_solution": solution.dual_solution,
                                    "variable_duals": solution.variable_duals,
                                }
                            ),
                        )
                    ]
                case Failure(error):
                    return [
                        TextContent(type="text", text=f"Error solving problem: {error}")
                    ]
                case _:
                    return [
                        TextContent(
                            type="text",
                            text="Unexpected error in simple_highs_solver",
                        )
                    ]
        except Exception as e:
            return [TextContent(type="text", text=f"Error in simple_highs_solver: {e!s}")]
  • FastMCP tool registration decorator for simple_highs_solver.
    @app.tool("simple_highs_solver")
  • Core solver logic (imported as solve_highs_problem): interfaces with highspy.Highs to set up LP/MIP, apply options, solve, and return HiGHSOutput.
    def solve_problem(problem: HiGHSProblem) -> Result[HiGHSOutput, str]:
        """Solve a HiGHs optimization problem."""
        try:
            # Create HiGHs instance
            h = highspy.Highs()
    
            # Always disable output for MCP server compatibility
            h.setOptionValue("output_flag", False)
            h.setOptionValue("log_to_console", False)
    
            # Apply options
            options_result = _apply_options(h, problem.options)
            if isinstance(options_result, Failure):
                return options_result
    
            problem_spec = problem.problem
            num_vars = len(problem_spec.variables)
            num_constraints = len(problem_spec.constraints.sense)
    
            # Set up objective
            obj_coeffs = np.array(problem_spec.objective.linear, dtype=float)
            if len(obj_coeffs) != num_vars:
                return Failure(
                    f"Objective coefficients length ({len(obj_coeffs)}) doesn't match number of variables ({num_vars})"
                )
    
            # Set up variable bounds
            var_lower = np.zeros(num_vars, dtype=float)
            var_upper = np.full(num_vars, highspy.kHighsInf, dtype=float)
    
            for i, var_spec in enumerate(problem_spec.variables):
                lb, ub = _get_variable_bounds(var_spec, i)
                var_lower[i] = lb
                var_upper[i] = ub
    
            # Build constraint matrix
            matrix_result = _build_constraint_matrix(problem_spec)
            if isinstance(matrix_result, Failure):
                return matrix_result
    
            rows, cols, values = matrix_result.unwrap()
    
            # Set up constraint bounds
            constraint_lower = np.zeros(num_constraints, dtype=float)
            constraint_upper = np.zeros(num_constraints, dtype=float)
    
            for i, (sense, rhs) in enumerate(
                zip(
                    problem_spec.constraints.sense,
                    problem_spec.constraints.rhs,
                    strict=False,
                )
            ):
                lb, ub = _convert_constraint_sense(sense, rhs)
                constraint_lower[i] = lb
                constraint_upper[i] = ub
    
            # Add variables
            h.addCols(
                num_vars,
                obj_coeffs,
                var_lower,
                var_upper,
                0,
                np.array([]),
                np.array([]),
                np.array([]),
            )
    
            # Set variable integrality constraints
            integrality = np.zeros(num_vars, dtype=int)  # 0 = continuous
            for i, var_spec in enumerate(problem_spec.variables):
                if var_spec.type == HiGHSVariableType.BINARY:
                    integrality[i] = 1  # 1 = integer (binary is integer with bounds 0-1)
                elif var_spec.type == HiGHSVariableType.INTEGER:
                    integrality[i] = 1  # 1 = integer
                # else: continuous (already 0)
    
            # Apply integrality constraints if any variables are integer/binary
            if np.any(integrality > 0):
                h.changeColsIntegrality(num_vars, np.arange(num_vars), integrality)
    
            # Add constraints using sparse format
            if len(rows) > 0:
                # Convert to row-wise sparse format for HiGHs
                # Group by rows and create start array
                unique_rows = np.unique(rows)
                start_array = np.zeros(num_constraints + 1, dtype=int)
    
                for row in unique_rows:
                    start_array[row] = np.sum(rows < row)
    
                start_array[-1] = len(rows)  # Final start
    
                h.addRows(
                    num_constraints,
                    constraint_lower,
                    constraint_upper,
                    len(values),
                    start_array,
                    cols,
                    values,
                )
            else:
                # No constraints case
                h.addRows(
                    num_constraints,
                    constraint_lower,
                    constraint_upper,
                    0,
                    np.array([0]),
                    np.array([]),
                    np.array([]),
                )
    
            # Set objective sense
            if problem_spec.sense == HiGHSSense.MAXIMIZE:
                h.changeObjectiveSense(highspy.ObjSense.kMaximize)
            else:
                h.changeObjectiveSense(highspy.ObjSense.kMinimize)
    
            # Solve the problem
            h.run()
    
            # Get results
            model_status = h.getModelStatus()
            solution = h.getSolution()
            info = h.getInfo()
    
            # Convert status
            status = _convert_status(model_status)
    
            # Extract solution values
            solution_values = solution.col_value if hasattr(solution, "col_value") else []
            dual_values = solution.row_dual if hasattr(solution, "row_dual") else []
            reduced_costs = solution.col_dual if hasattr(solution, "col_dual") else []
    
            # Get objective value
            objective_value = (
                info.objective_function_value
                if hasattr(info, "objective_function_value")
                else 0.0
            )
    
            return Success(
                HiGHSOutput(
                    status=status,
                    objective_value=objective_value,
                    solution=list(solution_values),
                    dual_solution=list(dual_values),
                    variable_duals=list(reduced_costs),
                )
            )
    
        except Exception as e:
            return Failure(f"Error solving HiGHs problem: {e}")
  • Pydantic models defining structure for HiGHS problems used internally by the handler (HiGHSProblem, HiGHSProblemSpec, HiGHSObjective, HiGHSVariable, HiGHSConstraints, etc.).
    class HiGHSProblem(BaseModel):
        """Complete HiGHS optimization problem."""
    
        problem: HiGHSProblemSpec = Field(..., description="Problem specification")
        options: HiGHSOptions | None = Field(None, description="Solver options")
  • Simplified highs solver wrapper (duplicated logic in MCP handler, used directly in example scripts).
    def simple_highs_solver(
        sense: str,
        objective_coeffs: list[float],
        variables: list[dict],
        constraint_matrix: list[list[float]],
        constraint_senses: list[str],
        rhs_values: list[float],
        options: dict | None = None,
        description: str = "",
    ) -> Result[HiGHSOutput, str]:
        """A simplified interface for solving HiGHs linear programming problems.
    
        This function provides a more straightforward interface for HiGHs problems,
        without requiring the full HiGHSProblem model structure.
    
        Args:
            sense: Optimization sense, either "minimize" or "maximize"
            objective_coeffs: List of objective function coefficients
            variables: List of variable definitions with optional bounds and types
            constraint_matrix: 2D list representing the constraint matrix (dense format)
            constraint_senses: List of constraint directions ("<=", ">=", "=")
            rhs_values: List of right-hand side values for constraints
            options: Optional solver options dictionary
            description: Optional description of the problem
    
        Returns:
            Result containing HiGHSOutput or error message
        """
        try:
            # Validate sense
            try:
                problem_sense = HiGHSSense(sense)
            except ValueError:
                return Failure(
                    f"Invalid sense: {sense}. "
                    f"Must be one of: {', '.join([s.value for s in HiGHSSense])}"
                )
    
            # Create objective
            objective = HiGHSObjective(linear=objective_coeffs)
    
            # Create variables
            problem_variables = []
            for i, var in enumerate(variables):
                var_name = var.get("name", f"x{i+1}")
                var_lb = var.get("lb", 0.0)
                var_ub = var.get("ub", None)
                var_type_str = var.get("type", "cont")
    
                try:
                    var_type = HiGHSVariableType(var_type_str)
                except ValueError:
                    return Failure(
                        f"Invalid variable type: {var_type_str}. "
                        f"Must be one of: {', '.join([t.value for t in HiGHSVariableType])}"
                    )
    
                problem_variables.append(
                    HiGHSVariable(name=var_name, lb=var_lb, ub=var_ub, type=var_type)
                )
    
            # Create constraints
            constraint_sense_enums = []
            for sense_str in constraint_senses:
                try:
                    constraint_sense_enums.append(HiGHSConstraintSense(sense_str))
                except ValueError:
                    return Failure(
                        f"Invalid constraint sense: {sense_str}. "
                        f"Must be one of: {', '.join([s.value for s in HiGHSConstraintSense])}"
                    )
    
            constraints = HiGHSConstraints(
                dense=constraint_matrix,
                sparse=None,
                sense=constraint_sense_enums,
                rhs=rhs_values,
            )
    
            # Create problem specification
            problem_spec = HiGHSProblemSpec(
                sense=problem_sense,
                objective=objective,
                variables=problem_variables,
                constraints=constraints,
            )
    
            # Create options if provided
            highs_options = None
            if options:
                highs_options = HiGHSOptions(**options)
    
            # Create full problem
            problem = HiGHSProblem(problem=problem_spec, options=highs_options)
    
            # Solve the problem
            return solve_problem(problem)
    
        except Exception as e:
            return Failure(f"Error in simple_highs_solver: {e!s}")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sdiehl/usolver'

If you have feedback or need assistance with the MCP directory API, please join our Discord server