what is morfa

Morfa is a general purpose programming language which enables custom Domain Specific Language (DSL) creation. It aims at combining fast and robust development of large systems with high expressiveness and performance.

  • statically typed with type inference for variables

  • JIT compiled and fast

  • user-defined operators

  • object-oriented, functional and generic programming

Morfa is presently used to develop a suite of toolboxes for scientific computing which use natural mathematical syntax. This suite includes toolboxes and Domain Specific Languages for matrix manipulations and linear algebra, optimization, ODE's and others.

operator ⊗
{
    kind = infix,   precedence = mul
}
alias ⊗ = kron;     // bind operator to function performing Kronecker product
operator ᵀ
{
    kind = postfix, precedence = not
}
alias $ᵀ = trans;   // $ indicates postfix operator here
var A = randn(3,4);
disp(speye(5,5) ⊗ (A * A ᵀ) );


                            
var n = 1000;
var diag = randn(n, 1);
var diag1 = randn(n-1, 1);
var T = bdiag(diag);        // create diagonal matrix
T{1} = diag1;               // substitute elements on sub- and superdiagonal
T{-1} = diag1;
T[1,1] = T[n,n];            // some additional substitution

// concatenate matrices to define the LHS of a linear system
var A = ᴹ[  T,          eye(n,n)    |
            eye(n,n),   2 * T       ];

var B = randn(2*n, 1);      // define the RHS
var x = linsolve(A, B);     // solve a block diagonal system of equations
                            
public interface OnClickListener
{
    public func onClick(view: View): void;
}
public class View
{
    public func setOnClickListener(listener: OnClickListener): void;
}
var view = new View;
view.setOnClickListener(new class OnClickListener
{
    public override func onClick(view: View): void
    {}  // some implementation of event handling goes here...
});
                            
var problem = new class SymbolicOptimizationDefinition { func new()
{
    // use optimization DSL to define variables...
    variable 2 <= 'x <= 3;
    variable 'y;
    variable 'z <= 5;
    
    // ... constraints and the objective function
         'z * 'y >= 7;
    0 <= 'x * 'y <= 5;
    minimize 'x^3 * 'y - 'z + 'x * 'y * 'z;
}};
var solver = new CoinWrapper(problem, false);
solver.solve(zeros(3,1));
                            
// use parser combinators to parse signed ternary integer numbers
func digitArrayToNumber(digits: text[]): int // ...
property ternaryInt(): Parser < int >
{
    // parse sequence of '0', '1', '2''s
    return (anyOf('0', '1', '2'))+ >> digitArrayToNumber;
}
property signedTernaryInt(): Parser < int >
{
    // parse ternary integer or negative ternary integer
    return ternaryInt | 
           char('-') -> ternaryInt >> func (n: int) { return -n; };
}        
var answer: int = parse(signedTernaryInt, "-1120");
                            
var problem = new class CallbackOdeDefinition { func new()
{
    var t = time;
    var x: Matrix = 1;
    // use DSL to define an ordinary differential equation x' = 2x
    ∂x / ∂t == func()
               {
                   return 2*x;
               };
}};
var solver = new OdepackWrapper(OdepackAlgorithm.lsode);
solver.calculate(problem, linspace(0.0, 10.0, 20));


                            
// defining maximum likelihood estimation problem for the Michaelis-Menten enzyme kinetic experiment
var likelihood = new class Likelihood { func new()
{
 
    variable 'α >= 0;                    // maximum reaction velocity,
    variable 'β >= 0;                    // Michaelis constant
    variable 'σ >= 0;
    
    // reaction velocity 'v and substrate concentration 's provided in data
    
    // the model
    model independent 'v ~~ N('α * 's / ('β + 's), ('σ * 's / ('β + 's)) ^ 2 );
}};

                            

Version 0.3.0 of Morfa is available for download: Win 64-bit / Linux (Ubuntu) 64-bit..

Morfa language is licensed under GPL version 3. For detailed information on licensing of Morfa components visit the licensing page.

news about morfa

releases / events
videos

v0.3.0 released


Version 0.3.0 of Morfa has been released. See here for the change-log.

Talk on Morfa given on CeBIT 2015 Developer World

Videos on using DSL's designed in Morfa

for whom

Morfa is a language for everyone who needs to develop fast and robust code and, at the same time, have access to high-level programming features to keep that code concise and expressive.

It is also designed for those who don't want to resort to using several programming languages to solve one problem.

The story


Coming from an econometrics/data analysis background, we have desired a language, which would allow us to define complex macroeconomic models and, at the same time, be a versatile and reliable general purpose language. We would like to have a single tool which would bridge the gap between interpreted languages like MATLAB® and R and languages like C++ and Java aimed at performance and stable software development.

Morfa is at its core a general purpose programming language: it can be used as a C++, Java or C# substitute. On the other hand it is designed so that all the math can be done as easily as possible. All mathematical and modelling features stem from natural and elegant programming constructs like classes and polymorphism, operator overloading, templates etc. No workarounds or hacks allowed, the design of the mathematical support machinery is completely transparent. Moreover writing own low-level algorithms results in fast code optimized using LLVM, so there is no need to resort to lower-level programming languages for the "hard work".

Using Morfa we have developed various libraries which handle numerical and symbolic computations - most importantly matrix operations, linear algebra, optimization and symbolic differentiation.

Morfa has been inspired by and is based on D and shares some of its features.

main features

Exceptional support for user-defined operators


  • define any identifier to be parsed as an operator - infix, postifix, prefix...

operator ∑
{
    kind = prefix,
    precedence = add
}
func ∑(summand: SomeSummableType): SomeSummedType;
// ...
var mySum = ∑ x_i * y_j + ∑ c_k;
                        
  • ... or define custom indexing and surrounding operators

operator 〔〕
{
    kind = surrounding,
    precedence = max
}
template < TList... >
func 〔〕(sequence: TList): void
{
    // operate on a sequence of arguments of different type
}
// ...
〔5, 5.6, "Hello World"〕;
                        

Performance and portability thanks to the LLVM


func fib(n: int): int
{
    return if(n < 2) n else fib(n-1) + fib(n-2);
}
assert(fib(20) == 6765); // ca. 200 times faster than MATLAB® R2012a
                        

Multi-paradigm general purpose programming language


Morfa provides the typical constructs that allow stable developement of large software systems. Taking the numerical and syntactical features away, you get a language Java and C# developers will immediatly feel at home with.

  • garbage collector, debugger, C interface-friendly

  • classes and interfaces for object-oriented programming

public interface AnInterface
{
    public func doSomething(): void;
}
public class AClass: AnInterface
{
    public func doSomething(): void
    {}   // implement doing something
}
                        

  • closures and higher-order functions for functional programming

public func getChecker(): (func(): bool)
{
    var condition = true;
    return func() { return condition; };
}
                        

  • templates and mixins for generic programming

template < AType >
public struct AStructure
{
    const isStruct = type.traits.IsStructType < AType >;
    public static func get(): AType
    {
        static if (isStruct)
        {
            return AType();
        }
        else if (traits(compiles, new AType))
        {
            return new AType;
        }
        else assert (false);
    }
}
                        

Interactive development in REPL console using JIT compilation


> import morfa.io.print;
> println("Hello World!");
Hello World!
> import matrix.Matrix;
> var multiplier = 2;
> var mySVD = func(m: Matrix) { return svd(multiplier * m); };
> disp(mySVD(ᴹ[1, 0 |
               0, 0 ]  ));
               
 dense real matrix, size: 2x1, type: general

   |    1
 --------
 1 | 2.00
 2 |    0
                    

Extensive standard library


Toolboxes for scientific computing


All of the features of these toolboxes are implemented in Morfa using overloading, templates and inheritance mechanisms.

  • matrix operations and linear algebra

var A = randn(n,n);             // random matrix creation
var B = T{1};                   // access the superdiagonal
A{-1} = B;                      // substitute the subdiagonal
var C = A[1..n, 1];             // access single column
var D = ᴹ[A, A |                // concatenate
          A, A ];
var E = A * A;                  // linear algebra
var F = linsolve(A, eye(n,n));
var S = svd(A);
// NOTE: none of the {}, ᴹ, | is built-in!
                    
  • linear and non-linear, constained and unconstrained optimization

// define and overload operators: variable, minimize, <=, >=, ==, etc.
// for example, within some limited scope overload:
func <=(lhs: float, rhs: Expression): SomeAdditionalType
{
    // handle addition of a non-linear constraint lhs <= rhs
}
// ...
variable 0  <= x <= 1;
variable -∞ <= y <= 1;
-0.5 <= x*y <= 0.5;
minimize x^3 + y^2;
                    
  • ordinary differential equation solution

// define and overload operators like ∂, /, ==, e.g.:
operator ∂
{
    kind = prefix,
    precedence = not
}
// ...
∂x / ∂t == func(): Matrix
           {
               return 2*x + t;
           };
                    
  • numerical integration

// define a set of operators to naturally handle numerical integration:
operator ∫
{
    kind = prefix,  precedence = add
}
operator on
{
    kind = infix,   precedence = assign    associativity = left
}
operator ⋴
{
    kind = infix,   precedence = compare
}
// ...
∫ x * exp(-x^2 * y^3 + log(y)) on [x ⋴ [-∞, ∞], y ⋴ [-1, 1] ]
                    

authors


Michał Bernardelli


Paweł Bylica


Radosław Cybulski


Piotr Dobaczewski


Piotr Janiuk


Daniel Kłobuszewski


Paweł Kowal


Mariusz Kozakiewicz


Anna Sawicka


Juliusz Stasiewicz


Krzysztof Surdacki


Radosław Zagórowicz


Artur Zawłocki

contact morfa

Sign up for morfa newsletter

To contact the morfa team post on the mailing list morfalang-users.

Morfa is developed by imapp. To get in touch send an email to morfa@imapp.pl.


Projekt współfinansowany przez Unię Europejską z Europejskiego Funduszu Rozwoju Regionalnego

© Copyright imapp

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.