eqsolver 0.2.4
Define model from system of equations, algebraically solve for variables, calculate boiling point, latent heat, other physics gas concepts
License: MIT
Requires Python: >=3.6


<h1>Equation System Solver </h1>

<h3>Purpose</h3>
1) define your own model of equations, and use the solver to solve them.
2) solve physics problems relating to gas: the energy to compress gas, final pressure/temperature after gas compression, boiling points and latent heat of water. 3) this solver can solve the ISLM economics model.

Finaly, this solver also solves a bug in sympy allowing larger systems of equations to be solved.

<h3>Solver Overview</h3>
To use the tool, one instantiates the solver class with as input a class of equations. One then can call this class with a method name equal to one of these equations, or several (separated by underscores), using the names of known variables as arguments. The output is a dictionary showing the values of unknown variables.

<h3>Examples</h3>

[Here is an example for making a class containing equations - here for the equations defining the ISLM economics model.](https://github.com/brighamturner12/eqsolver/blob/main/gas/eqsolver/eqsolver/ISLM.py)

[Here is the code that uses this class to find solutions to problems involivng the ISLM.](https://github.com/brighamturner12/eqsolver/blob/main/economicsExamples.py)

[Here are what the results would be.](https://github.com/brighamturner12/eqsolver/blob/main/resultsISLM.txt)

[Here is an example containing a class for the physics gas equations.](https://github.com/brighamturner12/eqsolver/blob/main/gas/eqsolver/eqsolver/gasEquations.py)

[And here these equations are used to solve physics problems.](https://github.com/brighamturner12/eqsolver/blob/main/gasExamples.py)

[Here are what the results would be for the physics model.](https://github.com/brighamturner12/eqsolver/blob/main/resultsPhysicsGas.txt)

One must note that in these examples, the entire file containing the model is imported as a class.

<h3>Equation Class</h3>
Each variable in this class is an equation - as described earlier, to use the equation, the solver class is called with method name equal to the name of the variable storing the equations. The solver won't use all of the equations in the equation class, only the ones referenced in a function call (again, each equation name separated by an underscore).
Warning: don't use "I" as a variable name because this will be counted as a complex number.

<h3>Equation Class Optional Inner Classes</h3>

If the equation class has inner classes, then instead of using the variable name of an equation as a method name, one can instead use the name of the inner class, and the solver will know to use every single equation in said inner class. Unless accessed through the name of the inner class, the solver won't be able to access equations defined in inner classes so using them as a method name won't work (this is deliberate, to potentially allow equation names to be similar). This is particularly useful, because to define a constant, one just uses the constant name as the variable name and sets it equal to an integer or float (so not a string as would be the case for an equation), so constant names that are equal which are defined in inner classes won't conflict with each other.

To allow the user to expose variables inside of an inner class to method calling, just add the key word "GROUP_" to the name of the inner class. This still allows all equations to be called simultaneously by using the inner class name (including the prefix "GROUP_").

Inner classes can also import equations from other inner classes. To do this, rather than defining a variable inside of the inner class to be equal to an equation, define it to be equal to the name of a different already defined equation or inner class (if inner class, it imports all equations contained by that class). Just be sure to include the prefix "get:" in the string before the following equation / inner class name. This works successively: if inner class B has "x = 'get:A'", and inner class C has "x = 'get:B'" and inner class D has "x = 'get:C'" then inncer class D will ultimately be referencing equations all the way back to inner class A.

<h3>Function Call Arguments</h3>

The the arguments to each method must be all of the known variables in the equations: there must always be at least as many equations as there are unknown variables. Thus, if you don't give the method enough known variables so that the unknown variables outnumber the equations it will throw an error. The name of each argument must be the same as the name of the variable. You may also provide a class with variable names in it, and it will decipher this class. Alternatively, you can simultaneously provide a class and keyword arguments.

<h3>Getting Algebraic Solution</h3>
Normally, the functions will return a dictionary where each key is an unknown variable and the value (float) of that key is the variable. All calculations are computed algebraically, not numerically, but unless you provide the keyword argument "algebraic" separated by underscores from the equation names in the name of the method, it will only give you the numbers for each solution, rather than the equation used to get these numbers.

If instead you use the "algebraic" keyword, no numbers will be provided, rather it will provide a dictionary where each key is a variable name and the value is the equation that would give the variable name's value given known variables. This dictionary is actually the first value in a list that is returned, the second value in the list is simply a repetition of all the known variables.

<h3>Multiple Solutions</h3>
If a system of equations has 2 solutions, you made also provide "solutionIndex" as an argument to the function and set this equal to either 0 - to get the first solution - 1 - to get the second solution, and so on. If there are multiple solutions but solutionIndex was never provided as a keyword, it will throw an error.

<h3>Updating Class of Inputs with Solutions</h3>
If you provide the solver with a class containing known variables and want the solver to variables to this class equal to the solutions, add "setVal = True" to the function arguments. If class already has these variables, it will throw an error unless you add "redefine = True" to the function arguments as well.

<h3>Instances Where It Gets Stuck Loading</h3>
At its core, the equation solver uses sympy. This solver should be better than sympy because sympy has a difficult with long sequences of equations, where the first can be easily solved, and once it is, each next equation can easily be solved. In cases like these, sympy usually gets stuck endlessly loading, whereas this solver will be able to solve them. In my experience, this equation solver or sympy have never been wrong, however, sometimes they can't find solutions (meaning they get stuck infinitely loading) to systems that do in fact have solutions. Particularly in cases where u substitution is required or dividing one equation by another equation is required to solve algebraically.

<h3>Numerical Solutions</h3>
One may get a numerical solution by including the keyword "numerical", separated by underscores, in a method call function name. Unfortunately, if there are multiple solutions, this may return the wrong one.

<h3>Using Derivatives, Integrals, and Solve Function in Equations</h3>
This solver can do a lot of interesting things with its equations - as seen in my examples with physics gas equations, an equation can use "integral", "derivative", or "solve" as functions - in the case of solve, it can solve an inner equation and put the output of that in the equation. See sympy for more details. It is also worth noting that sympy is coded to not use equations, but rather expressions that equal zero, so to use the solve function, the input is an expression that should resolve to zero, rather than an equation.
<h3>When You Should Use This Tool</h3>
Ultimately, if your goal is to solve just one equation, then this tool may be a little overcomplicated and it would be better to just directly use sympy. Rather, the scope of this tool is to solve long and complicated equations in a simple way: All one does is define the equations in a class, give them to the solver, and then tell the solver the known variables and it provides a solution. This allows the user to focus on perfecting their model and making sure the equations are correct, rather than focusing on checking if algebra was performed correctly. 

This solver also solves one of the bugs of sympy - as described before - sympy has a difficult time with systems with too many equations. Also, as an edge use, the solver class will store the algebraic solution to a problem once it is found. Thus, any algebra computed internally is never repeated, thus speeding up loops that may repeatedly ask for the same solution to an equation but with different inputs.

<h3>Project Inspiration</h3>
The original purpose of this tool was to simplify solving long systems of physics equations that were cumbersome to solve by hand and annoying to program into sympy. 
<h3>Solving Physics Gas Problems, and ISLM model</h3>
This solver already has stored in it a class containing the essential equations relating to gas compression and water evaporation. It can be used to solve for the boiling points of water and latent heat of water given pressure and temperature - computations that would be very difficult to perform by hand, and for which I haven't found python libraries that are coded to do.
In addition, to the solver also has stored in it the equations for the ISLM model, though these equations often vary.