Вы находитесь на странице: 1из 5

JSS

Experiments with Maxima


Aug 2014, Volume 01, Issue 01.

http://maxima.sourceforge.net//

Pattern Matching on lists in Maxima I


Pankaj Sejwal
pankajsejwal@gmail.com

Abstract
This article is an educated guess on how Mathematicas Blank, BlankSequence and
BlankNullSequence serving as basis for pattern matching work.

Keywords: Pattern matching, Mathematica, Maxima.

1. Mathematica style pattern matching on lists


This article is to give an introduction on the basic working mechanism of Mathematicas list
elements segregation based on Blank(_), BlankSequence(__) and BlankNullSequence(___)
notations and analyzing how it backtracks on precomputed list elements based on following
pattern notations. Maxima provides pattern matching on expressions using matchdeclare
and defmatch, but pattern matching on lists remains relatively less explored. It would be
wastage of space if significance of pattern matching is explained here as it usually remains
one of the most powerful feature in any software that supports it.
Sample pattern matching in Mathematica :
{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} /. {a_, b__, c_} :> {{a}, {b}, {c}}
{{1}, {2, 3, 4, 5, 6, 7, 8, 9}, {0}}
Another example, Split a list into disjoint sub-lists,so that one gets disjoint sub-lists such that
any element can be connected with another element through other elements inside that list
(like a disjoint chains of elements).Obviously sub-lists are of any length.
Most[Rest[# //. {a___, {x__List}, b___} -> {a,x,b} &
/@ (FlattenAt[{{1}, ##, {2}} &[(Intersection[{{a, b},
{b,c},{c,d},{e,f},{f,t},{j,k,l},{m,n},{l,m},{t,k},{k,h,i}}])],2]
//.{q___,s:{a___,b_}|{___,{a___,b_},___},r___,k:{b_,d___}, t__}->{q,{s,k},r,t})]]

Pattern Matching on lists

{{{a, b}, {b, c}, {c, d}}, {{e, f}, {f, t}, {t, k},
{k, h, i}}, {{l, m}, {m, n}}, {j, k, l}}

2. Conceptual Description
The basic idea behind these sequences is that it allocates the allowed number of elements to
a particular sequence. Blank must get one and only one element, BlankSequence might hold
one or more and BlankNullSequence might hold none or more. First example in article is a
good example for this description. To decide the allocation for each next pattern there is need
to backtrack up to some point and reallocate list elements from there to the present pattern.
That some point is nothing else but BlankSequence(__) or BlankNullSequence(___). Lets
call these containers. Once one of these containers is reached while backtracking then there
is no need to go before this.
{1,2,3,4,5,6,7,8,9,0}/.{a_,b_,c__,d_,e_}:>{{a},{b},{c},{d},{e}}
{{1}, {2}, {3, 4, 5, 6, 7, 8}, {9}, {0}}
{1,2,3,4,5,6,7,8,9,0}/.{a_,b_,c__,d__,e_}:>{{a},{b},{c},{d},{e}}
{{1}, {2}, {3}, {4, 5, 6, 7, 8, 9}, {0}}
In these two examples above, in the first one once control has reached container c, for d,e
content is taken from c.Allocations before c remain untouched irrespective of what follows
c.Pattern is considered a failure if pattern after c could not be satisfied with the input from
c as in the following case.
{1,2,3,4,5}/.{a_,b__,c__,d_,e_,f_}:>{{a},{b},{c},{d},{e},{f}}
{1, 2, 3, 4, 5}
To understand how it backtracks, lets take two examples,
{1, 2, 3, 4, 5} /. {a___, b_} :> {{a}, {b}}
{{1, 2, 3, 4}, {5}}
{1, 2, 3, 4, 5} /. {a___, b_, c_} :> {{a}, {b}, {c}}
{{1, 2, 3}, {4}, {5}}
In first case, b is 5 while when it finds one more Blank following it, it again starts allocation
from beginning Blank and now b gets 4 and c gets 5. In case of more such Blank patterns,
each time allocation starts from first blank in queue to the current Blank.
In case all the patterns are Blank then pattern match is successful only if number of Blank
are equal to number of elements in list.

Experiments with Maxima

{1, 2, 3, 4, 5} /. {a_, b_, c_} :> {{a}, {b}, {c}}


{1, 2, 3, 4, 5}
{1, 2, 3, 4, 5} /.{a_, b_, c_, d_, e_}:>{{a}, {b}, {c}, {d}, {e}}
{{1}, {2}, {3}, {4}, {5}}
The above mentioned backtracking Blank takes from the last of elements from container. But
if a container follows another container, then
{1, 2, 3, 4, 5}/.{a_, b___, c_, d__, e_}:>{{a}, {b}, {c}, {d}, {e}}
{{1}, {}, {2}, {3, 4}, {5}}
{1, 2, 3, 4, 5}/.{a_, b___, c_, d_, e__}:>{{a}, {b}, {c}, {d}, {e}}
{{1}, {}, {2}, {3}, {4, 5}}
backtracking results in allocation of elements from beginning of list from stopping point
container which in this case is b and the rest of the elements are put into current container.
It is also possible to write a pattern that is certain to be redundant largely.
{1,2}/.{a___,b___,c___,d___,e___,f___,g___}:>{{a},{b},{c},{d},{e},{f},{g}}
{{}, {}, {}, {}, {}, {}, {1, 2}}

3. Implementation details
3.1. Unique identity for every element
A good approach to address the problem of finding complement of duplicate elements is to
not have them during the processing at all.There is need to find complement when a stopping
container is followed by another container and allocation of elements happens from beginning
of list from last sub-list of stopping container to the patterns in between, the remaining
elements are kept in last container. So, one can use Maxima built in feature gensym() to
generate a unique symbol for all the list elements so internally the program handles unique
symbols rather than actual output. As part of post processing, one can substitute these in
received results.

3.2. List format for patterns


Let there be any list named list elements with some elements. As demonstrated in following
example, Blank must be allowed to keep one element and in case needed, it can be replaced
during processing if it arrives between stopping container and current pattern.

Pattern Matching on lists

list_elements=[1,2,3,4,5]
Could be one of,[a_,[1]],[a_,[2]]....[a_,[5]]
Because BlankSequence must have at least one element,[a__,[1],[2,3,4,5]]
BlankNullSequence can have none or more, [a___,[],[1,2,3,4,5]]
In case of BlankSequence(__) and BlankNullSequence(___) the operations performed on
the last sub-list are same but segregating information differently helps out in keeping the
working mechanism for both same.The second element in both these cases never gets touched
once decided as stopping container.

3.3. Cases with Blank as starting point


If BlankSequence(__) or BlankNullSequence(___) are the starting points of pattern then
rest of the patterns can prey upon its last sub-list but if Blank is the starting pattern then
there is need to prefix the pattern list with a BlankNullSequence(___), lets call it pivot.
Now the process of backtracking can work with this pivots last sub-list to allocate elements
to rest of patterns.
list_ele=[[1,2],3,4,[5,6],7,[8,9]])]
[[_a],"=",[[___pivot,[],[[1,2],3,4,[5,6],7]],[_a,[[8,9]]]]]
[[__b,_a],"=",[[__b,[1],[2,3,4,5,6,7,8]],[_a,[9]]]]
Both these patterns are relevant if only last element is of significance.Mathematica wont
acknowledge the first as a pattern but this implementation on Maxima considers it as a way
to get the last n-elements out from list. To get more refined result some post processing
on final list can be done to remove pivot container or could be passed to some checks and
rejected, but it could be left to the user as well.

4. Examples for usage of program on Maxima


Syntax is disect([list of patterns],[list of elements]
disect([_a,_b,_c],[[1,2],3,4,[5,6],7,[8,9]]);
[[___pivot,[],[[1,2],3,4]],[_a,[[5,6]]],[_b,[7]],[_c,[[8,9]]]]
disect([_a],[[1,2],3,4,[5,6],7,[8,9]]);
[[___pivot,[],[[1,2],3,4,[5,6],7]],[_a,[[8,9]]]]
disect([_s,_r,___w],[9,1,2,3,[4,5]]);
[[_s,[9]],[_r,[1]],[___w,[],[2,3,[4,5]]]]
disect([___q,___e,___r,___s,___w,___t],[1,2,3,4,5]);

Experiments with Maxima


[[___q,[]],[___e,[]],[___r,[]],[___s,[]],[___w,[]],[___t,[],[1,2,3,4,5]]]

5. Source
One can avail the source code at https://github.com/pankajsejwal/pattern-matching

Вам также может понравиться