Source code for VeraGridEngine.Utils.MIP.selected_interface

# 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 https://mozilla.org/MPL/2.0/.  
# SPDX-License-Identifier: MPL-2.0

"""
Uncomment the appropriate interface imports to use: Pulp or OrTools
"""
from typing import List, Union, Tuple
import numpy as np
from scipy.sparse import csc_matrix
from VeraGridEngine.basic_structures import ObjVec, ObjMat
from VeraGridEngine.enumerations import MIPFramework, MIPSolvers

from VeraGridEngine.Utils.MIP.pulp_interface import (LpExp as PulpLpExp,
                                                     LpVar as PulpLpVar,
                                                     PulpLpModel,
                                                     get_pulp_available_mip_solvers)

try:
    from VeraGridEngine.Utils.MIP.ortools_interface import (LpExp as OrToolsLpExp,
                                                            LpVar as OrToolsLpVar,
                                                            OrToolsLpModel,
                                                            get_ortools_available_mip_solvers)

    ORTOOLS_AVAILABLE = True
except ImportError:
    ORTOOLS_AVAILABLE = False
    OrToolsLpModel = None
    OrToolsLpExp = None
    OrToolsLpVar = None
    get_ortools_available_mip_solvers = None

LpExp = Union[PulpLpExp, OrToolsLpExp]
LpVar = Union[PulpLpVar, OrToolsLpVar]
LpModel = Union[PulpLpModel, OrToolsLpModel]


[docs] def get_available_mip_frameworks() -> List[MIPFramework]: """ Get list of available frameworks :return: List[MIPFramework] """ lst = [MIPFramework.PuLP] if ORTOOLS_AVAILABLE: lst.append(MIPFramework.OrTools) return lst
[docs] def get_model_instance(tpe: MIPFramework, solver_type: MIPSolvers) -> LpModel: """ Get an instance of the solver framework and the selected solver :param tpe: MIPInterface framework :param solver_type: MIPSolvers :return: OrToolsLpModel or PulpLpModel """ if tpe == MIPFramework.OrTools and ORTOOLS_AVAILABLE: return OrToolsLpModel(solver_type) elif tpe == MIPFramework.PuLP: return PulpLpModel(solver_type) else: return PulpLpModel(solver_type)
[docs] def get_available_mip_solvers(tpe: MIPFramework) -> List[str]: """ Get the solvers available in the selected interface :param tpe: :return: """ if tpe == MIPFramework.OrTools and ORTOOLS_AVAILABLE: return get_ortools_available_mip_solvers() elif tpe == MIPFramework.PuLP: return get_pulp_available_mip_solvers() else: return get_pulp_available_mip_solvers()
[docs] def join(init: str, vals: List[int], sep="_"): """ Generate naming string :param init: initial string :param vals: concatenation of indices :param sep: separator :return: naming string """ return init + sep.join([str(x) for x in vals])
[docs] def lpDot(mat: csc_matrix, arr: Union[ObjVec, ObjMat]) -> Union[ObjVec, ObjMat]: """ CSC matrix-vector or CSC matrix-matrix dot product (A x b) :param mat: CSC sparse matrix (A) :param arr: dense vector or matrix of object type (b) :return: vector or matrix result of the product """ n_rows, n_cols = mat.shape # check dimensional compatibility assert (n_cols == arr.shape[0]) # check that the sparse matrix is indeed of CSC format if mat.format != 'csc': raise Exception("lpDot: Sparse matrix must be in CSC format") if arr.ndim == 1: """ Uni-dimensional sparse matrix - vector product """ res = np.zeros(n_rows, dtype=arr.dtype) for i in range(n_cols): for ii in range(mat.indptr[i], mat.indptr[i + 1]): j = mat.indices[ii] # row index if mat.data[ii] != 0.0: res[j] += mat.data[ii] * arr[i] # C.data[ii] is equivalent to C[i, j] return res elif arr.ndim == 2: """ Multi-dimensional sparse matrix - matrix product """ cols_vec = arr.shape[1] res = np.zeros((n_rows, cols_vec), dtype=arr.dtype) for k in range(cols_vec): # for each column of the matrix "vec", do the matrix vector product for i in range(n_cols): for ii in range(mat.indptr[i], mat.indptr[i + 1]): j = mat.indices[ii] # row index if mat.data[ii] != 0.0: res[j, k] += mat.data[ii] * arr[i, k] # C.data[ii] is equivalent to C[i, j] return res else: raise Exception("lpDot: Unsupported number of dimensions")
[docs] def lpDot1D_changes(mat: csc_matrix, arr: Union[ObjVec, ObjMat]) -> Tuple[ObjVec, List[int]]: """ CSC matrix-vector or CSC matrix-matrix dot product (A x b) :param mat: CSC sparse matrix (A) :param arr: dense vector or matrix of object type (b) :return: vector or matrix result of the product """ n_rows, n_cols = mat.shape # check dimensional compatibility assert (n_cols == arr.shape[0]) # check that the sparse matrix is indeed of CSC format if mat.format != 'csc': raise Exception("lpDot: Sparse matrix must be in CSC format") if arr.ndim == 1: """ Uni-dimensional sparse matrix - vector product """ res = np.zeros(n_rows, dtype=arr.dtype) indices = list() for i in range(n_cols): for ii in range(mat.indptr[i], mat.indptr[i + 1]): j = mat.indices[ii] # row index if mat.data[ii] != 0.0: res[j] += mat.data[ii] * arr[i] # C.data[ii] is equivalent to C[i, j] indices.append(j) return res, indices else: raise Exception("lpDot1D_changes: Unsupported number of dimensions")