"""This module contains the `EllCalc` class."""
from math import sqrt
from typing import Optional, Tuple
from .ell_calc_core import EllCalcCore
from .ell_config import CutStatus
[docs]
class EllCalc:
"""The `EllCalc` class is used for calculating ellipsoid parameters and has attributes
for storing constants and configuration options.
Examples:
>>> calc = EllCalc(3)
"""
use_parallel_cut: bool = True
_n_f: float
_helper: EllCalcCore
def __init__(self, ndim: int) -> None:
"""
The function initializes several variables based on the input value.
:param ndim: The parameter `ndim` represents an integer value.
:type ndim: int
Examples:
>>> calc = EllCalc(3)
>>> calc._n_f
3.0
"""
self._n_f = float(ndim)
self._helper = EllCalcCore(self._n_f)
[docs]
def calc_single_or_parallel_deep_cut(
self, beta, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""Calculate single or parallel deep cut
The `calc_single_or_parallel_deep_cut` function calculates either a
single or parallel deep cut based on the input parameters.
:param beta: The parameter `beta` can be of type `int`, `float`, or a list of two elements
:param tsq: The `tsq` parameter is a floating-point number that represents the square of the
tolerance for the ellipsoid algorithm. It is used in the calculations performed by the
`calc_single_or_parallel_deep_cut` method.
:type tsq: float
:return: The function `calc_single_or_parallel_deep_cut` returns a tuple containing the following elements:
Examples:
>>> calc = EllCalc(3)
"""
if isinstance(beta, (int, float)):
return self.calc_deep_cut(beta, tsq)
if len(beta) < 2 or not self.use_parallel_cut: # unlikely
return self.calc_deep_cut(beta[0], tsq)
return self.calc_parallel_deep_cut(beta[0], beta[1], tsq)
[docs]
def calc_single_or_parallel_central_cut(
self, beta, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""single or parallel central cut
The function `calc_single_or_parallel_central_cut` calculates either a
single or parallel central cut based on the input parameters.
:param beta: The parameter `beta` is of type `_type_` and represents some value. The specific
details of its purpose and usage are not provided in the code snippet
:param tsq: tsq is a float value representing the squared t-value
:type tsq: float
:return: a tuple containing the following elements:
1. CutStatus: The status of the cut calculation.
2. float: The calculated value.
3. float: The calculated value.
4. float: The calculated value.
Examples:
>>> calc = EllCalc(4)
>>> calc.calc_single_or_parallel_central_cut([0, 0.11], 0.01)
(<CutStatus.Success: 0>, (0.020000000000000004, 0.4, 1.0666666666666667))
>>> calc.calc_single_or_parallel_central_cut([0, -1], 0.01)
(<CutStatus.NoSoln: 1>, None)
"""
if isinstance(beta, (int, float)) or len(beta) < 2 or not self.use_parallel_cut:
return (CutStatus.Success, self._helper.calc_central_cut(sqrt(tsq)))
return self.calc_parallel_central_cut(beta[1], tsq)
#
# ⎛ ╱ ╱ ⎞
# -τ 0 β0 β1 +τ
# ⎝ ╱ ╱ ⎠
[docs]
def calc_parallel_deep_cut(
self, beta0: float, beta1: float, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""parallel deep cut
The function `calc_parallel_deep_cut` calculates the parallel deep cut based on the given parameters.
:param beta0: The parameter `beta0` represents a float value
:type beta0: float
:param beta1: The parameter `beta1` represents a float value
:type beta1: float
:param tsq: tsq is a float representing the value of tsq
:type tsq: float
:return: The function `calc_parallel` returns a tuple of type `Tuple[CutStatus, Optional[Tuple[float, float, float]]]`.
"""
if beta1 < beta0:
return (CutStatus.NoSoln, None) # no sol'n
if beta1 > 0.0 and tsq < beta1 * beta1:
return self.calc_deep_cut(beta0, tsq)
return (
CutStatus.Success,
self._helper.calc_parallel_deep_cut(beta0, beta1, tsq),
)
[docs]
def calc_parallel_central_cut(
self, beta1: float, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""Parallel central cut
The function `calc_parallel_central_cut` calculates the parallel central cut for given values of `beta1` and
`tsq`.
:param beta1: The parameter `beta1` represents a float value. It is used in the calculation of the
central cut
:type beta1: float
:param tsq: The parameter `tsq` represents the square of a value
:type tsq: float
:return: The function `calc_parallel_central_cut` returns a tuple of four values: `CutStatus`, `float`,
`float`, `float`.
Examples:
>>> calc = EllCalc(4)
>>> calc.calc_parallel_central_cut(0.11, 0.01)
(<CutStatus.Success: 0>, (0.020000000000000004, 0.4, 1.0666666666666667))
>>> calc.calc_parallel_central_cut(-1.0, 0.01)
(<CutStatus.NoSoln: 1>, None)
"""
if beta1 < 0.0:
return (CutStatus.NoSoln, None) # no sol'n
if tsq < beta1 * beta1 or not self.use_parallel_cut:
return (CutStatus.Success, self._helper.calc_central_cut(sqrt(tsq)))
return (CutStatus.Success, self._helper.calc_parallel_central_cut(beta1, tsq))
[docs]
def calc_deep_cut(
self, beta: float, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""Deep Cut
The function calculates the deep cut based on the given beta and tsq values.
:param beta: The parameter `beta` represents a float value
:type beta: float
:param tsq: tsq is the square of the value of tau
:type tsq: float
:return: The function `calc_deep_cut` returns a tuple of four values: `CutStatus`, `float`, `float`, `float`.
Examples:
>>> calc = EllCalc(3)
>>> calc.calc_deep_cut(1.0, 4.0)
(<CutStatus.Success: 0>, (1.25, 0.8333333333333334, 0.84375))
>>> calc.calc_deep_cut(0.0, 4.0)
(<CutStatus.Success: 0>, (0.5, 0.5, 1.125))
>>> calc.calc_deep_cut(1.5, 2.0)
(<CutStatus.NoSoln: 1>, None)
"""
assert beta >= 0.0
if tsq < beta * beta:
return (CutStatus.NoSoln, None) # no sol'n
return (CutStatus.Success, self._helper.calc_deep_cut(beta, sqrt(tsq)))
[docs]
def calc_single_or_parallel_deep_cut_q(
self, beta, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""single deep cut or parallel cut (discrete)
The function `calc_single_or_parallel_deep_cut_q` calculates the deep cut or parallel cut based on the input
parameters `beta` and `tsq`.
:param beta: The parameter `beta` can be either a single value (int or float) or a list of two
values
:param tsq: tsq is a float value representing the square of the threshold value
:type tsq: float
:return: The function `calc_single_or_parallel_deep_cut_q` returns a tuple containing four elements:
`CutStatus`, `float`, `float`, and `float`.
"""
if isinstance(beta, (int, float)):
return self.calc_deep_cut_q(beta, tsq)
if len(beta) < 2 or not self.use_parallel_cut: # unlikely
return self.calc_deep_cut_q(beta[0], tsq)
return self.calc_parallel_deep_cut_q(beta[0], beta[1], tsq)
#
# ⎛ ╱ ╱ ⎞
# -τ 0 β0 β1 +τ
# ⎝ ╱ ╱ ⎠
#
[docs]
def calc_parallel_deep_cut_q(
self, beta0: float, beta1: float, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""Parallel deep cut (discrete)
The function `calc_parallel_deep_cut_q` calculates the parallel deep cut for a given set of parameters.
:param beta0: The parameter `beta0` represents a float value
:type beta0: float
:param beta1: The parameter `beta1` represents a float value
:type beta1: float
:param tsq: tsq is a float value that represents the square of a variable
:type tsq: float
:return: The function `calc_parallel_deep_cut_q` returns a tuple of type `Tuple[CutStatus, float, float,
float]`.
"""
if beta1 < beta0:
return (CutStatus.NoSoln, None) # no sol'n
if beta1 > 0.0 and tsq < beta1 * beta1:
return self.calc_deep_cut_q(beta0, tsq)
if self._n_f * beta0 * beta1 < -tsq: # for discrete optimization
return (CutStatus.NoEffect, None) # no effect
# TODO: check beta0 + beta1 == 0
return self.calc_parallel_deep_cut(beta0, beta1, tsq)
[docs]
def calc_deep_cut_q(
self, beta: float, tsq: float
) -> Tuple[CutStatus, Optional[Tuple[float, float, float]]]:
"""Deep Cut (discrete)
The function `calc_deep_cut_q` calculates the deep cut for a given beta and tsq value.
:param beta: The parameter `beta` represents a float value
:type beta: float
:param tsq: tsq is the square of the threshold value. It is a float value that represents the
threshold squared
:type tsq: float
:return: The function `calc_deep_cut_q` returns a tuple of four values: `CutStatus`, `float`, `float`,
`float`.
Examples:
>>> from ell_algo.ell_calc import EllCalc
>>> calc = EllCalc(3)
>>> calc.calc_deep_cut_q(0.0, 4.0)
(<CutStatus.Success: 0>, (0.5, 0.5, 1.125))
>>> calc.calc_deep_cut_q(1.5, 2.0)
(<CutStatus.NoSoln: 1>, None)
>>> calc.calc_deep_cut_q(-1.5, 4.0)
(<CutStatus.NoEffect: 2>, None)
"""
tau = sqrt(tsq)
if tau < beta:
return (CutStatus.NoSoln, None) # no sol'n
if tau <= -self._n_f * beta:
return (CutStatus.NoEffect, None)
return (CutStatus.Success, self._helper.calc_deep_cut(beta, tau))
if __name__ == "__main__":
from pytest import approx
ell_calc = EllCalc(4)
status, result = ell_calc.calc_parallel_deep_cut_q(0.07, 0.03, 0.01)
assert status == CutStatus.NoSoln
status, result = ell_calc.calc_parallel_deep_cut_q(0.0, 0.05, 0.01)
assert status == CutStatus.Success
assert result is not None
rho, sigma, delta = result
assert sigma == approx(0.8)
assert rho == approx(0.02)
assert delta == approx(1.2)
status, result = ell_calc.calc_parallel_deep_cut_q(0.05, 0.11, 0.01)
assert status == CutStatus.Success
assert result is not None
rho, sigma, delta = result
assert sigma == approx(0.8)
assert rho == approx(0.06)
assert delta == approx(0.8)
status, result = ell_calc.calc_parallel_deep_cut_q(0.01, 0.04, 0.01)
assert status == CutStatus.Success
assert result is not None
rho, sigma, delta = result
assert sigma == approx(0.928)
assert rho == approx(0.0232)
assert delta == approx(1.232)
ell_calc = EllCalc(4)
assert ell_calc.use_parallel_cut is True