diff --git a/highspy/highs.py b/highspy/highs.py index bc706b7882..203f714787 100644 --- a/highspy/highs.py +++ b/highspy/highs.py @@ -1,43 +1,11 @@ from highspy._highs import simplex_constants as simpc -from highspy._highs import ( - # enum classes - ObjSense, - MatrixFormat, - HessianFormat, - SolutionStatus, - BasisValidity, - HighsModelStatus, - HighsPresolveStatus, - HighsBasisStatus, - HighsVarType, - HighsOptionType, - HighsInfoType, - HighsStatus, - HighsLogType, - # classes - Highs_, - HighsSparseMatrix, - HighsLp, - HighsHessian, - HighsModel, - HighsInfo, - HighsOptions, - # structs - HighsSolution, - HighsObjectiveSolution, - HighsBasis, - HighsRangingRecord, - HighsRanging, - # constants - kHighsInf, - kHighsIInf, -) +from highspy import _highs as _h from itertools import groupby from operator import itemgetter from decimal import Decimal -class Highs(Highs_): +class Highs(_h.Highs_): """HiGHS solver interface""" __slots__ = ['_batch', '_vars', '_cons'] @@ -58,7 +26,7 @@ def minimize(self, obj): raise Exception('Objective cannot be an inequality') self.update() - super().changeObjectiveSense(ObjSense.kMinimize) + super().changeObjectiveSense(_h.ObjSense.kMinimize) # reset objective super().changeColsCost(self.numVars, range(self.numVars), [0]*self.numVars) @@ -80,7 +48,7 @@ def maximize(self, obj): raise Exception('Objective cannot be an inequality') self.update() - super().changeObjectiveSense(ObjSense.kMaximize) + super().changeObjectiveSense(_h.ObjSense.kMaximize) # reset objective super().changeColsCost(self.numVars, range(self.numVars), [0]*self.numVars) @@ -120,16 +88,16 @@ def vals(self, vars): # # add variable & useful constants # - def addVar(self, lb = 0, ub = kHighsInf, obj = 0, type=HighsVarType.kContinuous, name = None): + def addVar(self, lb = 0, ub = _h.kHighsInf, obj = 0, type=_h.HighsVarType.kContinuous, name = None): var = self._batch.add(obj, lb, ub, type, name, self) self._vars.append(var) return var - def addIntegral(self, lb = 0, ub = kHighsInf, obj = 0, name = None): - return self.addVar(lb, ub, obj, HighsVarType.kInteger, name) + def addIntegral(self, lb = 0, ub = _h.kHighsInf, obj = 0, name = None): + return self.addVar(lb, ub, obj, _h.HighsVarType.kInteger, name) def addBinary(self, obj = 0, name = None): - return self.addVar(0, 1, obj, HighsVarType.kInteger, name) + return self.addVar(0, 1, obj, _h.HighsVarType.kInteger, name) def removeVar(self, var): for i in self._vars[var.index+1:]: @@ -142,7 +110,7 @@ def getVars(self): @property def inf(self): - return kHighsInf + return _h.kHighsInf @property def numVars(self): @@ -278,8 +246,8 @@ class highs_linear_expression(object): def __init__(self, other=None): self.constant = 0 - self.LHS = -kHighsInf - self.RHS = kHighsInf + self.LHS = -_h.kHighsInf + self.RHS = _h.kHighsInf if isinstance(other, highs_linear_expression): self.vars = list(other.vars) @@ -301,7 +269,7 @@ def __neg__(self): # (LHS <= self <= RHS) <= (other.LHS <= other <= other.RHS) def __le__(self, other): if isinstance(other, highs_linear_expression): - if self.LHS != -kHighsInf and self.RHS != kHighsInf and len(other.vars) > 0 or other.LHS != -kHighsInf: + if self.LHS != -_h.kHighsInf and self.RHS != _h.kHighsInf and len(other.vars) > 0 or other.LHS != -_h.kHighsInf: raise Exception('Cannot construct constraint with variables as bounds.') # move variables from other to self @@ -324,7 +292,7 @@ def __le__(self, other): # (LHS <= self <= RHS) == (other.LHS <= other <= other.RHS) def __eq__(self, other): if isinstance(other, highs_linear_expression): - if self.LHS != -kHighsInf and len(other.vars) > 0 or other.LHS != -kHighsInf: + if self.LHS != -_h.kHighsInf and len(other.vars) > 0 or other.LHS != -_h.kHighsInf: raise Exception('Cannot construct constraint with variables as bounds.') # move variables from other to self @@ -339,7 +307,7 @@ def __eq__(self, other): return NotImplemented elif isinstance(other, (int, float, Decimal)): - if self.LHS != -kHighsInf or self.RHS != kHighsInf: + if self.LHS != -_h.kHighsInf or self.RHS != _h.kHighsInf: raise Exception('Logic error in constraint equality.') self.LHS = other diff --git a/highspy/highs_bindings.cpp b/highspy/highs_bindings.cpp index 988386ae87..0f9dbac037 100644 --- a/highspy/highs_bindings.cpp +++ b/highspy/highs_bindings.cpp @@ -3,6 +3,10 @@ #include #include +#include +#include + +#include "lp_data/HighsOptions.h" #include "Highs.h" @@ -548,6 +552,55 @@ std::tuple highs_getRowByName(Highs* h, return std::make_tuple(status, row); } +// highs_options.cpp +bool log_to_console = false; +bool output_flag = true; +HighsLogOptions highs_log_options = {nullptr, &output_flag, &log_to_console, + nullptr}; + +class HighsOptionsManager { + public: + HighsOptionsManager() { + for (const auto& record : highs_options_.records) { + record_type_lookup_.emplace(record->name, record->type); + } + } + + const HighsOptions& get_highs_options() const { return highs_options_; } + + const std::map& get_record_type_lookup() const { + return record_type_lookup_; + } + + template + bool check_option(const std::string& name, const T value) { + std::lock_guard guard(highs_options_mutex); + HighsInt idx = 0; + const OptionStatus idx_status = getOptionIndex( + highs_log_options, name.c_str(), highs_options_.records, idx); + + if (OptionStatus::kOk != idx_status) { + return false; + } + + OptionRecordType& record = + static_cast(*highs_options_.records.at(idx)); + const OptionStatus check_status = + checkOptionValue(highs_log_options, record, value); + if (OptionStatus::kIllegalValue == check_status) { + return false; + } + + return true; + } + + private: + HighsOptions highs_options_; + std::mutex highs_options_mutex; + std::map record_type_lookup_; +}; + + PYBIND11_MODULE(_highs, m) { // enum classes py::enum_(m, "ObjSense") @@ -951,6 +1004,44 @@ PYBIND11_MODULE(_highs, m) { m.attr("kHighsInf") = kHighsInf; m.attr("kHighsIInf") = kHighsIInf; // Submodules + // Highs Options + py::module_ highs_options = + m.def_submodule("highs_options", "Submodule for highs options"); + py::class_(highs_options, "HighsOptionsManager") + .def(py::init<>()) + .def("get_option_type", + [](const HighsOptionsManager& manager, const std::string& name) { + const auto& lookup = manager.get_record_type_lookup().find(name); + if (manager.get_record_type_lookup().end() == lookup) { + return -1; + } + return static_cast(lookup->second); + }) + .def("get_all_option_types", &HighsOptionsManager::get_record_type_lookup) + .def("get_highs_options_records", + [](const HighsOptionsManager& manager) { + std::vector records_names; + for (const auto& record : manager.get_highs_options().records) { + records_names.push_back(record->name); + } + return records_names; + }) + .def("check_int_option", + [](HighsOptionsManager& self, const std::string& name, int value) { + return self.check_option(name, value); + }) + .def( + "check_double_option", + [](HighsOptionsManager& self, const std::string& name, double value) { + return self.check_option(name, value); + }) + .def("check_string_option", [](HighsOptionsManager& self, + const std::string& name, + const std::string& value) { + return self.check_option(name, value); + }); + + // Simplex Constants py::module_ simplex_constants = m.def_submodule("simplex_constants", "Submodule for simplex constants"); diff --git a/highspy/highs_options.cpp b/highspy/highs_options.cpp deleted file mode 100644 index 05eb0f3d11..0000000000 --- a/highspy/highs_options.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include - -#include -#include - -#include "lp_data/HighsOptions.h" - -namespace py = pybind11; - -bool log_to_console = false; -bool output_flag = true; -HighsLogOptions highs_log_options = {nullptr, &output_flag, &log_to_console, - nullptr}; - -class HighsOptionsManager { - public: - HighsOptionsManager() { - for (const auto& record : highs_options_.records) { - record_type_lookup_.emplace(record->name, record->type); - } - } - - const HighsOptions& get_highs_options() const { return highs_options_; } - - const std::map& get_record_type_lookup() const { - return record_type_lookup_; - } - - template - bool check_option(const std::string& name, const T value) { - std::lock_guard guard(highs_options_mutex); - HighsInt idx = 0; - const OptionStatus idx_status = getOptionIndex( - highs_log_options, name.c_str(), highs_options_.records, idx); - - if (OptionStatus::kOk != idx_status) { - return false; - } - - OptionRecordType& record = - static_cast(*highs_options_.records.at(idx)); - const OptionStatus check_status = - checkOptionValue(highs_log_options, record, value); - if (OptionStatus::kIllegalValue == check_status) { - return false; - } - - return true; - } - - private: - HighsOptions highs_options_; - std::mutex highs_options_mutex; - std::map record_type_lookup_; -}; - -PYBIND11_MODULE(_highs_options, m) { - py::class_(m, "HighsOptionsManager") - .def(py::init<>()) - .def("get_option_type", - [](const HighsOptionsManager& manager, const std::string& name) { - const auto& lookup = manager.get_record_type_lookup().find(name); - if (manager.get_record_type_lookup().end() == lookup) { - return -1; - } - return static_cast(lookup->second); - }) - .def("get_all_option_types", &HighsOptionsManager::get_record_type_lookup) - .def("get_highs_options_records", - [](const HighsOptionsManager& manager) { - std::vector records_names; - for (const auto& record : manager.get_highs_options().records) { - records_names.push_back(record->name); - } - return records_names; - }) - .def("check_int_option", - [](HighsOptionsManager& self, const std::string& name, int value) { - return self.check_option(name, value); - }) - .def( - "check_double_option", - [](HighsOptionsManager& self, const std::string& name, double value) { - return self.check_option(name, value); - }) - .def("check_string_option", [](HighsOptionsManager& self, - const std::string& name, - const std::string& value) { - return self.check_option(name, value); - }); -} diff --git a/highspy/meson.build b/highspy/meson.build index b16ccccf81..9b5e964a58 100644 --- a/highspy/meson.build +++ b/highspy/meson.build @@ -15,16 +15,6 @@ py.extension_module( include_directories: _incdirs, ) -py.extension_module( - '_highs_options', - sources : highsoptions_cpp, - dependencies: [pyb11_dep, highs_dep], - cpp_args: _args, - install: true, - subdir: 'highspy', - include_directories: _incdirs, -) - py.install_sources( highspy_py, subdir: 'highspy', diff --git a/meson.build b/meson.build index d12a08f418..1c85ecd74f 100644 --- a/meson.build +++ b/meson.build @@ -139,9 +139,6 @@ if get_option('with_pybind11') highspy_cpp = files([ 'highspy/highs_bindings.cpp' ]) - highsoptions_cpp = files([ - 'highspy/highs_options.cpp' - ]) highspy_py = files([ 'highspy/__init__.py', 'highspy/highs.py',