All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem.OpenRaoMPSolver Maven / Gradle / Ivy

/*
 * Copyright (c) 2021, RTE (http://www.rte-france.com)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package com.powsybl.openrao.searchtreerao.linearoptimisation.algorithms.linearproblem;

import com.powsybl.openrao.commons.OpenRaoException;
import com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider;
import com.powsybl.openrao.raoapi.parameters.RangeActionsOptimizationParameters;
import com.powsybl.openrao.searchtreerao.commons.RaoUtil;
import com.powsybl.openrao.searchtreerao.result.api.LinearProblemStatus;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPSolverParameters;
import org.apache.commons.lang3.NotImplementedException;

import java.util.HashMap;
import java.util.Map;

/**
 * Encapsulates OR-Tools' MPSolver objects in order to round up doubles
 *
 * @author Philippe Edwards {@literal }
 */
public class OpenRaoMPSolver {

    private static final int NUMBER_OF_BITS_TO_ROUND_OFF = 30;
    private final MPSolver mpSolver;
    private MPSolverParameters solveConfiguration;
    Map constraints = new HashMap<>();
    Map variables = new HashMap<>();
    OpenRaoMPObjective objective;

    // Only for tests
    protected OpenRaoMPSolver() {
        mpSolver = null;
    }

    public OpenRaoMPSolver(String optProblemName, RangeActionsOptimizationParameters.Solver solver) {
        switch (solver) {
            case CBC:
                this.mpSolver = new MPSolver(optProblemName, MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING);
                break;
            case SCIP:
                this.mpSolver = new MPSolver(optProblemName, MPSolver.OptimizationProblemType.SCIP_MIXED_INTEGER_PROGRAMMING);
                break;
            case XPRESS:
                this.mpSolver = new MPSolver(optProblemName, MPSolver.OptimizationProblemType.XPRESS_MIXED_INTEGER_PROGRAMMING);
                break;
            default:
                throw new OpenRaoException(String.format("unknown solver %s in RAO parameters", solver));
        }
        solveConfiguration = new MPSolverParameters();
    }

    public OpenRaoMPConstraint getConstraint(String name) {
        if (constraints.containsKey(name)) {
            return constraints.get(name);
        } else {
            throw new OpenRaoException(String.format("Constraint %s has not been created yet", name));
        }
    }

    public OpenRaoMPVariable getVariable(String name) {
        if (variables.containsKey(name)) {
            return variables.get(name);
        } else {
            throw new OpenRaoException(String.format("Variable %s has not been created yet", name));
        }
    }

    public OpenRaoMPObjective getObjective() {
        return this.objective;
    }

    public OpenRaoMPObjective objective() {
        if (this.objective == null) {
            this.objective = new OpenRaoMPObjective(mpSolver.objective(), NUMBER_OF_BITS_TO_ROUND_OFF);
        }
        return this.objective;
    }

    public OpenRaoMPVariable makeNumVar(double lb, double ub, String name) {
        OpenRaoMPVariable mpVariable = new OpenRaoMPVariable(
            mpSolver.makeNumVar(RaoUtil.roundDouble(lb, NUMBER_OF_BITS_TO_ROUND_OFF), RaoUtil.roundDouble(ub, NUMBER_OF_BITS_TO_ROUND_OFF), name),
            NUMBER_OF_BITS_TO_ROUND_OFF
        );
        variables.put(name, mpVariable);
        return mpVariable;
    }

    public OpenRaoMPVariable makeIntVar(double lb, double ub, String name) {
        OpenRaoMPVariable mpVariable = new OpenRaoMPVariable(
            mpSolver.makeIntVar(RaoUtil.roundDouble(lb, NUMBER_OF_BITS_TO_ROUND_OFF), RaoUtil.roundDouble(ub, NUMBER_OF_BITS_TO_ROUND_OFF), name),
            NUMBER_OF_BITS_TO_ROUND_OFF
        );
        variables.put(name, mpVariable);
        return mpVariable;
    }

    public OpenRaoMPVariable makeBoolVar(String name) {
        OpenRaoMPVariable mpVariable = new OpenRaoMPVariable(mpSolver.makeBoolVar(name), NUMBER_OF_BITS_TO_ROUND_OFF);
        variables.put(name, mpVariable);
        return mpVariable;
    }

    public OpenRaoMPConstraint makeConstraint(double lb, double ub, String name) {
        OpenRaoMPConstraint mpConstraint = new OpenRaoMPConstraint(
            mpSolver.makeConstraint(RaoUtil.roundDouble(lb, NUMBER_OF_BITS_TO_ROUND_OFF), RaoUtil.roundDouble(ub, NUMBER_OF_BITS_TO_ROUND_OFF), name),
            NUMBER_OF_BITS_TO_ROUND_OFF
        );
        constraints.put(name, mpConstraint);
        return mpConstraint;
    }

    public OpenRaoMPConstraint makeConstraint(String name) {
        OpenRaoMPConstraint mpConstraint = new OpenRaoMPConstraint(mpSolver.makeConstraint(name), NUMBER_OF_BITS_TO_ROUND_OFF);
        constraints.put(name, mpConstraint);
        return mpConstraint;
    }

    public boolean setSolverSpecificParametersAsString(String solverSpecificParameters) {
        if (solverSpecificParameters != null) {
            return mpSolver.setSolverSpecificParametersAsString(solverSpecificParameters);
        } else {
            return true;
        }
    }

    public void setRelativeMipGap(double relativeMipGap) {
        solveConfiguration.setDoubleParam(MPSolverParameters.DoubleParam.RELATIVE_MIP_GAP, relativeMipGap);
    }

    public LinearProblemStatus solve() {
        if (OpenRaoLoggerProvider.TECHNICAL_LOGS.isTraceEnabled()) {
            mpSolver.enableOutput();
        }
        return convertResultStatus(mpSolver.solve(solveConfiguration));
    }

    private static LinearProblemStatus convertResultStatus(MPSolver.ResultStatus status) {
        switch (status) {
            case OPTIMAL:
                return LinearProblemStatus.OPTIMAL;
            case ABNORMAL:
                return LinearProblemStatus.ABNORMAL;
            case FEASIBLE:
                return LinearProblemStatus.FEASIBLE;
            case UNBOUNDED:
                return LinearProblemStatus.UNBOUNDED;
            case INFEASIBLE:
                return LinearProblemStatus.INFEASIBLE;
            case NOT_SOLVED:
                return LinearProblemStatus.NOT_SOLVED;
            default:
                throw new NotImplementedException(String.format("Status %s not handled.", status));
        }
    }

    public int numVariables() {
        return mpSolver.numVariables();
    }

    public int numConstraints() {
        return mpSolver.numConstraints();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy