Source code for cake.expressions.linear

## Linear expressions
from __future__ import annotations
from typing import Any, Tuple, TypeVar, Generic

from cake import Add, Expression, Variable, utils
import cake

from .core import PolynomialExpression

M = TypeVar('M')
C = TypeVar('C')


[docs]class LinearExpression(PolynomialExpression, Generic[M, C]): ''' Represents a basic linear expression, this expression can also be expressed as ``y = mx + c``. Parameters ---------- m: Any[Like[cake.BasicNode]] Gradient of expression c: Any[Like[cake.BasicNode]] Intercept of expression ''' def __init__(self, m: M, c: C) -> None: self.m = m self.c = c
[docs] def as_expression(self) -> Expression: ''' Returns a :class:`Expression` in the form of a :class:`LinearExpression` ''' return Expression(Add(Variable('x', coefficient=self.m), self.c))
[docs] def solve(self, x: Any, **kwds) -> Any: ''' Returns a value for when ``x`` is given, kwargs for other values may be passed as well but ``x`` is always overwritten. .. code-block:: py >>> y = LinearExpression(Real(0.5), 10) >>> y 0.5*x + 10 >>> y.solve(x=5) 12.5 ''' kwds.update(x=x) return self.as_expression().solve(**kwds)
[docs] def r_solve(self, y: Any, **kwds) -> Any: ''' Returns a value for when ``y`` is given, kwargs for other values may be passed as well but ``y`` is always overwritten .. code-block:: py >>> y = LinearExpression(2, 10) >>> y 2*x + 10 >>> y.r_solve(y=10) 0 >>> y.r_solve(y=3) -3.5 ''' kwds.update(y=y) r = getattr(y, 'copy', lambda: y)() r -= utils.solve_if_possible(self.c, **kwds) r /= utils.solve_if_possible(self.m, **kwds) return r
[docs] def differentiate(self) -> M: return getattr(self.m, 'copy', lambda: self.m)()
[docs] def integrate(self) -> 'cake.expressions.QuadraticExpression': return cake.expressions.QuadraticExpression(a=self.m / 2, b=self.c, c=0)
[docs] def roots(self) -> Tuple[Any, ...]: return (self.r_solve(y=0),)
''' Properties and setters ''' @property def gradient(self) -> M: ''' Returns the gradient of the expression ''' return self.m @property def intercept(self) -> C: ''' Returns the intercept of the expression ''' return self.m ''' Classmethods '''
[docs] @classmethod def from_points(cls, point1: 'cake.geometry.Point2D', point2: 'cake.geometry.Point2D', /) -> LinearExpression: ''' Returns a linear expression from 2 given 2D points Parameters ---------- point1, point2: :class:`geometry.Point2D` A 2D point to use ''' gradient = (point1.y - point2.y) / (point1.x - point2.x) intercept = point2.y - (gradient * point1.x) return LinearExpression(gradient, intercept)
[docs] @classmethod def generic(cls) -> LinearExpression: ''' Returns a generic linear expression ''' return LinearExpression(Variable('m'), Variable('c'))
[docs] @classmethod def through_origin(cls, m: Any) -> LinearExpression: ''' Returns a linear expression which passes through the origin Parameters ---------- m: Any[Like[cake.BasicNode]] Gradient of the expression ''' return LinearExpression(m, 0)
[docs] @classmethod def from_expression(cls, expr: Expression) -> LinearExpression: ''' Creates a :class:`LinearExpression` from a :class:`Expression`. Parameters ---------- expr: :class:`Expression` Expression to use, must be in the form ``Add(variable, Any, ...)`` Any values after ``Any`` will expressed as ``Add(Any, ...)`` Raises ------ :py:obj:`TypeError`: Invalid expression was given, either operation was not Add or it didn't match the valid pattern. ''' if not isinstance(expr.exp, Add): raise TypeError('Invalid expression passed') try: gradient, *intercept = expr.exp.nodes gradient = gradient.coefficient if len(intercept) > 1: intercept = Expression(Add(*intercept)) else: intercept = intercept[0] except (AttributeError, ValueError): raise TypeError('Invalid expression passed') return LinearExpression(gradient, intercept)
''' Internal ''' def __str__(self) -> str: return f'{self.m}*x + {self.c}' def __repr__(self) -> str: return f'LinearExpression(m={repr(self.m)}, c={repr(self.m)})'