Skip to content

Commit

Permalink
Merge branch 'pr/Sepuliini/49'
Browse files Browse the repository at this point in the history
  • Loading branch information
light-weaver committed Sep 25, 2023
2 parents 8511bef + 08d6fa9 commit 8707fe2
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 5 deletions.
86 changes: 86 additions & 0 deletions .github/workflows/DESDEO-tools.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: DESDEO-tools
#on: push

on:
push:
branches:
- '*'
# pull_request:
# branches:
# - master

jobs:
build:
runs-on: ubuntu-latest
steps:
#----------------------------------------------
# check-out repo and set-up python
#----------------------------------------------
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
#----------------------------------------------
# load pip cache if cache exists
#----------------------------------------------
- uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip
restore-keys: ${{ runner.os }}-pip

test:
#needs: linting
strategy:
fail-fast: true
matrix:
os: [ "ubuntu-latest" ]
python-version: [ "3.11" ]
runs-on: ${{ matrix.os }}
steps:
#----------------------------------------------
# check-out repo and set-up python
#----------------------------------------------
- name: Check out repository
uses: actions/checkout@v2
- name: Set up python ${{ matrix.python-version }}
id: setup-python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
#----------------------------------------------
# ----- install & configure poetry -----
#----------------------------------------------
- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
#----------------------------------------------
# load cached venv if cache exists
#----------------------------------------------
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v2
with:
path: .venv
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
#----------------------------------------------
# install dependencies if cache does not exist
#----------------------------------------------
- name: Install dependencies
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root
#----------------------------------------------
# install your root project, if required
#----------------------------------------------
- name: Install library
run: poetry install --no-interaction
#----------------------------------------------
# add matrix specifics and run test suite
#----------------------------------------------

- name: Run tests
id: run-tests
run: |
source .venv/bin/activate
pip install pytest-rerunfailures
pytest tests/
46 changes: 46 additions & 0 deletions .github/workflows/Lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Lint

on:
# Trigger the workflow on push or pull request,
# but only for the main branch
push:
branches:
- master
pull_request:
branches:
- master

jobs:
run-linters:
name: Run linters
runs-on: ubuntu-latest

steps:
- name: Check out Git repository
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: 3.11

- name: Install Python dependencies
run: pip install black flake8 isort

- name: Run linters
uses: wearerequired/lint-action@v1
with:
black: true
black_args: "--line-length 120"
flake8: true
flake8_args: "--max-line-length 120 --extend-ignore=E203"
isort: true
isort_args: "--apply --remove-imports"

- name: Ruff
uses: actions/checkout@v3

- name: Run Ruff
uses: chartboost/ruff-action@v1
with:
args: --config tests/pyproject.toml
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[![PyPI version](https://badge.fury.io/py/desdeo-tools.svg)](https://badge.fury.io/py/desdeo-tools)
[![Documentation Status](https://readthedocs.org/projects/desdeo-tools/badge/?version=latest)](https://desdeo-tools.readthedocs.io/en/latest/?badge=latest)
[![DESDEO-tools](https://github.com/Sepuliini/desdeo-tools/actions/workflows/DESDEO-tools.yml/badge.svg)](https://github.com/Sepuliini/desdeo-tools/actions/workflows/DESDEO-tools.yml)

# desdeo-tools

Expand Down
107 changes: 102 additions & 5 deletions desdeo_tools/solver/ScalarSolver.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# THIS CELL CAN BE REMOVED WHEN TOOLS AND PROBLEM REPOSITORYS

Check failure on line 1 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L1

Trailing whitespace (W291)
# HAVE BEEN UPDATED

"""Implements methods for solving scalar valued functions.
"""
import numpy as np
import os

from typing import Callable, Dict, Optional, Union
from desdeo_tools.scalarization.Scalarizer import DiscreteScalarizer, Scalarizer
from scipy.optimize import NonlinearConstraint, differential_evolution, minimize

from desdeo_tools.scalarization.ASF import PointMethodASF
#from desdeo_problem import variable_builder, ScalarObjective, MOProblem

Check failure on line 14 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L14

Block comment should start with '# ' (E265)


#import rbfopt

Check failure on line 17 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L17

Block comment should start with '# ' (E265)


class ScalarSolverException(Exception):
pass
Expand Down Expand Up @@ -63,6 +73,78 @@ def __call__(self, obj_fun: Callable, x0: np.ndarray, bounds: np.ndarray, constr
return res


class MixedIntegerMinimizer:

"""Implements methods for solving scalar valued functions.

Check failure on line 79 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L79

Blank line contains whitespace (W293)
Args:
scalarized_objective (Callable): The objective function that has been scalarized

Check failure on line 81 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L81

Trailing whitespace (W291)
and ready for minimization.
problem (MOProblem): A MOProblem instance required to get variable types.
minlp_solver_path (str): The path to the bonmin solver.
"""

def __init__(self, scalarized_objective: Callable, problem, minlp_solver_path: str):

Check failure on line 88 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L88

Blank line contains whitespace (W293)
# Try importing rbfopt
try:
global rbfopt
import rbfopt
except ImportError:
raise ScalarSolverException("The library 'rbfopt' is required for using MixedIntegerMinimizer. Please install it and try again.")

Check failure on line 94 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Run linters

Ruff (E501)

desdeo_tools/solver/ScalarSolver.py:94:121: E501 Line too long (141 > 120 characters)

Check failure on line 94 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L94

Line too long (141 > 120 characters) (E501)

Check failure on line 95 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L95

Blank line contains whitespace (W293)
self.scalarized_objective = scalarized_objective
self.problem = problem
self.lower_bounds = [var.get_bounds()[0] for var in self.problem.variables]
self.upper_bounds = [var.get_bounds()[1] for var in self.problem.variables]
var_types = np.array(["I" if var.type.lower() in ["i", "integervariable", "integer"] else "R" for var in problem.variables])

Check failure on line 100 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Run linters

Ruff (E501)

desdeo_tools/solver/ScalarSolver.py:100:121: E501 Line too long (132 > 120 characters)

Check failure on line 100 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L100

Line too long (132 > 120 characters) (E501)
self.var_types = var_types
self.minlp_solver_path = minlp_solver_path

print("Scalarized objectives: ", self.scalarized_objective)
print(f"Problem: {self.problem}")
print(f"Lower bounds: {self.lower_bounds}")
print(f"Upper bounds: {self.upper_bounds}")
print(f"Var_types: {self.var_types}")
print(f"minlp_solver_path: {self.minlp_solver_path}")


Check failure on line 111 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L111

Blank line contains whitespace (W293)
def create_settings(self, max_evaluations=25, nlp_solver_path="ipopt"):

Check failure on line 112 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L112

Too many blank lines (2) (E303)
settings = rbfopt.RbfoptSettings(
#'/Users/seanjana/Desktop/Työt/project_codes/COIN_Bundle/coin.macos64.20211124/bonmin'

Check failure on line 114 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L114

Block comment should start with '# ' (E265)
max_evaluations=max_evaluations,
global_search_method="solver",

Check failure on line 116 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L116

Trailing whitespace (W291)
nlp_solver_path=nlp_solver_path,

Check failure on line 117 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L117

Trailing whitespace (W291)
minlp_solver_path=self.minlp_solver_path,
print_solver_output=False

Check failure on line 119 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L119

Trailing whitespace (W291)
)
return settings

Check failure on line 122 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L122

Blank line contains whitespace (W293)
def evaluate_objective(self, x):
result = self.scalarized_objective(x)
print(f"Evaluating at {x}, result: {result}")
return result

Check failure on line 127 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L127

Blank line contains whitespace (W293)
def minimize(self, x0, **kwargs):
print(self.var_types)
bb = rbfopt.RbfoptUserBlackBox(
dimension =len(self.lower_bounds),

Check failure on line 131 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L131

Unexpected spaces around keyword / parameter equals (E251)
var_lower = self.lower_bounds,

Check failure on line 132 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L132

Unexpected spaces around keyword / parameter equals (E251)

Check failure on line 132 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L132

Unexpected spaces around keyword / parameter equals (E251)
var_upper = self.upper_bounds,

Check failure on line 133 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L133

Unexpected spaces around keyword / parameter equals (E251)

Check failure on line 133 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L133

Unexpected spaces around keyword / parameter equals (E251)
var_type = self.var_types,

Check failure on line 134 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L134

Unexpected spaces around keyword / parameter equals (E251)

Check failure on line 134 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L134

Unexpected spaces around keyword / parameter equals (E251)
obj_funct = lambda x, **kwargs: scalarized_objectives(x, **kwargs)[0]

Check failure on line 135 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Run linters

Ruff (F821)

desdeo_tools/solver/ScalarSolver.py:135:45: F821 Undefined name `scalarized_objectives`

Check failure on line 135 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L135

Unexpected spaces around keyword / parameter equals (E251)

Check failure on line 135 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L135

Unexpected spaces around keyword / parameter equals (E251)

Check failure on line 135 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L135

Undefined name 'scalarized_objectives' (F821)
)

Check failure on line 137 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L137

Blank line contains whitespace (W293)
null_stream = open(os.devnull, 'w')
alg = rbfopt.RbfoptAlgorithm(self.create_settings(), bb)
alg.set_output_stream(null_stream)

val, x, itercount, evalcount, fast_evalcount = alg.optimize()
null_stream.close()

Check failure on line 144 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L144

Blank line contains whitespace (W293)
return {'x': x, 'fun': val, 'success': itercount > 0, 'itercount': itercount, 'evalcount': evalcount, 'fast_evalcount': fast_evalcount}

Check failure on line 145 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Run linters

Ruff (E501)

desdeo_tools/solver/ScalarSolver.py:145:121: E501 Line too long (143 > 120 characters)

Check failure on line 145 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L145

Line too long (143 > 120 characters) (E501)


class ScalarMinimizer:
"""Implements a class for minimizing scalar valued functions with bounds set for the
variables, and constraints.
Expand All @@ -74,6 +156,8 @@ def __init__(
bounds: np.ndarray,
constraint_evaluator: Callable = None,
method: Optional[Union[ScalarMethod, str]] = None,
problem = None,

Check failure on line 159 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L159

Unexpected spaces around keyword / parameter equals (E251)

Check failure on line 159 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L159

Unexpected spaces around keyword / parameter equals (E251)
**kwargs
):
"""
Args:
Expand All @@ -93,12 +177,26 @@ def __init__(
of available preset solvers.
Defaults to None.
"""
self.presets = ["scipy_minimize", "scipy_de"]

self.presets = ["scipy_minimize", "scipy_de", "MixedIntegerMinimizer"]
self._scalarizer = scalarizer
self._bounds = bounds
self.problem = problem
self._constraint_evaluator = constraint_evaluator
if (method is None) or (method == "scipy_minimize"):

Check failure on line 185 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L185

Blank line contains whitespace (W293)
if method is None or method == "MixedIntegerMinimizer":
# Check if problem contains integer variables
integer_vars = any([var.type.lower() in ["i", "integervariable", "integer"] for var in problem.variables])
if integer_vars:
# Use MixedIntegerMinimizer if integer variables are found
minlp_solver_path = kwargs.get('minlp_solver_path', None)
if minlp_solver_path is None:
raise ValueError("Please provide a path to the MinLP solver via 'minlp_solver_path' keyword argument.")

Check failure on line 193 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Run linters

Ruff (E501)

desdeo_tools/solver/ScalarSolver.py:193:121: E501 Line too long (123 > 120 characters)

Check failure on line 193 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L193

Line too long (123 > 120 characters) (E501)
self._use_scipy = False
self._mixed_integer_minimizer = MixedIntegerMinimizer(self._scalarizer, problem, minlp_solver_path=minlp_solver_path)

Check failure on line 195 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Run linters

Ruff (E501)

desdeo_tools/solver/ScalarSolver.py:195:121: E501 Line too long (133 > 120 characters)

Check failure on line 195 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L195

Line too long (133 > 120 characters) (E501)
self._method = ScalarMethod(lambda x, _, **y: self._mixed_integer_minimizer.minimize(x, **y))


elif (method is None) or (method == "scipy_minimize"):

Check failure on line 199 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L199

Too many blank lines (2) (E303)
# scipy minimize
self._use_scipy = True
# Assuming the gradient reqruies evaluation of the
Expand All @@ -119,7 +217,7 @@ def __init__(
lambda x, _, **y: differential_evolution(x, **y), method_args={"polish": True}
)
self._method = scipy_de_method

Check failure on line 220 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L220

Blank line contains whitespace (W293)
else:
self._use_scipy = method._use_scipy
self._method = method
Expand Down Expand Up @@ -222,7 +320,6 @@ def minimize(self, vectors: np.ndarray) -> dict:
min_index = np.nanargmin(res)
return {"x": min_index, "fun": min_value, "success": True}


if __name__ == "__main__":

Check failure on line 323 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L323

Expected 2 blank lines after class or function definition, found 1 (E305)
from desdeo_tools.scalarization.ASF import PointMethodASF

Check failure on line 324 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Run linters

Ruff (F811)

desdeo_tools/solver/ScalarSolver.py:324:48: F811 Redefinition of unused `PointMethodASF` from line 13

Check failure on line 324 in desdeo_tools/solver/ScalarSolver.py

View workflow job for this annotation

GitHub Actions / Flake8

desdeo_tools/solver/ScalarSolver.py#L324

Redefinition of unused 'PointMethodASF' from line 13 (F811)

Expand Down
49 changes: 49 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ scipy = "^1.2"
numba = "^0.58"
hvwfg = "^1.0.2"

[tool.poetry.extras]
mixed-integer-solver = ["rbfopt"]

[tool.poetry.group.dev.dependencies]
ruff = "^0.0.291"
Expand All @@ -35,6 +37,53 @@ IPython = "^7.31.1"
ipykernel = "^5.3.0"
plotly = "^4.14.3"

[tool.ruff]
# Enable the pycodestyle (`E`) and Pyflakes (`F`) rules by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = ["E", "F"]
ignore = []

# Allow autofix for all enabled rules (when `--fix`) is provided.
fixable = []
unfixable = []

# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]
per-file-ignores = {}

# Same as Black.
line-length = 120

# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

# Assume Python 3.10.
target-version = "py311"


[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ pylint==2.16.2 ; python_version >= "3.9" and python_version < "3.11"
pyparsing==3.0.9 ; python_version >= "3.9" and python_version < "3.11"
pyrsistent==0.19.3 ; python_version >= "3.9" and python_version < "3.11"
pytest==7.2.1 ; python_version >= "3.9" and python_version < "3.11"
pytest-rerunfailures==10.1
python-dateutil==2.8.2 ; python_version >= "3.9" and python_version < "3.11"
pytz==2022.7.1 ; python_version >= "3.9" and python_version < "3.11"
pywin32==305 ; sys_platform == "win32" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "3.11"
Expand Down Expand Up @@ -114,3 +115,7 @@ wcwidth==0.2.6 ; python_version >= "3.9" and python_version < "3.11"
webencodings==0.5.1 ; python_version >= "3.9" and python_version < "3.11"
wrapt==1.15.0 ; python_version >= "3.9" and python_version < "3.11"
zipp==3.15.0 ; python_version >= "3.9" and python_version < "3.10"

rbfopt ; python_version >= "3.9" and python_version < "3.11"


0 comments on commit 8707fe2

Please sign in to comment.