New Features in Maple 16: Maple Programming Language

Next Feature


The Maple language is a full programming language designed for mathematical computation, combining the best principles from procedural, functional, and object-oriented programming. Approximately 95% of Maple's mathematical algorithms are implemented using the Maple programming language, so all users have access to the same programming power that Maple is built on. Because of Maple's pervasive use of powerful, high-level constructs, the same algorithm in Maple needs on average ten times less code compared to implementing it in the C language. In addition, because it is an interpreted language, you get immediate feedback, making it an ideal prototyping environment.

Maple 16 adds support for light-weight objects for enhanced object-oriented programming. Such objects integrate closely with Maple using operator overloading, making your objects almost indistinguishable from built-in Maple types. With the object model, Maple becomes an even more open and extensible system, perfect for both small and large scale mathematical application development.

Example: Implementing Objects

In this example, new light-weight objects are used to represent integers modulo n. While Maple already supports modular arithmetic, this example demonstrates how objects are implemented and used. Prior to Maple 16, modules could also be used for this purpose. Maple modules represent another very powerful construct, and are extremely useful in many contexts. When used to represent objects, however, modules require a lot more overhead for storing the associated information. The new objects in Maple 16 are more memory efficient.

module IntMod()
option object;

local base := 1;
local value := 0;

# implement a ModuleApply and ModuleCopy routine
# to use IntMod() as a object constructor
export ModuleApply::static := proc()
Object( IntMod, _passed );
end;

export ModuleCopy::Static := proc( self::IntMod, proto::IntMod,
v::integer, b::integer, $ )
if ( _npassed < 3 ) then
# if a value was not given, copy the prototype
self:-value := proto:-value;
else
# use the given value
self:-value := v;
end;

if ( _npassed < 4 ) then
# if a base was not given, opy the prototype
self:-base := proto:-base;
else
# use the given base
self:-base := b;
end;

# apply the mod
self:-value := self:-value mod self:-base;
end;

# implement ModulePrint to make the display nice
export ModulePrint::static := proc( self::IntMod )
nprintf( "%d mod %d", self:-value, self:-base );
end;

# Implement Module type to enable type checking with
# with a specified base
export ModuleType::static := proc( self, type, b, $ )
if ( _npassed = 2 ) then
true;
else
evalb( self:-base = b );
end;
end;

# accessor to get the stored value
export getValue::static := proc( self::IntMod )
self:-value;
end;

# implement the + operator to allow IntMods to work properly
# in sum statements. We assume that the modular arthemetic is
# contagious and the entire addition become modular
export `+`::static := proc( )
local ints, imods, total, base, other;

# remove the stuff we aren't going to manipulate
( ints, other ) := selectremove( type, [_passed],
{ 'IntMod', 'integer' } );

( imods, ints ) := selectremove( type, ints, 'IntMod' );

base := imods[1]:-base;
if ( not andmap( type, imods, 'IntMod'( base ) ) ) then
error "all IntMods must be of the same base"
end;

#Add the IntMods and the integer constant, if one exists
total := ( `if`( numelems(ints) > 0, ints[1], 0 ) +
add( getValue(i), i in imods ) ) mod base;

# return a sequence
IntMod( total, base ), op( other );
end;

# implement the * operator
export `*`::static := proc( )
local ints, imods, total, base, other;

# remove the stuff we aren't going to manipulate
( ints, other ) := selectremove( type, [_passed],
{ 'IntMod', 'integer' } );

( imods, ints ) := selectremove( type, ints, 'IntMod' );

base := imods[1]:-base;
if ( not andmap( type, imods, 'IntMod'( base ) ) ) then
error "all IntMods must be of the same base"
end;

# remove the stuff we aren't going to manipulate
total := ( `if`( numelems(ints) > 0, ints[1], 1 ) *
add( getValue(i), i in imods ) ) mod base;

# return a sequence
IntMod( total, base ), op( other );
end;

# implement the ^ operator
export `^`::static := proc( self::IntMod, exponent::integer, $ )
IntMod( self:-value^exponent, self:-base );
end;

# implement the basic comparison operators
export `=`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value = other:-value )
end;

export `<`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value < other:-value )
end;

export `<=`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value <= other:-value )
end;

export `>`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value > other:-value )
end;

export `>=`::static := proc( self::IntMod, other::IntMod, $ )
evalb( self:-base = other:-base and
self:-value >= other:-value )
end;

# override the convert routine to allow IntMods to be converted
# to integers. The inverse does not work because we con't know
# which base to use
export convert::static := proc( v, toType, $ )
if ( v::IntMod ) then
if ( toType = ':-integer' ) then
v:-value;
else
error "cannot convert from IntMod to %1", toType;
end;
else
error "cannot convert into IntMod from %1", v
end;
end;
end:


Using Objects Within Maple


 

> i0m5 := IntMod(0, 5); 1
 

thismodule
 

Notice the nicely printed form. 

Now create a new object by copying an existing one.   Specify a new value, but notice that the base will be copied from the given object. 

> i1m5 := Object(i0m5, 1); 1
 

thismodule
 

Test that these newly create objects are instances of the IntMod class 

> type(i1m5, 'IntMod'); 1
 

true
 

The ModuleType procedure allows the IntMod type check to support specifying a base. 

> type(i1m5, ('IntMod')(3)); 1
 

false
 

> type(i1m5, ('IntMod')(5)); 1
 

true
 

ModInt implements a '+' operator.  You can use this to generate the rest of the integers mod 5  

> i2m5 := `+`(i1m5, 1); 1
 

thismodule
 

> i3m5 := `+`(i2m5, 1); 1
 

thismodule
 

> i4m5 := `+`(i3m5, 1); 1
 

thismodule
 

> `+`(i4m5, 1); 1
 

thismodule
 

> `+`(i3m5, i4m5); 1
 

thismodule
 

The implementation of + also supports non-integer values, by leaving them alone. 

> `+`(`+`(`+`(4, i1m5), 18), i2m5, 3, f(x), y); 1
 

`+`(`*`(object, `*`(thismodule)), `*`(, `*`(ModuleCopy::Static)), `*`(, `*`()))
 

IntMod overloads the * and ^ operators. 

> `*`(i3m5, `*`(i4m5, `*`(y, `*`(f(x))))); 1
 

`*`(`^`(thismodule, object), `*`(`^`(ModuleCopy::Static, ), `*`(`^`(, ))))
 

> i2m5; 1
 

thismodule
 

> `*`(`^`(i2m5, 2)); 1
 

thismodule
 

> `*`(`^`(i2m5, 3)); 1
 

thismodule
 

> `*`(`^`(i2m5, 4)); 1
 

thismodule
 

> `*`(`^`(i2m5, 5)); 1
 

thismodule
 

The ModInt object also overloads the convert function.  This allows the conversion of IntMods to integers. 

> convert(i3m5, 'integer'); 1
 

3
 

Next Feature

How to Proceed:   Pricing & Purchase Evaluate Upgrade Get Price Quote Buy Online