Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

140 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Formula

handle mathematical expressions at haxe-runtime.

This tool has its roots in old C symbolic math stuff.

It can form derivatives, simplify terms and
handle parameters to connect Formulas together.

Installation

haxelib install formula

or use the latest developement version from github:

haxelib git formula https://github.com/maitag/formula.git

Testing

To perform benchmarks or unit-tests call the text.hxhxp script.

install hxp via:

haxelib install hxp
haxelib run hxp --install-hxp-alias

then simple call hpx help into projectfolder to see options.

If you use hxp bench to compare performance versus hscripts math-expression parsing
you need to install hscript from haxelib first!

Documentation

Formula class is a haxe-abstract to support operator-overloading for the underlaying TermNode class,
therefore prefer this one for instantiation:

var f:Formula;

Set up a math expression from String with new or by using the "="-operator:

f = new Formula("1+2*3");
f = "1+2*3";
f = 7; // supports Float too

Math expressions:

two side operators:
+, -, *, /, ^, %

mathmatical functions:
log(a, b), ln(a), abs(a), max(a,b), min(a,b)
sin(a), cos(a), tan(a), cot(a), asin(a), acos(a), atan(a), atan2(a,b)

constants: e() and pi()

Naming formulas:

To be known to 'others', you can give a Formula object a name:

f.name = "f";

or alternatively name it at first position in the definition (separated by a colon):

f = "f: 1+2*3";

Parameter binding:

Bind Formulas together by using custom literals (like variable names):

f = "sin(b)"; // other formula can be bound to 'b' later

Now define another Formula object x to connect to variable b with the 'bind()' method:

var x:Formula = 0;
f.bind( x, "b" );

Formula x does not necessarily has to have the same name as the variable inside f,
but if Formula x has the same name, it's easier:

x.name = "b";
f.bind(x);

To bind more than one variable at once you can proceed like this: f.bindMap( ["b" => x, "c" => c] );
Alternatively use arrays of formulas and to what parameters it should bind: f.bindArray( [x, c], ["b", "c"] ); or if all formulas have the same names as expected: f.bindArray( [x, c] );

Unbinding of parameters:

// unbind a connected formula
f.unbind(x);
// unbind the formula thats connected to a variable name
f.unbindParam("b");
// unbind more than one formula with array usage:
f.unbindArray( [x, c] );
f.unbindParamArray( ["b", "c"] );
// unbind all with:
f.unbindAll();
trace(f); // "sin(b)"

Output formulas:

In a String context Formula will return the full dissolved mathmatical expression (includes all bindings):

trace(f); // sin(0)

To dissolve only to a certain level of subterms, use the toString method:

trace( f.toString(0) ); // sin(b)
trace( f.toString(1) ); // sin(0)

Or print out all binding levels in order with the debug() method:

f.name = "f";
f.debug(); // f = sin(b) -> sin(0)

Calculating results:

The result of a formula expression can be calculated with the result getter method.
Use this if no unbound variables are left:

trace( f.result ); // 0

Formula API

new(formula:String)
creates an Formula object based on the string formula
name:String (get and set)
Formula name
result:Float (get only)
calculation result of the math expression
bind(formula:Formula, ?paramName:String):Formula
link a variable inside of this Formula to another Formula
bindArray(formulas:Array<Formula>, ?paramNames:Array<String>):Formula
link variables inside of this Formula to another Formulas
bindMap(formulaMap:Map<String, Formula>):Formula
link variables inside of this Formula to another Formulas
where the mapkey is equal to the name of the variable
unbind(formula:Formula):Formula
delete all connections of the linked Formula
unbindArray(formulas:Array<Formula>):Formula
delete all connections of the linked Formulas
unbindParam(paramName:String):Formula
delete all connections to linked formulas for a given variable name
unbindParamArray(paramNames:Array<String>):Formula
delete all connections to linked formulas for the given variable names
unbindAll():Formula
deletes the connection between all variables of the Formula and all linked Formulas
resolveAll(?depth:Int):Formula
resolves all bindings into formula or optional to a specified the depth level,
removes parameters and replaces it with copies of the linked formulas
hasBinding(formula:Formula):Bool
returns true if this contains a binding to formula
hasParam(paramName:String):Bool
returns true if formula contains a param with specified name
params():Array<String>
returns an array of parameter-names
depth():Int
returns the max depth of parameter bindings
set(a:Formula):Formula
copy all from another Formula to this (keeps it's own name if defined)
copy(?depth:Int):Formula
returns a full copy of this Formula or optional to a specified depth level
toString(?depth:Null<Int>, ?plOut:String):String
returns the mathmatical expression in form of a string
parameters:
depth: specifies how deep variables should be replaced by their corresponding Formulas
plOut: to generate output syntax for different programming languages ( only 'glsl' yet )
debug()
debugging output to see all bindings
derivate(paramName:String):Formula
returns new formula that is derivate to the variable paramName
simplify():Formula
tries various ways to make the term appear simpler and also normalizes it
(use with caution because this process is not trivial and could be changed in later versions)
returns the result as new formula
expand():Formula
mathematically expands into a polynomial and returns it as new formula
factorize():Formula
factorizes and returns it as new formula
toBytes():Bytes
packs Formula into haxe.io.Bytes for more efficiently storage
Formula.fromBytes(b:Bytes):Formula
static function to extract a Formula from haxe.io.Bytes

Samples

var x:Formula, a:Formula, b:Formula, c:Formula, f:Formula;
x = 7.0;
a = "a: 1+2*3"; // a has a defined name
f = "2.5 * sin(x-a)^2";
// change name of Formula
x.name = "x";
// bind Formulas as parameters to other Formula
f.bindMap(["x" => x, "a" => a]);
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
// fast calculation at runtime
trace( f.result ); // 0
// derivation // 2.5*(((2*(sin(x-a)^2))*cos(x-a))/sin(x-a))
trace( f.derivate("x").simplify().toString(0) );
// change value (keeps parameter bindings)
x.set("atan(a)");
x.bind(a); // a has a defined name to bind to
trace( f.toString(0) ); // 2.5*(sin(x-a)^2)
trace( f.toString(1) ); // 2.5*(sin(atan(a)-(1+(2*3)))^2)
trace( f.toString(2) ); // 2.5*(sin(atan((1+(2*3)))-(1+(2*3)))^2)
// unbind parameter
f.unbind(a); // unbind a Formula
f.unbindParam("x"); // unbind by param-name
// or alternatively: //f.unbindArray([a , x]); // unbind array of Formulas
//f.unbindParamArray(["a", "x"]); // unbind array of param-names
//f.unbindAll(); // or unbind all params
trace( f ); // 2.5*(sin(x-a)^2)
// operations with Formulas
a = "a: 1-2"; x = "x = 3*4";
c = 5;
f = a + x / c;
f.name = "f";
// show parameters
// c has no name, so operation will not generate param for f
trace( f.params() ); // [ "a", "x" ]
// debugging Formulas
f.debug(); // f = a+(x/5) -> (1-2)+((3*4)/5)
// simplify reduces operations
a.set(a.simplify());
trace( f ); // -1+((3*4)/5)
// using math functions
f = Formula.sin(c * a) + Formula.max(f, 3);
f.name = "F";
f.debug(); // F = sin(5*a)+max(f,3) -> sin(5*-1)+max((a+(x/5)),3) -> sin(5*-1)+max((-1+((3*4)/5)),3)
// error handling
c = "4";
f = "3 * c";
try f.bind(c) catch(e:FormulaException) trace(e.msg); // Error: Can't bind to unnamed parameter...
var s:String = "4 + (3 - )";
try {
f = s;
} catch (e:FormulaException) {
trace(e.msg); // Error: Missing right operand.
var spaces = ""; for (i in 0...e.pos) spaces += " ";
trace(s);
trace(spaces + "^");
}

More can be found in formula-samples repository.

Todo

  • remove of unnecessary parentheses in string output
  • option for parsing in/out to reduce notation of number-params multiplication like: "2x + 3y"
  • cleaner algorithms for term-transformations
  • more ways to customize the simplification of terms
  • comparing terms for math-equality

Possible tasks in future

  • handling other datatypes for values (integer, fixed-point numbers, vectors, matrices, complex numbers)
  • more math operations (hyperbolic functions, logic operators)
  • handle recursive parameter bindings (something like x(n+1) = x(n) ...)
  • definite integrals (or even indefinite later on)
  • gpu-optimization for parallel calculations

Releases

Packages

Contributors

Languages