The latest version of the Iterator package is now available at the Maplesoft Application Center. It provides a new export, MultiPartition, extensions to existing exports, and options to most exports for transforming the output to a more desirable form. The help pages have been improved, with some hopefully interesting examples. Here is one, showing how it can be used to write a procedure for solving a generalized alphametic.
alphametic := module()
export ModuleApply;
local SymbolToAlg;
ModuleApply := proc(eq :: string
, base :: posint := 10
, { compile :: truefalse := true }
, $
)
local chars
, ex,i,n,vars,x,pred,iter
, p
;
uses ST=StringTools;
# Parse the string and convert an equation to an expression.
ex := parse(eq);
ex := `if`(ex :: equation
, (lhs-rhs)(ex)
, ex
);
# Extract the symbols (names).
vars := indets(ex,symbol);
# Convert each symbol in ex to an algebraic equivalent
# in terms of the characters in the the symbol.
ex := subs([seq(x = SymbolToAlg(x,base), x=vars)],ex);
# Assign vars the characters in ex
vars := indets(ex,symbol);
n := nops(vars);
if n > base then
error "too many characters (%1) for base %2", n, base;
end if;
# Convert characters to indexed names of V
ex := subs([seq(vars[i]='V'[i],i=1..n)],ex);
ex := expand(ex);
# Assign a predicate that returns true if the permutation
# evaluates ex to 0 (evalb does not work with Compiler:-Compile).
pred := subs('_ex'=ex, proc(V :: Array(datatype=integer[4]))
local ex := _ex;
if ex=0 then
return true;
else
return false;
end if;
end proc
);
# Optionally compile the predicate
if compile then
pred := Compiler:-Compile(pred);
end if;
# Construct an iterator to iterate over all acceptable permutations.
iter := Iterator:-Permute(0..(base-1),n, 'accept'=pred);
# Find solutions and format as equations.
vars := map(convert,vars,string);
chars := ST:-Explode(eq);
seq(ST:-Join(subs([seq(vars[i]=convert(p[i],string), i = 1..n)]
, chars)
,"")
, p=iter
);
end proc:
# Procedure that converts a symbol into a multinomial
# over the characters of the symbol.
SymbolToAlg := proc(symb,base::posint:=10)
local val,char;
val := 0;
for char in convert(symb,string) do
val := base*val+cat(``,char);
end do;
val;
end proc:
end module:
eq := "maple*sim = modelica + model":
alphametic(eq);
"16540*781 = 12904836 + 12904"