"""Deduce the missing vars with a given set."""
from sympy.core.basic import Basic
from sympy.core.relational import Equality
from sympy.core.symbol import Symbol
from sympy.sets.sets import EmptySet
from sympy.solvers.solveset import linsolve
SYMBOLS = {
# references
"i_min": Symbol("i_min", real=True),
"j_min": Symbol("j_min", real=True),
"i_max": Symbol("i_max", real=True),
"j_max": Symbol("j_max", real=True),
# others
"x_min": Symbol("x_min", real=True),
"y_min": Symbol("y_min", real=True),
"x_max": Symbol("x_max", real=True),
"y_max": Symbol("y_max", real=True),
"i_center": Symbol("i_center", real=True),
"j_center": Symbol("j_center", real=True),
"x_center": Symbol("x_center", real=True),
"y_center": Symbol("y_center", real=True),
"i_size": Symbol("i_size", real=True),
"j_size": Symbol("j_size", real=True),
"x_size": Symbol("x_size", real=True),
"y_size": Symbol("y_size", real=True),
}
EQUATIONS = [
Equality(SYMBOLS["x_min"], SYMBOLS["j_min"]),
Equality(SYMBOLS["y_min"], SYMBOLS["i_max"]),
Equality(SYMBOLS["x_max"], SYMBOLS["j_max"]),
Equality(SYMBOLS["y_max"], SYMBOLS["i_min"]),
Equality(SYMBOLS["i_center"], SYMBOLS["i_min"]/2 + SYMBOLS["i_max"]/2),
Equality(SYMBOLS["j_center"], SYMBOLS["j_min"]/2 + SYMBOLS["j_max"]/2),
Equality(SYMBOLS["x_center"], SYMBOLS["x_min"]/2 + SYMBOLS["x_max"]/2),
Equality(SYMBOLS["y_center"], SYMBOLS["y_min"]/2 + SYMBOLS["y_max"]/2),
Equality(SYMBOLS["i_size"], SYMBOLS["i_max"] - SYMBOLS["i_min"]),
Equality(SYMBOLS["j_size"], SYMBOLS["j_max"] - SYMBOLS["j_min"]),
Equality(SYMBOLS["x_size"], SYMBOLS["x_max"] - SYMBOLS["x_min"]),
Equality(SYMBOLS["y_size"], SYMBOLS["y_max"] - SYMBOLS["y_min"]),
]
[docs]
def deduce_all_bounds(**bounds: dict[str, Basic]) -> dict[str, Basic]:
"""Solve the system for extracting the values of the i, j bounds.
Parameters
----------
**bounds : dict[str, sympy.code.basic.Basic]
The values of the given vars.
The considerated keys are the keys presents in the ``SYMBOLS`` dict.
Returns
-------
all_bounds : dict[str, sympy.code.basic.Basic]
The expressions associated to all the values of ``SYMBOLS`` keys.
Raises
------
ValueError
If input is not valid or if the linear system is inconsistent.
Examples
--------
>>> from sympy.core.symbol import Symbol
>>> from sympy.core.sympify import sympify
>>> from cutcutcodec.core.generation.video.fractal.geometry import deduce_all_bounds
>>> solutions = deduce_all_bounds(
... x_center=Symbol("t", real=True, positive=True)/2,
... y_center=sympify(1),
... x_size=sympify(2),
... y_size=1 + Symbol("t", real=True, positive=True)**2,
... )
>>> solutions["i_min"]
t**2/2 + 3/2
>>> solutions["i_max"]
1/2 - t**2/2
>>> solutions["j_min"]
t/2 - 1
>>> solutions["j_max"]
t/2 + 1
>>>
"""
assert all(n in SYMBOLS for n in bounds), f"{set(bounds) - set(SYMBOLS)} are not allowed"
assert all(isinstance(e, Basic) for e in bounds.values()), bounds
assert len(bounds) == 4, f"only 4 expressions are required, not {len(bounds)}"
new_eqs = [Equality(SYMBOLS[name], expr) for name, expr in bounds.items()]
ordered_symbs = list(SYMBOLS) # not list(SYMBOLS.values()) for frozen order
if (sols := linsolve(EQUATIONS + new_eqs, [SYMBOLS[s] for s in ordered_symbs])) is EmptySet:
raise ValueError(f"not enouth provided informations for solving bounds {new_eqs}")
return dict(zip(ordered_symbs, sols.args[0]))