This section shows some examples using Maple to detect some patterns. In all of these the
main maple function used is patmatch
. Some example also show the Mathematica command
to compare results with.
Many of these can be done in Maple without using patmatch
command, and even using
shorter code. But these examples are meant to show how to use patmatch
.
This detects Reduced Riccati ode \(y'=a x^n + b y^2\) where \(a,n,b\) are scalars and \(y(x)\) is the dependent function. The input to the proc is the ode and the dependent function \(y(x)\). The parsing function will return \(a,b,n\) if successful match is found, or FAIL if ode does not match the expected pattern.
reduced_riccati_parse:=proc(ode::`=`,func::function(name),$) local RHS; local y:=op(0,func); local x:=op(1,func); local la,a,b,n; try RHS:=timelimit(30,[solve(ode,diff(y(x),x))]); if nops(RHS)<>1 then RETURN(FAIL); fi; RHS:=expand(RHS[1]); catch: RETURN(FAIL); end try; if patmatch(RHS,a::anything*x^(n::anything)+b::anything*y(x)^2,'la') then assign(la); if has(a,x) or has(a,y(x)) then RETURN(FAIL); fi; if has(n,x) or has(n,y(x)) then RETURN(FAIL); fi; if has(b,x) or has(b,y(x)) then RETURN(FAIL); fi; RETURN(a,b,n); else RETURN(FAIL); fi; end proc:
Example usage
ode:=diff(y(x),x)=x-1+y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [_Riccati] ode:=diff(y(x),x)=x-1+y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [_Riccati] ode:=diff(y(x),x)=-3*x^2+y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); -3, 1, 2 [[_Riccati, _special]] ode:=diff(y(x),x)=x^(-4)+y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); 1, 1, -4 [_rational, [_Riccati, _special]] ode:=diff(y(x),x)=sin(x)*x^(-4)+y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [_Riccati] ode:=diff(y(x),x$2)=x^(-4)+y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [[_2nd_order, _with_linear_symmetries]] ode:=diff(y(x),x)-x^(-4)-9*y(x)^2=0: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); 1, 9, -4 [_rational, [_Riccati, _special]] ode:=diff(y(x),x)=1/x+x*y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [_rational, _Riccati] ode:=diff(y(x),x)=a*1/x+b*y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); a, b, -1 [_rational, [_Riccati, _special]] ode:=diff(y(x),x)=a*x^n+b*y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); a, b, n [[_Riccati, _special]] ode:=diff(y(x),x)=a*x^n+y(x)+b*y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [_Riccati] ode:=diff(y(x),x)=y(x)*x^n+b*y(x)^2: reduced_riccati_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [_Bernoulli]
This detects the general Riccati ode \(y'=f_0(x) + f_1(x) y(x)+ f_2(x) y^2\)
The input to the proc is the ode and the dependent function \(y(x)\). The parsing function will return \(f_0,f_1,f_2\) if successful match is found, or FAIL if ode does not match the expected pattern.
\(f_0,f_2\) can not be zero (i.e. missing), but \(f_1\) could be missing.
In the case \(f_1=0\), either \(f_0\) or \(f_2\) or both must be functions of \(x\). Also in the case of \(f_1=0\), if it is reduced Riccati, then it return FAIL.
In the case \(f_1\) is present and also depends on \(x\), then now \(f_0,f_2\) are both allowed not to be functions of \(x\). But if \(f_1\) present and also does not depend on \(x\), then now at least one of \(f_0,f_2\) must be function of \(x\).
general_riccati_parse:=proc(ode::`=`,func::function(name),$) local RHS; local y:=op(0,func); local x:=op(1,func); local stat; local la,f0,f1,f2; stat:= reduced_riccati_parse(ode,func); if stat<>FAIL then #this is reduced riccati, hence not general RETURN(FAIL); fi; #now check if general riccati try RHS:=timelimit(30,[solve(ode,diff(y(x),x))]); if nops(RHS)<>1 then RETURN(FAIL); fi; RHS:=expand(RHS[1]); RHS:=collect(RHS,[y(x),y(x)^2]);#must collect to insure the right form catch: RETURN(FAIL); end try; if patmatch(RHS,f0::anything+f1::anything*y(x)+f2::anything*y(x)^2,'la') then assign(la); if f0=0 or f2=0 then RETURN(FAIL); fi; if has(f0,y(x)) or has(f1,y(x)) or has(f2,y(x)) then RETURN(FAIL); fi; if has(f1,x) then RETURN(f0,f1,f2); else if not has(f0,x) and not has(f2,x) then RETURN(FAIL); else RETURN(f0,f1,f2); fi; fi; else #check for f1 missing if patmatch(RHS,f0::anything+f2::anything*y(x)^2,'la') then assign(la); if has(f0,y(x)) or has(f2,y(x)) then RETURN(FAIL); fi; if not has(f0,x) and not has(f2,x) then RETURN(FAIL); fi; RETURN(f0,0,f2); else RETURN(FAIL); fi; fi; end proc:
Example usage
ode:=diff(y(x),x)=f0(x)+f1*y(x)+f2*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); f0(x), f1, f2 [_Riccati] ode:=diff(y(x),x)=f0+f1(x)*y(x)+f2*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); f0, f1(x), f2 [_Riccati] ode:=diff(y(x),x)=f0(x)+f1(x)*y(x)+f2*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); f0(x), f1(x), f2 [_Riccati] ode:=diff(y(x),x)=f0(x)+f1(x)*y(x)+f2(x)*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); f0(x), f1(x), f2(x) [_Riccati] ode:=diff(y(x),x)=f0(x)+f2(x)*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); f0(x), 0, f2(x) [_Riccati] ode:=diff(y(x),x)=x+f2(x)*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); x, 0, f2(x) [_Riccati] ode:=diff(y(x),x)=x+f2*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); FAIL [[_Riccati, _special]] ode:=diff(y(x),x)=1/x+y(x)+y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); 1 -, 1, 1 x [_rational, _Riccati] ode:=diff(y(x),x)=1/x+y(x)+x*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); 1 -, 1, x x [_rational, _Riccati] ode:=diff(y(x),x)=x*y(x)+c*y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); FAIL [_Bernoulli] ode:=diff(y(x),x)=x-1+y(x)^2: general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); -1 + x, 0, 1 [_Riccati] ode:=diff(y(x),x)=(3+9*x+8*y(x))^(2): #this onde needs the collect general_riccati_parse(ode,y(x)); DETools:-odeadvisor(ode); 81*x^2 + 54*x + 9, 144*x + 48, 64 [[_homogeneous, class C], _Riccati]
Where \(n\) can not be \(1\). \(a\) can be missing but not \(b,c\). And \(a,b,c\) are scalars.
The parsing routing returns either FAIL or \(a,b,c,b\) if pattern is matched.
homog_c_parse:=proc(ode::`=`,func::function(name),$) local RHS; local y:=op(0,func); local x:=op(1,func); local la,a,b,c,n,p,the_power; try RHS:=timelimit(30,[solve(ode,diff(y(x),x))]); if nops(RHS)<>1 then RETURN(FAIL); fi; RHS:=simplify(RHS[1]); catch: RETURN(FAIL); end try; if patmatch(RHS,(p::anything)^(the_power::anything),'la') then assign(la); if the_power=1 then RETURN(FAIL); fi; if patmatch(p,a::anything+b::anything*x+c::anything*y(x),'la') then assign(la); if has(a,x) or has(a,y(x)) then RETURN(FAIL); fi; if has(b,x) or has(b,y(x)) then RETURN(FAIL); fi; if has(c,x) or has(c,y(x)) then RETURN(FAIL); fi; RETURN(a,b,c,the_power); else if patmatch(p,b::anything*x+c::anything*y(x),'la') then assign(la); if has(b,x) or has(b,y(x)) then RETURN(FAIL); fi; if has(c,x) or has(c,y(x)) then RETURN(FAIL); fi; RETURN(0,b,c,the_power); else RETURN(FAIL); fi; fi; else RETURN(FAIL); fi; end proc:
Examples usages
ode:=diff(y(x),x)=(3+9*x+8*y(x))^(1/2): homog_c_parse(ode,y(x)); DEtools:-odeadvisor(ode); 1 3, 9, 8, - 2 [[_homogeneous, class C], _dAlembert] ode:=diff(y(x),x)=(3+9*x+8*y(x))^(2): homog_c_parse(ode,y(x)); DEtools:-odeadvisor(ode); 3, 9, 8, 2 [[_homogeneous, class C], _Riccati] ode:=(x+y(x))*diff(y(x),x)=1: homog_c_parse(ode,y(x)); DEtools:-odeadvisor(ode); 0, 1, 1, -1 [[_homogeneous, class C], [_Abel, 2nd type, class C], _dAlembert] ode:=diff(y(x),x)=sqrt(x+y(x)+1): homog_c_parse(ode,y(x)); DEtools:-odeadvisor(ode); 1 1, 1, 1, - 2 [[_homogeneous, class C], _dAlembert] ode:=diff(y(x),x)=1/(x+y(x)+1): homog_c_parse(ode,y(x)); DEtools:-odeadvisor(ode); 1, 1, 1, -1 [[_homogeneous, class C], [_Abel, 2nd type, class C], _dAlembert] ode:=diff(y(x),x)=1/(x+y(x)+sin(x)): homog_c_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [[_Abel, 2nd type, class C]] ode:=diff(y(x),x)=(x+y(x)^2)^(2/3): homog_c_parse(ode,y(x)); DEtools:-odeadvisor(ode); FAIL [y=_G(x,y')]
And also find the values of \(A,B,f\) in the above. This can be used to parse first order ode after checking it is linear ode (linear in \(y'\) and \(y\)).
The parsing routing returns either FAIL or \(A,B,f\) if pattern is matched.
restart; linear_first_order_parse:=proc(ode::`=`,func::function(name),$) local y:=op(0,func); local x:=op(1,func); local LHS; local la,A,B,F; LHS:= lhs(ode)-rhs(ode); LHS:= numer(normal(LHS)); #this is needed to normalize the ode #for example 1/y' + x = 0 will becomes 1+x y' = 0, else #the pattern will fail #must collect on y and y' to get the pattern to work OK for all cases LHS:= collect(LHS,diff(y(x),x)); LHS:= collect(LHS,y(x)); if patmatch(LHS,A::anything*diff(y(x),x)+B::anything*y(x)+F::anything,'la') then assign(la); if has(A,y(x)) then RETURN(FAIL); fi; if has(B,y(x)) then RETURN(FAIL); fi; if has(F,y(x)) then RETURN(FAIL); fi; RETURN(A,B,F); else if patmatch(LHS,A::anything*diff(y(x),x)+F::anything,'la') then assign(la); if has(A,y(x)) then RETURN(FAIL); fi; B:=0; if has(F,y(x)) then RETURN(FAIL); fi; RETURN(A,B,F); else RETURN(FAIL); fi; fi; end proc:
Notice that we had to check for the general case \(A y'+ B y + F\) first and if that fails then check for the specific case \(A y' + F \). This is because if \(y\) term is missing then Maple will not match the pattern. i.e. it will not give \(B=0\). So have to make separate pattern matching for the case with missing \(y\) in the ode.
For the case \(A y' + F\) Maple will match \(F=0\) if this term is missing. So we do not need to make more specialized pattern for just \(A y'\).
This is typical. We start with the most general pattern and if that fail, we go to more specialized ones.
Examples usages
ode:=1/diff(y(t),t)+t=0; linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); t, 0, 1 [_quadrature] ode:=1/diff(y(t),t)+t=y(t); linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); FAIL [[_homogeneous, class C], [_Abel, 2nd type, class C], _dAlembert] ode:=t*diff(y(t),t)+5=0; linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); t, 0, 5 [_quadrature] ode:=t^2*diff(y(t),t)+t*y(t)=sin(t); linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); 2 t , t, -sin(t) [_linear] ode:=y(t)*diff(y(t),t)+t*y(t)=sin(t); linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); FAIL [[_Abel, 2nd type, class A]] ode:=sin(t)*diff(y(t),t)-99*ln(t)*y(t)=sin(t)+y(t); linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); sin(t), -99 ln(t) - 1, -sin(t) [_linear] ode:=sin(t)*diff(y(t),t)-99*ln(t)*y(t)=sin(t)+9*diff(y(t),t)/t+ln(t); linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); 9 sin(t) - -, -99 ln(t), -ln(t) - sin(t) t [_linear] ode:=diff(y(t),t)-y(t)^2=sin(t); linear_first_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); FAIL [_Riccati]
And also find the values of \(A,B,C,f\) in the above. This can be used to parse second order ode after checking it is linear ode (linear in \(y'',y',y\)).
The parsing routing returns either FAIL or \(A,B,C,f\) if pattern is matched.
linear_second_order_parse:=proc(ode::`=`,func::function(name),$) local y:=op(0,func); local x:=op(1,func); local LHS; local la,A,B,C,F; # DEBUG(); LHS:= lhs(ode)-rhs(ode); LHS:= numer(normal(LHS)); #this is needed to normalize the ode #for example 1/y'' + x = 0 will becomes 1+x y'' = 0, else #the pattern will fail LHS:= collect(LHS,diff(y(x),x$2)); LHS:= collect(LHS,diff(y(x),x)); LHS:= collect(LHS,y(x)); if patmatch(LHS,A::anything*diff(y(x),x$2) +B::anything*diff(y(x),x) +C::anything*y(x)+F::anything,'la') then assign(la); if has(A,y(x)) then RETURN(FAIL); fi; if has(B,y(x)) then RETURN(FAIL); fi; if has(C,y(x)) then RETURN(FAIL); fi; if has(F,y(x)) then RETURN(FAIL); fi; RETURN(A,B,C,F); elif patmatch(LHS,A::anything*diff(y(x),x$2) +C::anything*y(x)+F::anything,'la') then assign(la); if has(A,y(x)) then RETURN(FAIL); fi; B:=0; if has(C,y(x)) then RETURN(FAIL); fi; if has(F,y(x)) then RETURN(FAIL); fi; RETURN(A,B,C,F); elif patmatch(LHS,A::anything*diff(y(x),x$2) +B::anything*diff(y(x),x)+F::anything,'la') then assign(la); if has(A,y(x)) then RETURN(FAIL); fi; if has(B,y(x)) then RETURN(FAIL); fi; C:=0; if has(F,y(x)) then RETURN(FAIL); fi; RETURN(A,B,C,F); elif patmatch(LHS,A::anything*diff(y(x),x$2)+F::anything,'la') then assign(la); if has(A,y(x)) then RETURN(FAIL); fi; B:=0; C:=0; if has(F,y(x)) then RETURN(FAIL); fi; RETURN(A,B,C,F); else RETURN(FAIL); fi; end proc:
We see we had to check for all possible patterns. \(A y''+B y'+C y+f\) and \(A y''+B y'+f\) and \(A y''+C y+f\) and \(y''+f\). This is because the pattern for say \(B y'\) will not return \(B=0\) if the term \(B y'\) is missing. In this case there are 4 possible pattern to check for for second order linear ode.
It is possible to do this parsing without using pattern ofcourse (see my ode section below,
using the command DEtools:-convertAlg(ode,y(x));
will do it. But the point here is to
do this using patterns.
For expression of many terms, many patterns are need to cover all possible inputs. This is
becuase there is no option to tell Maple to match A::anything*y(x)
and give \(A=0\)
when the whole term is missing. If there was such an option, it will make life much
simpler.
Examples usages
ode:=t/diff(y(t),t$2)+t=0: linear_second_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); t, 0, 0, t [[_2nd_order, _quadrature]] ode:=t*diff(y(t),t$2)+5=0: linear_second_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); t, 0, 0, 5 [[_2nd_order, _quadrature]] ode:=t*diff(y(t),t$2)+diff(y(t),t)+5*t=0: linear_second_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); t, 1, 0, 5 t [[_2nd_order, _missing_y]] ode:=t*diff(y(t),t$2)+99*y(t)=0: linear_second_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); t, 0, 99, 0 [[_Emden, _Fowler]] ode:=t*diff(y(t),t$2)+99*y(t)=sin(t)*y(t)+diff(y(t),t): linear_second_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); t, -1, -sin(t) + 99, 0 [[_2nd_order, _with_linear_symmetries]] ode:=y(t)*diff(y(t),t$2)+99*y(t)=sin(t)*y(t)+diff(y(t),t): linear_second_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); FAIL [[_2nd_order, _reducible, _mu_x_y1], ode:=diff(y(t),t)*diff(y(t),t$2)+99*y(t)=sin(t)*y(t): linear_second_order_parse(ode,y(t)); DEtools:-odeadvisor(ode); FAIL [NONE]
Using Mathematica pattern the above is a little simpler, since there one can use default zero if term is missing, so no need to check for all possible patterns. Here is an example
rule = (aa : a_. y''[x] : 0) + (bb : b_. y'[x] : 0) + (cc : c_. y[x] :0) + any_. :> {Plus@a, Plus@b, Plus@c, any}; x^2*y''[x] + x*y'[x] + x*y[x] - 3*x /. rule
Gives {x^2, x, x, -3 x}
and if a term is missing, same pattern still works
x^2*y''[x] - 3*x /. rule
Gives {x^2, 0, 0, -3 x}
so we did not have to make pattern for possible missing terms. I
was not able to do the same using Maple’s pattern match as it has no default option. In this
example, we see that Mathematica’s pattern matching is better. If I find a way to do the
same in Maple I will update this.
Given list \(3,4,x,x^2,x^3\), find those elements of form \(x^n\) where \(n\) is anything other than \(1\).
In Maple
L:=[3,4,x,x^2,x^3]; map(X->`if`(patmatch(X,x^n::nonunit(anything)),X,NULL),L) [x^2, x^3]
The above can also be written in the long form
restart; L:=[3,4,x,x^2,x^3]; map(proc(X) if patmatch(X,x^n::nonunit(anything)) then X; else NULL; fi; end proc,L) [x^2, x^3]
In Mathematica
Cases[{3, 4, x, x^2, x^3}, x^_] {x^2, x^3}
Given list \(3,4,x,x^2,x^3\), find those elements of form \(x^n\) where \(n\) is now allowed to be 1. In Maple
L:=[3,4,x,x^2,x^3]; map(X->`if`(patmatch(X,x^n::anything),X,NULL),L) [x, x^2, x^3]
In Mathematica
Cases[{3, 4, x, x^2, x^3}, x^_.] {x,x^2,x^3}
Given list \(3,4,x,x^2,x^3\), return list of exponents of \(x\), other than \(1\).
In Maple
L:=[3,4,x,x^2,x^3]; f:=proc(X::anything,x::symbol) local la,n; if patmatch(X,x^n::nonunit(anything),'la') then eval(n,la); else NULL; fi; end proc; map(X->f(X,x),L) [2, 3]
Another option is to use inlined if, like this
restart; L:=[3,4,x,x^2,x^3]; map(proc(X) local la,n; if patmatch(X,x^n::nonunit(anything),'la') then eval(n,la); else NULL; fi; end proc, L); [2, 3]
In Mathematica
Cases[{3, 4, x, x^2, x^3}, x^n_ -> n] {2, 3}
Gives list {f(a,a),f(a,b),f(c,d),f(b,b)}
return {g(a),f(a,b),f(c,d),g(b)}
where
only function that takes two arguments which are the same is replaced by \(g(x)\) where \(x\) here is the
argument in the original list.
In Maple
restart; L:={f(a,a),f(a,b),f(c,d),f(b,b)}; map(X->[unassign('x'),`if`(patmatch(X,f(x::anything,x::anything),'la'),[assign(la),g(x)][],X)][],L) {f(a, b), f(c, d), g(a), g(b)}
Or using the long form of map, which is more clear, even though the code is longer
restart; L:={f(a,a),f(a,b),f(c,d),f(b,b)}; map(proc(X) local la; if patmatch(X,f('x'::anything,'x'::anything),'la') then g(eval('x',la)); else X; fi; end proc, L ); {f(a, b), f(c, d), g(a), g(b)}
In Mathematica
L = {f[a, a], f[a, b], f[c, d], f[b, b]} L /. f[x_, x_] -> g[x] {g[a], f[a, b], f[c, d], g[b]}
Given f(a)+f(b)
transform it using pattern f(x::anything)->x^2
to obtain a^2+b^2
In Maple
expr:=f(a)+f(b); map( proc(X) local la,x; if patmatch(X,f(x::anything),'la') then eval(x,la)^2; else NULL; fi; end proc, expr); a^2 + b^2
In Mathematica
f[a] + f[b] /. f[x_] -> x^2 a^2+b^2
Given [1, x, x^2, x^3]
write pattern to change all x^n::anything
to r(n)
In Maple
L:=[1, x, x^2, x^3]; map( proc(X) local la,n; if patmatch(X,x^n::'nonunit'(anything),'la') then r(eval(n,la)); else X; fi; end proc, L); [1, x, r(2), r(3)]
In Mathematica
{1, x, x^2, x^3} /. x^n_ -> r[n] {1, x, r[2], r[3]}
Given f(a + b) + f(a + c) + f(b + d)
apply transformation f(a + x_) + f(c + y_) -> p(x, y)
Here to do not use map, since we want to apply pattern on the whole expression. In Maple
restart; expr:=f(a+b)+f(a+c)+f(b+d): if patmatch(expr,f(a+x::anything)+f(c+y::anything)+z::anything,'la') then p(eval(x,la),eval(y,la))+eval(z,la); else expr; fi; p(b, a) + f(b + d)
In Mathematica
f[a+b]+f[a+c]+f[b+d]/. f[a+x_]+f[c+y_]->p[x,y] f[b+d]+p[b,a]
Write pattern to change f(a^b)
to p(a^b,b)
In Maple
restart; expr:=f(a^b); if patmatch(expr,f( (a::anything)^b::anything ),'la') then print(la); p( eval(a,la)^eval(b,la) , eval(b,la) ); else expr; fi; p(a^b, b)
In Mathematica
f[a^b] /. f[x : _^n_] -> p[x, n] p[a^b,b]
Write pattern to select from list [3,-4,5,-2]
only the numbers that are negative.
In Maple, we use the form patmatch(X, conditional(patttern,condition))
restart; L:=[3,-4,5,-2]; map( proc(X) local la; if patmatch(X, conditional(n::integer,n<0),'la') then eval(n,la); else NULL; fi; end proc, L); [-4, -2]
In Mathematica
Cases[{3, -4, 5, -2}, x_ /; x < 0] {-4,-2}
Write pattern to select from list [z(1, 1), z(-1, 1), z(-2, 2)]
only those with first
argument which is negative.
In Maple, we use the form patmatch(X, conditional(patttern,condition))
restart; L:=[z(1, 1), z(-1, 1), z(-2, 2)]; map( proc(X) local la,a,b; if patmatch(X, conditional(z(a::integer,b::integer),a<0),'la') then z(eval(a,la),eval(b,la)); else NULL; fi; end proc, L ); [z(-1, 1), z(-2, 2)]
In Mathematica
Cases[{z[1, 1], z[-1, 1], z[-2, 2]}, z[x_ /; x < 0, y_]] {z[-1,1],z[-2,2]}
Write pattern to select from list 1+a,2+a,-3+a]
only those that have negative number added
to \(a\) and output \(p(x)\) where \(x\) is that number.
In Maple, we use the form patmatch(X, conditional(patttern,condition))
L:=[1+a,2+a,-3+a]; map( proc(X) local la,x; if patmatch(X, conditional(a+x::integer,x<0),'la') then p(eval(x,la)); else X; fi; end proc, L ); [1 + a, 2 + a, p(-3)]
In Mathematica
{1+a,2+a,-3+a}/. (x_/;x<0)+a->p[x] {1 + a, 2 + a, p[-3]}
Use pattern to square only numbers in a list.
L:=[2.3,4,7/8,a,b]; map( proc(X) local la,x; if patmatch(X, x::numeric,'la') then eval(x,la)^2; else X; fi; end proc, L ); [5.29, 16, 49/64, a, b]
In Mathematica
{2.3, 4, 7/8, a, b} /. (x_ /; NumberQ[x]) -> x^2 {5.29,16,49/64,a,b}
Use pattern to convert p(4.5) + p(3/2) + p(u)
to 22.5 + p(u)
by squaring and adding
arguments of those function which has its argument numeric.
p:=x->`if`(x::numeric,x^2,x); p(4.5) + p(3/2) + p(u); 22.50000000 + u
In Mathematica
p[x_?NumberQ] := x^2 p[4.5] + p[3/2] + p[u] 22.5 + p[u]
Write pattern to pick all elements from list which are not integers.
L:=[a, b, 0, 1, 2, x, y]: map( proc(X) local la,x; if patmatch(X, conditional( x::anything, not _type(x,integer) ),'la') then eval(x,la); else NULL; fi; end proc, L ); [a, b, x, y]
This can also be done without pattern matching like this
select(not type,L,integer) [a, b, x, y]
In Mathematica
Cases[{a, b, 0, 1, 2, x, y}, Except[_Integer]] {a, b, x, y}
Replace variable \(x\) in expression with a value \(1\).
L:=[x, x^2,y,z, sin(x), exp( tan(x) )]: f:=proc(X::anything,x::symbol) local la,y; if patmatch(X, conditional( y::anything, _has(y,x) ),'la') then eval(y,la); eval(%,x=1); else X; fi; end proc; map(X->f(X,x),L); [1, 1, y, z, sin(1), exp(tan(1))]
Actually, we do not need patmatch for this, but the above is just an exercise. This can be done in one line in Maple as follows
L:=[x, x^2,y,z, sin(x), exp( tan(x) )]: map(X->eval(X,x=1),L) [1, 1, y, z, sin(1), exp(tan(1))]
In Mathematica
L={x, x^2,y,z, Sin[x], Exp[Tan[x]]} L/.x->1 {1,1,y,z,Sin[1],Exp[Tan[1]]}
Replace variable \(x\) in expression with a list.
L:=[x, x^2,y,z]: f:=proc(X::anything,x::symbol) local la,y; if patmatch(X, conditional( y::anything, _has(y,x) ),'la') then eval(y,la); eval(%,x={a,b}); else X; fi; end proc; map(X->f(X,x),L); [{a, b}, {a, b}^2, y, z]
Actually, we do not need patmatch for this, but the above is just an exercise. This can be done in one line in Maple as follows
L:=[x, x^2,y,z]: map(X->eval(X,x={a,b}),L) [{a, b}, {a, b}^2, y, z]
In Mathematica
{x, x^2, y, z} /. x -> {a, b} {{a, b}, {a^2, b^2}, y, z}
Replace \(sin\) by \(cos\)
f:=proc(X::anything) local la,x; if patmatch(X, conditional( x::anything, _has(x,sin) ),'la') then eval(x,la); eval(%,sin=cos); else X; fi; end proc; L:=[sin(x), cos(x)+sin(2*x),tan(x)]: map(X->f(X), L); [cos(x), cos(x) + cos(2*x), tan(x)]
Actually, we do not need patmatch for this, but the above is just an exercise. This can be done in one line in Maple as follows
L:=[sin(x), cos(x)+sin(2*x),tan(x)]: map(X->eval(X,sin=cos), L) [cos(x), cos(x) + cos(2*x), tan(x)]
In Mathematica
{Sin[x], Cos[x] + Sin[2*x], Tan[x]} /. Sin -> Cos {Cos[x], Cos[x] + Cos[2 x], Tan[x]}
Use pattern to replace \(x^n\) by \(f(n)\)
restart; expr:=1 + x^2 + x^4; F:=proc(X::anything,x::symbol) local la,y,n; if patmatch(X, (y::anything)^(n::'nonunit'(anything)) ,'la') then if eval(y,la)=1 then #bug in maple? X; else f(eval(n,la)); fi; else X; fi; end proc; map(X->F(X,x), expr); f(4) + f(2) + 1
In Mathematica
1 + x^2 + x^4 /. x^p_ :> f[p] 1 + f[2] + f[4]
replaces a whole expression by default. In Maple, this is easier to do it without pattern, like this
restart; expr:=f(1, 2, z); e:=map(X->`if`(X::integer,"int",X),[op(expr)]); f(op(e)) f("int", "int", z)
In Mathematica, a pattern works easier
Replace[f[1, 2, z], _Integer :> "int", {1}] f["int", "int", z]
The main issue is that it is hard to match a squence in Maple. For example, in Mathematica this works
f[1, 2, z] /. f[x___] :> x Sequence[1, 2, z]
But in Maple
expr:=f(1, 2, z); patmatch(expr, f(x::anything)) false
So pattern matching does work to match sequence of arguments.