FriCAS has various equation solvers, these are usually provided by a 'solve' function.

As far as I can see, each 'solve' function is written specifically for a given type of equation without much common infrastructure or standardisation. I don't think these solvers use rules discussed here.

I would like a solver for say quaternions. It would be good if it could be done in as general way as possible, although given that quaternions are the only noncommutative, associative division algebra there is probably not much scope for generalisation in this case. However, as a general principle it might provide more generality if solvers could be written in terms of axioms and identities.

Waldek has given some information which may help to get started from this thread:

 ```> ** [feature-requests:#10] Add Ability to Write Equation Solvers for a given Domain.** > > FriCAS has quite good support for say, systems of polynomial equations in field or OrderedRing, see numsolve.spad.pamphlet for more details. > > Would it be possible to generalise this so that someone writing code for an SPAD domain can add their own equation solvers for their domain. With variables that represent elements of that domain. > > So, for example, we might want to write equations where the variables are quaternions. So we need to write a solver which can handle a non-commuting algebra. > > I suppose someone could write some code in SPAD to do this now? But it really needs a proper framework to do it efficiently? > You can write solvers just now. Existing solvers are packages which export 'solve' function. Of course, you need an algorithm for given domain. Given system of linear equations over quaternions one can convert it to a bigger linear system over base ring and call existing solver. Then convert back to quaternions. In principle similar approach may work for polynomial equations, but even simple polynomial equations over quaternions will produce complicated equations over base ring. Directly working with quaternions may produce better solver. Anyway, the main problems is to find a method of solving for given domain. -- Waldek Hebisch ```

and:

 ```> > You can write solvers just now. Existing solvers are packages > > which export 'solve' function. Of course, you need an algorithm > > for given domain. Given system of linear equations over quaternions > > one can convert it to a bigger linear system over base ring > > and call existing solver. Then convert back to quaternions. > > In principle similar approach may work for polynomial equations, > > but even simple polynomial equations over quaternions will > > produce complicated equations over base ring. Directly working > > with quaternions may produce better solver. > > > > Anyway, the main problems is to find a method of solving for > > given domain. > > OK thanks, I did not know this, it looks useful I'll have to experiment > with it. Do you know of any tutorials? Basically, for the interpreter 'solve' is just like another function. If you add a new one normal overloading resolution will choose appropriate one. You need some way of writing equations. If you want to have '=' sign, then you can use Equation domain. Eqation can do only a little: '=' sign on command line will create equation, you can extract left hand side and right hand side. For both sides you need some representation of terms. For polynomial Polynomial is good choice, but for noncommutative domains you need someting different. We have 'XPolynomial' domain which may work OK. I write 'may work' because 'XPolynomial' assumes that variables commute with coefficients which strictly speaking is not true if you work with equations over noncommutative ring. This is OK if you take coefficients from the base ring. And any system of algebraic equations can be written is such a way that you never multiply variable by noncommuting coefficient. The problem is that if you are not careful writing your equation, then 'XPolynomial' will change relative order of coefficients and variables which may lead to inequivalent system. So, it may be wise to create a generalization of 'XPolynomial' which preserves relative order of variables and coefficients. Anyway, if you have a finite dimensional algebra over a commutative ring (like Quaternion), then you can replace each variable from the algebra by a linear combination of basis elements with coefficients form base ring. So, instead of 'x' in quaternion you will have 'x1 + i*x2 + j*x3 + k*x4'. Practically, this can be done by using say 'Quaternion(Polyniomial(Fraction(Integer)))' and defining appropriate mapping from noncommutative polynomials (which represent your equations) to the quaternions with polynomial coefficients. For polynomials there is 'PolynomialCategoryLifting' package which helps building mappings between polynomials and a commitative ring. Something similar would be needed form noncommutative polynomials. Note that the approch above is rather naive and potentially quite inefficient. In general case, one can use Expression to represent equations. The real difficulty is to have solving algorithm. Basically any open problem in mathematics can be formulated as question about solutions of aproproate equations, so it unlikely that any general method exists. ```

 ```(1) -> )di op solve There are 33 exposed functions called solve :  (List(Fraction(Polynomial(Integer))),D3) -> List(List(Equation( Polynomial(D3)))) from FloatingRealPackage(D3) if D3 has Join(OrderedRing, Field)  (List(Equation(Fraction(Polynomial(Integer)))),D3) -> List(List( Equation(Polynomial(D3)))) from FloatingRealPackage(D3) if D3 has Join(OrderedRing, Field)  (Fraction(Polynomial(Integer)),D3) -> List(Equation(Polynomial( D3))) from FloatingRealPackage(D3) if D3 has Join(OrderedRing, Field)  (Equation(Fraction(Polynomial(Integer))),D3) -> List(Equation( Polynomial(D3))) from FloatingRealPackage(D3) if D3 has Join(OrderedRing, Field)  (D2,D3,Symbol) -> Union(Record(particular: D3,basis: List(D3)), "failed") from ElementaryFunctionLODESolver(D5,D3,D2) if D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero) and D3 has Join( AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D2 has LODOCAT(D3)  (D2,D1,Symbol,D1,List(D1)) -> Union(D1,"failed") from ElementaryFunctionLODESolver(D5,D1,D2) if D1 has Join(AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero) and D2 has LODOCAT(D1)  (D2,D3) -> Record(particular: Union(D3,"failed"),basis: List(D3) ) from LinearSystemMatrixPackage(D4,D5,D3,D2) if D4 has FIELD and D5 has Join(FiniteLinearAggregate(D4), shallowlyMutable) and D3 has Join(FiniteLinearAggregate(D4) ,shallowlyMutable) and D2 has MATCAT(D4,D5,D3)  (D2,List(D6)) -> List(Record(particular: Union(D6,"failed"), basis: List(D6))) from LinearSystemMatrixPackage(D4,D5,D6,D2) if D6 has Join(FiniteLinearAggregate(D4),shallowlyMutable) and D4 has FIELD and D5 has Join(FiniteLinearAggregate(D4), shallowlyMutable) and D2 has MATCAT(D4,D5,D6)  (Matrix(D4),Vector(D4)) -> Record(particular: Union(Vector(D4), "failed"),basis: List(Vector(D4))) from LinearSystemMatrixPackage1(D4) if D4 has FIELD  (List(List(D4)),Vector(D4)) -> Record(particular: Union(Vector( D4),"failed"),basis: List(Vector(D4))) from LinearSystemMatrixPackage1(D4) if D4 has FIELD  (Matrix(D4),List(Vector(D4))) -> List(Record(particular: Union( Vector(D4),"failed"),basis: List(Vector(D4)))) from LinearSystemMatrixPackage1(D4) if D4 has FIELD  (List(List(D4)),List(Vector(D4))) -> List(Record(particular: Union(Vector(D4),"failed"),basis: List(Vector(D4)))) from LinearSystemMatrixPackage1(D4) if D4 has FIELD  (Matrix(D6),Vector(D6),Symbol) -> Union(Record(particular: Vector(D6),basis: List(Vector(D6))),"failed") from ElementaryFunctionODESolver(D5,D6) if D6 has Join(AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (Matrix(D5),Symbol) -> Union(List(Vector(D5)),"failed") from ElementaryFunctionODESolver(D4,D5) if D5 has Join(AlgebraicallyClosedFunctionSpace(D4), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D4 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (List(Equation(D6)),List(BasicOperator),Symbol) -> Union( Record(particular: Vector(D6),basis: List(Vector(D6))),"failed") from ElementaryFunctionODESolver(D5,D6) if D6 has Join(AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (List(D6),List(BasicOperator),Symbol) -> Union(Record( particular: Vector(D6),basis: List(Vector(D6))),"failed") from ElementaryFunctionODESolver(D5,D6) if D6 has Join(AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (Equation(D6),BasicOperator,Symbol) -> Union(Record(particular : D6,basis: List(D6)),D6,"failed") from ElementaryFunctionODESolver(D5,D6) if D6 has Join(AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (D2,BasicOperator,Symbol) -> Union(Record(particular: D2,basis : List(D2)),D2,"failed") from ElementaryFunctionODESolver(D5,D2) if D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero) and D2 has Join( AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory)  (Equation(D1),BasicOperator,Equation(D1),List(D1)) -> Union(D1, "failed") from ElementaryFunctionODESolver(D5,D1) if D1 has Join(AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (D1,BasicOperator,Equation(D1),List(D1)) -> Union(D1,"failed") from ElementaryFunctionODESolver(D5,D1) if D1 has Join(AlgebraicallyClosedFunctionSpace(D5), TranscendentalFunctionCategory,PrimitiveFunctionCategory) and D5 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  Expression(D3) -> List(Equation(Expression(D3))) from TransSolvePackage(D3) if D3 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  Equation(Expression(D3)) -> List(Equation(Expression(D3))) from TransSolvePackage(D3) if D3 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (Equation(Expression(D4)),Symbol) -> List(Equation(Expression( D4))) from TransSolvePackage(D4) if D4 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (Expression(D4),Symbol) -> List(Equation(Expression(D4))) from TransSolvePackage(D4) if D4 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (List(Equation(Expression(D4))),List(Symbol)) -> List(List( Equation(Expression(D4)))) from TransSolvePackage(D4) if D4 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero)  (List(Fraction(Polynomial(D4))),List(Symbol)) -> List(List( Equation(Fraction(Polynomial(D4))))) from SystemSolvePackage(D4) if D4 has INTDOM  (List(Equation(Fraction(Polynomial(D4)))),List(Symbol)) -> List (List(Equation(Fraction(Polynomial(D4))))) from SystemSolvePackage(D4) if D4 has INTDOM  List(Fraction(Polynomial(D3))) -> List(List(Equation(Fraction( Polynomial(D3))))) from SystemSolvePackage(D3) if D3 has INTDOM  List(Equation(Fraction(Polynomial(D3)))) -> List(List(Equation( Fraction(Polynomial(D3))))) from SystemSolvePackage(D3) if D3 has INTDOM  (Fraction(Polynomial(D4)),Symbol) -> List(Equation(Fraction( Polynomial(D4)))) from SystemSolvePackage(D4) if D4 has INTDOM  (Equation(Fraction(Polynomial(D4))),Symbol) -> List(Equation( Fraction(Polynomial(D4)))) from SystemSolvePackage(D4) if D4 has INTDOM  Fraction(Polynomial(D3)) -> List(Equation(Fraction(Polynomial( D3)))) from SystemSolvePackage(D3) if D3 has INTDOM  Equation(Fraction(Polynomial(D3))) -> List(Equation(Fraction( Polynomial(D3)))) from SystemSolvePackage(D3) if D3 has INTDOM There are 7 unexposed functions called solve :  (List(Polynomial(D4)),List(Symbol)) -> List(List(Equation( Fraction(Polynomial(D4))))) from NonLinearSolvePackage(D4) if D4 has INTDOM  List(Polynomial(D3)) -> List(List(Equation(Fraction(Polynomial( D3))))) from NonLinearSolvePackage(D3) if D3 has INTDOM  (D1,D1,BasicOperator,Symbol) -> Union(D1,"failed") from NonLinearFirstOrderODESolver(D4,D1) if D4 has Join(Comparable,EuclideanDomain,RetractableTo( Integer),LinearlyExplicitRingOver(Integer), CharacteristicZero) and D1 has Join( AlgebraicallyClosedFunctionSpace(D4), TranscendentalFunctionCategory,PrimitiveFunctionCategory)  (Matrix(D5),Vector(D5),((D6,D5) -> Union(Record(particular: D5, basis: List(D5)),"failed"))) -> Union(Record(particular: Vector( D5),basis: Matrix(D5)),"failed") from SystemODESolver(D5,D6) if D5 has FIELD and D6 has LODOCAT(D5)  (Polynomial(Fraction(Integer)),Float) -> List(Float) from RealSolvePackage  (Polynomial(Integer),Float) -> List(Float) from RealSolvePackage  D2 -> List(D3) from PolynomialSolveByFormulas(D2,D3) if D3 has Field with ?^? : (%,Fraction(Integer)) -> % and D2 has UPOLYC( D3) ```