Skip to content

Functions preprocessor

Axel Kramer edited this page Jan 8, 2022 · 11 revisions

Add new identifiers in AST2Expr

To add new predefined constants or function symbols you have to extend the following String arrays in org.matheclipse.core.convert.AST2Expr

  • UPPERCASE_SYMBOL_STRINGS - symbols which are exactly one uppercase constant or function
  • DOLLAR_STRINGS - symbols starting with a '$' character
  • SYMBOL_STRINGS - constant identifiers, which are not used as a function identifier
  • FUNCTION_STRINGS - function identifiers

We can for example add a new user function MyFunction to the FUNCTION_STRINGS array.

Generate files

If the AST2Expr definitions have changed these two programs can generate new sources in the Eclipse console output:

Implementing new functions

The built-in Symja constants are implemented in the file:

The built-in Symja functions are implemented in the packages:

System built-in functions must implement the interface IFunctionEvaluator and are evaluated according to the assigned function symbol attributes defined in the IFunctionEvaluator#setUp() method (only very special built-in functions must implement the interface ICoreFunctionEvaluator and evaluate their arguments in a non standard way).

A lot of the system functions have associated pattern matching rule files in the folders:

These rules are converted by the class org.matheclipse.core.preprocessor.RulePreprocessor into the package org.matheclipse.core.reflection.system.rules

A new built-in Symja function name should be added to org.matheclipse.core.convert.AST2Expr#FUNCTION_STRINGS String[] array, with a leading upper case character in its name.

A typical "template" for an example built-in function MyFunction is implemented like this. The evaluation of MyFunction({a,b,c}) should return the first argument {a,b,c} if the first argument is a list.

package org.matheclipse.core.builtin;

import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.exception.Validate;
import org.matheclipse.core.eval.interfaces.AbstractEvaluator;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;

public class UserFunctions {
	static {
		F.MyFunction.setEvaluator(new MyFunction());
	}

	private static class MyFunction extends AbstractEvaluator {

		@Override
		public IExpr evaluate(final IAST ast, EvalEngine engine) {
		   // test if only 1 argument is allowed:
			Validate.checkRange(ast, 2);
			if (ast.arg1().isList()) {
				return ast.arg1();
			}
			return F.NIL;
		}
	}

	private final static UserFunctions CONST = new UserFunctions();

	public static UserFunctions initialize() {
		return CONST;
	}

	private UserFunctions() {

	}

}

It must be initialized in the F.class static block:

...

	static {
		Thread INIT_THREAD = null;
...

			VectorAnalysisFunctions.initialize();
			QuantityFunctions.initialize();
			FinancialFunctions.initialize();
			WXFFunctions.initialize();
			WindowFunctions.initialize();
			UserFunctions.initialize();
...


	}	
...

Now the evaluation of MyFunction({a,b,c}) returns the first argument {a,b,c}. And the evaluation of MyFunction(test) returns unevaluated as MyFunction(test).

Integrating your own Java library with the WXF format

For creating a quick prototype which can use Symja functions to call your own library, you should consider implementing functions similar to the BinarySerialize, BinaryDeserialize functions with the WXF format:

The implementation which is used in Symja can be found here:

Clone this wiki locally