Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default dtype and device to SB environment #38

Merged
merged 13 commits into from
Nov 17, 2023
9 changes: 5 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ jobs:
test:
strategy:
matrix:
python: ["3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10"]
os: [ubuntu-latest, windows-latest, macos-latest]

name: Install and test package on ${{ matrix.os }} for Python ${{ matrix.python }}
name: Install and test package on ${{ matrix.os }} for Python ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup Python ${{ matrix.python }}
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
python-version: ${{ matrix.python-version }}

- name: Install package [pip]
run: |
Expand All @@ -53,6 +53,7 @@ jobs:
python .github/scripts/metadata_checker

- name: Upload coverage to Codecov
if: ${{ matrix.python-version == '3.8' && matrix.os == 'ubuntu-latest' }}
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
3 changes: 2 additions & 1 deletion src/simulated_bifurcation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@


from . import models
from .optimizer import ConvergenceWarning, get_env, reset_env, set_env
from .environment import get_env, reset_env, set_env
from .optimizer.simulated_bifurcation_optimizer import ConvergenceWarning
from .polynomial import (
BinaryPolynomial,
BinaryQuadraticPolynomial,
Expand Down
67 changes: 67 additions & 0 deletions src/simulated_bifurcation/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from typing import Dict, Optional

from .optimizer.optimization_variables import OptimizationVariable


def get_env() -> Dict[str, float]:
"""
Returns the values of the quantum physical constants behind the
Simulated Bifurcation algorithm.
"""
return {variable.name: variable.get() for variable in OptimizationVariable}


def set_env(
*,
time_step: Optional[float] = None,
pressure_slope: Optional[float] = None,
heat_coefficient: Optional[float] = None,
):
"""
Override the values of the pre-set and fine-tuned quantum physical
constants behind the Simulated Bifurcation algorithm.

Parameters
----------
time_step: float, optional
Temporal discretization step.
pressure_slope: float, optional
Adiabatic system evolution rate.
heat_coefficient: float, optional
Influence of heating for HbSB or HdSB.

Notes
-----
All parameters are keyword-only and optional with a default
value to `None`. `None` means that the variable is not
changed in the environment.

See Also
--------
To set a default dtype and a default device for tensors
please use `torch.set_default_dtype` and
`torch.set_default_device`.
"""
if (
(time_step is None or isinstance(time_step, float))
and (pressure_slope is None or isinstance(pressure_slope, float))
and (heat_coefficient is None or isinstance(heat_coefficient, float))
):
OptimizationVariable.TIME_STEP.set(time_step)
OptimizationVariable.PRESSURE_SLOPE.set(pressure_slope)
OptimizationVariable.HEAT_COEFFICIENT.set(heat_coefficient)
else:
raise TypeError("All optimization variables must be floats.")


def reset_env() -> None:
"""
Reset the Simulated Bifurcation algorithm quantum physical
constants to their original fine-tuned value:

- time step: 0.1
- pressure slope: 0.01
- heat coefficient: 0.06
"""
for variable in OptimizationVariable:
variable.reset()
4 changes: 2 additions & 2 deletions src/simulated_bifurcation/ising_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ def __init__(
self,
J: Union[torch.Tensor, ndarray],
h: Union[torch.Tensor, ndarray, None] = None,
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
self.dimension = J.shape[0]
if isinstance(J, ndarray):
Expand Down
6 changes: 3 additions & 3 deletions src/simulated_bifurcation/models/ising.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Union
from typing import Optional, Union

import numpy as np
import torch
Expand All @@ -21,8 +21,8 @@ def __init__(
self,
J: Union[torch.Tensor, np.ndarray],
h: Union[torch.Tensor, np.ndarray, None] = None,
dtype: torch.dtype = torch.float32,
device: str = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
super().__init__(-0.5 * J, h, None, dtype, device)
self.J = J
Expand Down
6 changes: 3 additions & 3 deletions src/simulated_bifurcation/models/knapsack.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from enum import Enum
from typing import Dict, List, Union
from typing import Dict, List, Optional, Union

import numpy as np
import torch
Expand All @@ -19,8 +19,8 @@ def __init__(
weights: List[int],
costs: List[Union[int, float]],
max_weight: int,
dtype: torch.dtype = torch.float32,
device: str = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
self.weights = weights[:]
self.costs = costs[:]
Expand Down
8 changes: 4 additions & 4 deletions src/simulated_bifurcation/models/markowitz.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def __init__(
initial_stocks: Optional[Union[torch.Tensor, np.ndarray]] = None,
risk_coefficient: float = 1,
number_of_bits: int = 1,
dtype: torch.dtype = torch.float32,
device: str = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
"""
covariances : T x N x N
Expand Down Expand Up @@ -114,8 +114,8 @@ def __init__(
expected_return: Union[torch.Tensor, np.ndarray],
risk_coefficient: float = 1,
number_of_bits: int = 1,
dtype: torch.dtype = torch.float32,
device: str = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
covariance = torch.unsqueeze(covariance, 0)
expected_return = torch.unsqueeze(expected_return, 0)
Expand Down
7 changes: 5 additions & 2 deletions src/simulated_bifurcation/models/number_partitioning.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Union
from typing import Dict, List, Optional, Union

import torch
from numpy import sum
Expand All @@ -14,7 +14,10 @@ class NumberPartitioning(SpinQuadraticPolynomial):
"""

def __init__(
self, numbers: list, dtype: torch.dtype = torch.float32, device: str = "cpu"
self,
numbers: list,
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
self.numbers = numbers
tensor_numbers = torch.tensor(self.numbers, dtype=dtype, device=device).reshape(
Expand Down
6 changes: 3 additions & 3 deletions src/simulated_bifurcation/models/qubo.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Union
from typing import Optional, Union

import numpy as np
import torch
Expand All @@ -18,8 +18,8 @@ class QUBO(BinaryQuadraticPolynomial):
def __init__(
self,
Q: Union[torch.Tensor, np.ndarray],
dtype: torch.dtype = torch.float32,
device: str = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
super().__init__(Q, None, None, dtype, device)
self.Q = self.matrix
1 change: 0 additions & 1 deletion src/simulated_bifurcation/optimizer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .optimization_variables import get_env, reset_env, set_env
from .optimizer_mode import OptimizerMode
from .simulated_bifurcation_optimizer import (
ConvergenceWarning,
Expand Down
40 changes: 7 additions & 33 deletions src/simulated_bifurcation/optimizer/optimization_variables.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,19 @@
import os
from enum import Enum
from typing import Dict, Optional
from typing import Optional


def get_env() -> Dict[str, float]:
return {variable.name: variable.get() for variable in OptimizationVariable}


def set_env(
time_step: Optional[float] = None,
pressure_slope: Optional[float] = None,
heat_coefficient: Optional[float] = None,
):
if (
(time_step is None or isinstance(time_step, float))
and (pressure_slope is None or isinstance(pressure_slope, float))
and (heat_coefficient is None or isinstance(heat_coefficient, float))
):
OptimizationVariable.TIME_STEP.set(time_step)
OptimizationVariable.PRESSURE_SLOPE.set(pressure_slope)
OptimizationVariable.HEAT_COEFFICIENT.set(heat_coefficient)
return
raise TypeError(f"All optimization variables must be floats.")


def reset_env() -> None:
for variable in OptimizationVariable:
variable.reset()
ENV_PREFIX = "PYTHON_SB_"


class OptimizationVariable(Enum):
TIME_STEP = 0.1, "PYTHON_SB_TIME_STEP"
PRESSURE_SLOPE = 0.01, "PYTHON_SB_PRESSURE_SLOPE"
HEAT_COEFFICIENT = 0.06, "PYTHON_SB_HEAT_COEFFICIENT"
TIME_STEP = 0.1
PRESSURE_SLOPE = 0.01
HEAT_COEFFICIENT = 0.06

def __init__(self, default_value: float, env_name: str) -> None:
def __init__(self, default_value: float) -> None:
super().__init__()
self.__default_value = default_value
self.__name = env_name[10:].replace("_", " ").lower()
self.__env_name = env_name
self.__env_name = ENV_PREFIX + self.name
self.reset()

def set(self, value: Optional[float]) -> None:
Expand All @@ -47,7 +22,6 @@ def set(self, value: Optional[float]) -> None:
if not isinstance(value, float):
raise TypeError(f"Expected a float but got a {type(value)}.")
os.environ[self.__env_name] = str(value)
print(f"Simulated Bifurcation optimizer's {self.__name} set to {value}.")

def get(self) -> float:
return float(os.environ[self.__env_name])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def __init__(
vector: Union[torch.Tensor, np.ndarray, None] = None,
constant: Union[int, float, None] = None,
accepted_values: Union[torch.Tensor, np.ndarray, List[int], None] = None,
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
"""
Parameters
Expand Down Expand Up @@ -156,6 +156,8 @@ def __len__(self) -> int:

@staticmethod
def __check_device(device: Union[str, torch.device]):
if device is None:
return
if isinstance(device, torch.device):
device = device.type
elif not isinstance(device, str):
Expand Down
4 changes: 2 additions & 2 deletions src/simulated_bifurcation/polynomial/binary_polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ def __init__(
matrix: Union[torch.Tensor, np.ndarray],
vector: Union[torch.Tensor, np.ndarray, None] = None,
constant: Union[float, int, None] = None,
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
super().__init__(matrix, vector, constant, [0, 1], dtype, device)

Expand Down
4 changes: 2 additions & 2 deletions src/simulated_bifurcation/polynomial/integer_polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ def __init__(
vector: Union[torch.Tensor, np.ndarray, None] = None,
constant: Union[float, int, None] = None,
number_of_bits: int = 1,
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
if not isinstance(number_of_bits, int) or number_of_bits < 1:
raise ValueError("The number of bits must be a non-negative integer.")
Expand Down
6 changes: 3 additions & 3 deletions src/simulated_bifurcation/polynomial/spin_polynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"""

import warnings
from typing import Union
from typing import Optional, Union

import numpy as np
import torch
Expand Down Expand Up @@ -127,8 +127,8 @@ def __init__(
matrix: Union[torch.Tensor, np.ndarray],
vector: Union[torch.Tensor, np.ndarray, None] = None,
constant: Union[float, int, None] = None,
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> None:
super().__init__(matrix, vector, constant, [-1, 1], dtype, device)

Expand Down
16 changes: 8 additions & 8 deletions src/simulated_bifurcation/simulated_bifurcation.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ def optimize(
vector: Union[torch.Tensor, ndarray, None] = None,
constant: Union[int, float, None] = None,
input_type: str = "spin",
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
agents: int = 128,
max_steps: int = 10_000,
best_only: bool = True,
Expand Down Expand Up @@ -305,8 +305,8 @@ def minimize(
vector: Union[torch.Tensor, ndarray, None] = None,
constant: Union[int, float, None] = None,
input_type: str = "spin",
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
agents: int = 128,
max_steps: int = 10_000,
best_only: bool = True,
Expand Down Expand Up @@ -558,8 +558,8 @@ def maximize(
vector: Union[torch.Tensor, ndarray, None] = None,
constant: Union[int, float, None] = None,
input_type: str = "spin",
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
agents: int = 128,
max_steps: int = 10_000,
best_only: bool = True,
Expand Down Expand Up @@ -811,8 +811,8 @@ def build_model(
vector: Union[torch.Tensor, ndarray, None] = None,
constant: Union[int, float, None] = None,
input_type: str = "spin",
dtype: torch.dtype = torch.float32,
device: Union[str, torch.device] = "cpu",
dtype: Optional[torch.dtype] = None,
device: Optional[Union[str, torch.device]] = None,
) -> BaseMultivariateQuadraticPolynomial:
"""
Instantiate a multivariate degree 2 polynomial over a given domain.
Expand Down
4 changes: 2 additions & 2 deletions tests/models/test_ising.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

def test_ising():
torch.manual_seed(42)
J = torch.tensor([[0, -2, 3], [-2, 0, 1], [3, 1, 0]])
h = torch.tensor([1, -4, 2])
J = torch.tensor([[0.0, -2.0, 3.0], [-2.0, 0.0, 1.0], [3.0, 1.0, 0.0]])
h = torch.tensor([1.0, -4.0, 2.0])
model = Ising(J, h, device=torch.device("cpu"))
spin_vector, value = model.optimize(
agents=10,
Expand Down
Loading