it.grypho.scala.leonardo.equation

Members list

Type members

Classlikes

enum CompareOp

The ordering relations, and inequality.

The ordering relations, and inequality.

== is deliberately absent: that is _EqualityCheck, which already exists and which != is defined as the negation of.

Attributes

Companion
object
Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object CompareOp

Attributes

Companion
enum
Supertypes
trait Sum
trait Mirror
class Object
trait Matchable
class Any
Self type
CompareOp.type
case class _Comparison(lhs: _Expression, op: CompareOp, rhs: _Expression) extends _Expression

A comparison between two expressions: lhs < rhs and friends.

A comparison between two expressions: lhs < rhs and friends.

Reduces to a core._Bool when both sides are concrete and comparable, so comparisons feed the logic tier directly — x < 2 and y > 3 needs no new machinery, because the connectives take untyped operands.

Deliberately NOT _ElementWise, unlike _Equation and _EqualityCheck. That marker lets algorithms distribute over both sides, which is why 2 * (x = 1) reduces to 2x = 2 today. For an inequality that rewrite is invalid: multiplying x < 1 through by -1 gives -x < -1, which is false exactly when the original is true, because the direction has to flip. Distributing correctly would require knowing the sign of the multiplier, which in general is not available — so the marker is omitted, per the codebase rule that it may be present only when distribution is valid for every algorithm. It is one word long and both neighbouring node types carry it, so this is written down rather than left to be re-derived.

Not solvable. _Solve.eval requires an _Equation, so solve(x < 2, x) stays symbolic on its own; inequality solving would need interval-valued solutions, which the solver has no carrier for.

Value parameters

lhs

left-hand side

op

the relation

rhs

right-hand side

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait _Expression
class Object
trait Matchable
class Any
Show all
case class _EqualityCheck(lhs: _Expression, rhs: _Expression) extends _ElementWise

An explicit equality test: lhs == rhs.

An explicit equality test: lhs == rhs.

Always reduces to _Bool when both sides are concrete, using the same tolerance as _Equation (|a - b| <= 0.5 * 10^(-env.precision)).

Unlike _Equation it is:

  • NOT solvable: _Solve.eval requires an _Equation, so solve(a == b, x) stays symbolic. Use = to build a solvable relation.
  • Still _ElementWise: simplify/expand/derive distribute over both sides, mirroring the _Equation treatment.

toString is "lhs == rhs", which round-trips through the parser.

Value parameters

lhs

left-hand side expression

rhs

right-hand side expression

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait _ElementWise
trait _Expression
class Object
trait Matchable
class Any
Show all
case class _Equation(lhs: _Expression, rhs: _Expression) extends _ElementWise

A relation between two expressions: lhs = rhs.

A relation between two expressions: lhs = rhs.

eval reduces both sides and compares them when both are concrete. Numeric equality is tolerance-based, tied to env.precision -- exact Double comparison would make sin(pi) = 0 false on floating-point noise; instead two numbers are equal when |a - b| <= 0.5 * 10^(-p). Concrete matrices compare element-wise under the same tolerance. Anything else stays symbolic with the sides reduced.

Marked _ElementWise: an equation is a container of its two sides, so derive/simplify/expand/integrate apply the algorithm to both sides (e.g. d/dx (lhs = rhs) is d(lhs)/dx = d(rhs)/dx).

toString is "lhs = rhs" (no outer parentheses): equations exist only at the top level of the grammar, and the round-trip invariant parse(toString(e)) == e holds.

Value parameters

lhs

left-hand side expression

rhs

right-hand side expression

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait _ElementWise
trait _Expression
class Object
trait Matchable
class Any
Show all
case class _Solve(eq: _Expression, v: _Variable) extends _Expression

AST node for the solve(eq, v) functional (parser: solve(expr = expr, v)).

AST node for the solve(eq, v) functional (parser: solve(expr = expr, v)).

eq is typed as _Expression, not [[_Equation]], so a named equation binding (h := x = 5) can be passed directly: after substitution expands h to _Equation(x, 5), eval pattern-matches on the concrete _Equation and delegates to solve. If eq is not an _Equation at eval time (e.g. a plain expression or an _EqualityCheck), the node stays symbolic -- only = builds a solvable relation, not ==.

A solution set is never a concrete _Value, so eval always answers Left:

  • no solution found / known -> Left(this) (stays symbolic)
  • exactly one solution -> Left(v = expr) (an _Equation)
  • several solutions -> Left([[v=e1, v=e2]]) (a row-vector _Matrix)

children exposes eq as a single child (binder v is excluded), so substitute/dependsOn/rebuild walk into eq -- if eq is a _Variable naming a definition, substitute replaces it with its body before eval runs.

Value parameters

eq

the equation expression (must resolve to an _Equation at eval time)

v

the solve variable (binder -- excluded from children)

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait _Expression
class Object
trait Matchable
class Any
Show all
case class _SolveSystem(equations: _Expression, variables: List[_Variable]) extends _Expression

AST node for solveSystem(equations, v1, v2, ...) in the grammar.

AST node for solveSystem(equations, v1, v2, ...) in the grammar.

equations is expected to be a _Matrix whose elements are _Equation nodes -- e.g. [[2*x + y = 5, x + 3*y = 10]]. After the REPL substitutes any named matrix binding, eval extracts the equations and delegates to solveSystem.

The solve variables are binders (excluded from children / substitute traversal), exactly as in _Derivative and _Integral -- solving for x does not substitute x itself.

eval result shape (mirrors _Solve):

  • no solution (singular, nonlinear, ...) -> Left(this) (stays symbolic)
  • single variable -> Left(v = expr)
  • multiple variables -> Left([[v1 = e1, v2 = e2, ...]])

toString is "solveSystem(equations, v1, v2, ...)" -- round-trips through the parser.

Value parameters

equations

a _Matrix expression whose elements must be _Equation nodes

variables

the solve variables (binders -- excluded from children)

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait _Expression
class Object
trait Matchable
class Any
Show all

Value members

Concrete methods

def solve(eq: _Equation, v: _Variable, env: Environment): List[_Equation]

Returns the solutions of eq in v as a list of v = expr equations.

Returns the solutions of eq in v as a list of v = expr equations.

An empty list means no solution was found (or the equation does not constrain v). The caller (_Solve.eval) interprets the list: empty -> stays symbolic, one -> single equation, many -> a row-vector _Matrix of equations.

Value parameters

env

the evaluation environment (variable bindings + precision)

eq

the equation to solve

v

the variable to solve for

Attributes

Returns

the solution list, possibly empty

def solveSystem(equations: List[_Equation], variables: List[_Variable], env: Environment): Option[List[_Equation]]

Returns the unique solution of a square linear system, or None.

Returns the unique solution of a square linear system, or None.

Value parameters

env

the evaluation environment (variable bindings + precision)

equations

the list of equations (must be n equations for n variables)

variables

the solve variables (must match the number of equations)

Attributes

Returns

Some(list of v_i = expr_i) on success; None when non-square, nonlinear, singular, or near-singular