-
Notifications
You must be signed in to change notification settings - Fork 3
MathJS Incorporation
Given that the mathematical operations supported by Fable are very limited, a JS math library had to be incorporated in this project to perform the necessary matrix and complex number operations. The chosen library is MathJS (link). This page aims to analyse the new data types introduced, along with the binding process.
Following the Fable guide on how to incorporate JS libraries, the necessary binding functions were written in F#, for all the functions that are used by ADDIE. These are (from Simulator/MathJSHelpers.fs
):
type MathsJS =
abstract complex : float * float -> obj
abstract re : obj -> float
abstract im : obj -> float
abstract reshape : ResizeArray < obj > * ResizeArray <int > -> obj
abstract inv : obj -> obj
abstract multiply : obj * obj -> ResizeArray < obj >
abstract divide : obj * obj -> obj
abstract det : obj -> float
As already known, in JavaScript, all data/variables are treated as JavaScript objects
, without specific type prior to runtime. Therefore, the equivalent complex/matrix types had to be created in F#.
For complex numbers, two different types were created: one to represent them in their cartesian format, and one for polar representation.
type ComplexC = { Re: float; Im: float}
type ComplexP = { Mag: float; Phase: float}
Complex numbers are converted to JS objects and back using two helper functions which utilize the MathJS functions complex
(to JS obj), re
and im
(from JS obj).
toComplexJS : ComplexC -> obj
toComplexF : obj -> ComplexC
Another problem encountered was the necessity to use 2D arrays (Matrices) which Fable does not support. However, despite not supporting 2D Arrays, it is allowed to have an Array of Arrays, which is how matrices were represented in F#. To convert to mathJS, the following algorithm was used:
(ComplexC array array)
where:
- flatten : (ComplexC array array) -> (ComplexC array): Flattens the matrix by collecting the rows
- flattenedToMatrix : (obj array) -> (obj): Given that the matrix is guaranteed to be square by construction, the function first checks that the length of the array is a perfect square. Then, the square root of the array’s length is found (let it be sqrt), and the reshape MathJS function is called with inputs the flattenedMatrix and the Array [|sqrt,sqrt|] which specifies the sizes of the reshaped matrix.
As soon as the Matrix is converted to a JavaScript object, all the MathJS function can be used (det
, inv
, etc.)
All of the above functions are wrapped inside one general function which solves the MNA equations,
safeSolveMatrixVecComplex
, which has two inputs: (i) the flattened matrix and (ii) the vector b (vector of known currents/voltages),
and performs the following operations:
- Convert to a matrix, using flattenedToMatrix
- Find its determinant, using the MathJS det function
- If the determinant is 0, return None, else invert the matrix and continue
- If the dimension of the matrix does not match with the length of the vector b, return None, else perform the multiplication of the inverted matrix with vector b and return the solutions (as an Option).