Introduction to Patterns

Math 213 - Math with Mathematica
Christopher Hanusa

Overview

In this tutorial, we explore how Mathematica uses patterns.  By the end of this tutorial, you should be able to use Mathematica to check for patterns in data and lists and define function that are only valid on certain inputs.

Important Concept: Q

The computer can determine if the number you give it is even or odd.  
The function EvenQ is one of many Mathematica functions that ask a question (Q).  When you evaluate a number, EvenQ determines if the number is even or not.  Evaluate the next cell.

EvenQ[3]
EvenQ[4]
EvenQ[Sqrt[2]]

Go to the documentation center and search for `Q' and focus on the built-in commands that end in Q, especially on the second page of results.  You will get a good feel for all the sorts of questions you can ask Mathematica to determine if a variable satisfies a property or not.

How Mathematica looks for patterns

In various situations, you will probably want Mathematica to determine if it sees a pattern in a list.  We'll focus solely on numbers and lists for now, but Mathematica can handle more than lists and you can read more in its tutorial "Introduction to patterns" if you need this at some point.

First, we'll introduce the function MatchQ.  Notice the Q suffix; you know that this is a function that will either output True or False.  So what does it do?

?MatchQ

That wasn't too helpful, now was it?  Here's an example from the documentation center.

Head[Pi]
Head[{1,2,3}]
Head[1+q]

MatchQ[12345,_Integer]
MatchQ[12.345,_Integer]

Now you can start to guess what it is doing---it checks to see if the given input is an integer.
Mathematica will check for all sorts of objects, not just integers.
For numbers, Mathematica will check Integer, Rational, Real, and Complex.  For more examples, in the documentation center, you can go to tutorial/TypesOfNumbers.

Now let's talk about that underscore (_) that is before the Integer in the MatchQ function call above.  There are three types of wild cards, _, __, and ___.  That is, a single underscore, a double underscore, and a triple underscore.  The difference is that a single underscore means "something", a double underscore means "a (nonempty) sequence of data", and a triple underscore means "a sequence of data that might be empty".  So if we type

MatchQ[12345,_]

We are, in effect, asking Mathematica if 12345 is something.  Well, yes, yes it is. And each of the following examples is "something" as well:

MatchQ[,_]
MatchQ[x^5,_]
MatchQ[gaga,_]
MatchQ[Sqrt[30],_]

We can also check to see if an input is of the form something to the something power...

MatchQ[,_^_]
MatchQ[x^5,_^_]
MatchQ[gaga,_^_]
MatchQ[Sqrt[30],_^_]

The differences between the three types of wild cards is helpful when searching for elements in lists.  Consider the following inputs, that try to determine if a given list contains a certain pattern.  I have divided them into different types based on the number of underscores I have used.

MatchQ[{0,1,2,3},{_,0,_}] (* Type I *)

MatchQ[{0,1,2,3},{__,0,__}] (* Type II *)

MatchQ[{0,1,2,3},{___,0,___}] (* Type III *)

MatchQ[{0,1,2,3},{_,1,_}] (* Type I *)

MatchQ[{0,1,2,3},{__,1,__}] (* Type II *)

MatchQ[{0,1,2,3},{___,1,___}] (* Type III *)

TYPE I: You can see that the list {0,1,2,3} does NOT contain the pattern {_,0,_} or {_,1,_}, because each of these two are checking to see if the list is of length three and if the entry (0 or 1) is in the middle of the list.  
TYPE III: You can see that the list {0,1,2,3} DOES contain the patterns {___,0,___} and {___,1,___}, because {0,1,2,3} looks like {nothing,0,(1,2,3)} and also like {(0),1,(2,3)}, which are of the form with the wild cards.
TYPE II is where there is a difference.  The list {0,1,2,3} does contain the pattern {__,1,__} because it looks like {(0),1,(2,3)}, which has at least one entry before 1 and at least one entry after 1.  However, {0,1,2,3} does not contain the pattern {__,0,__} because there is no entry before the 0.

Something else we can do with pattern matching:  we can use MatchQ with any other Q function, such as PrimeQ and EvenQ:

MatchQ[2,_?PrimeQ]

We are trying to see if "2" is Prime.  Right now this has not brought us much more than we already have.  The power of this construction comes from the next two tutorial sections that follow.  For instance, we already have the following expression that does the same thing

PrimeQ[2]

One last construction that might be helpful in pattern matching is testing if a number fits in a range somewhere, such as the following command which determines if the number two and a half is "something" and if it fits between the numbers 0 and 10.

MatchQ[2.5,_?(0<#<10&)]

The above expression evaluates to True because the following expression is True.

0<2.5<10

Then you can mix and match the statements by asking if 2 and 2.5 are integers in that range.

MatchQ[2,_Integer?(0<#<10&)]
MatchQ[2.5,_Integer?(0<#<10&)]

Comprehension Questions:

1.  Explore what Mathematica considers a Number (use pattern checking and NumberQ).  Pi? 2+I (imaginary)? 3.21?  a variable q before it's defined as 1? After q is defined as 1?  How about a list such as {1}?  Others?

2. Which of the following patterns does {0,1,2,3} contain, and why?
{_,_,1,_}, {_,_,2,_}, {__,3,__},{___,3,___},{_,1,___}, {0,_,3},{0,__,3},{0,___,3}.

3. Create three MatchQ statements, on the list {2,3,5,7} as follows.  You know the answers; get Mathematica to agree with you.
First, check if the list is a list that starts with the number two.
Next, check if the list is a nonempty list with integer entries.
Last, check if the list is a list with odd entries.

4. Write a function that takes as its input a list, and outputs True or False depending on if the number 1 appears before the number 2 in the list.  Then verify that your program works.

Defining functions with a restricted domain

There is a direct correspondence between the _ in the pattern testing above and the _ we used in defining functions.  When we were defining a function such as:

f[x_]:={x,x}

what we were actually doing was defining f which looked for an input of length one (because there is one underscore _) and gave it the name x.  Then the right hand side explains that the output of the function is this input squared. This is why f has no problem doing the following:

f[{2,1,0}]

Yet it can not evaluate

f[y,z]

because y,z is not an input of length 1.  On the other hand, if we had defined f differently

f2[x__]:={x,x}

Then if would be able to evaluate both

f2[{2,1,0}]
f2[y,z]

But not

f2[]

because (empty sequence) does not match the pattern __.

The two major messages in this section of the tutorial are as follows.  First, the letter before the wild card is the name we give to whatever fills the wildcard in a pattern.  Second, we can use the pattern matching from the previous section to define functions on a restricted domain.  For example, here is a function that is defined only if the input is an integer:

g[x_Integer] := Prime[x]-x
{g[10],g[10.2],g[z]}

You can see that g is defined as follows.  Check to see if the input is of length one and is an integer.  If so, give it the name x.  The output of the function will be the x-th prime number minus x.

As you can imagine, this means that we can restrict the domain of the function by using pattern checking.  Here are two examples.  First, define a function that is only valid on the interval (0,10).

h[x_?(0<#<10&)]:=x+10
{h[-1],h[2],h[100]}

You can see the function does not evaluate unless if the input matches the pattern.  The same is true in the following example which is defined only when the input is a list that contains (at least one) 1.

i[{list1___,1,list2___}]:={list1,list2}
{i[1],i[{1}],i[{2}],i[{2,1,3,4}],i[{3,4,5}],i[{0,1,2,1,3}]}

The function i only gives an output when the list contained a 1.  We can define what should happen to the rest of the elements by giving a more general rule as follows:

i[{list___}]:={list}
{i[1],i[{1}],i[{2}],i[{2,1,3,4}],i[{3,4,5}],i[{0,1,2,1,3}]}

To see which rule takes precedence, use the ? command for help.

?i

We can define multiple instances of the same function if we want to define a piecewise defined function, such as the following.  (Accompanied by a plot)

j[x_?(#<0&)]:=-x
j[x_?(0≤#≤1&)] := 2
j[x_?(1<#&)]:=x
Plot[j[x],{x,-3,3}]

Also, by giving the variables names, Mathematica can also check to see if the same input appears multiple times:

k[{list1___,i__,i__,i__,list2___}]:={list1,list2}

k[{1,1,2,2,3,3,3}]

k[{1,2,1,2,1,2}]

k[{3,3,1,2,3,3}]

Comprehension Questions:

5. Create a new function f3 that does the same thing as f and f2 and that DOES accept the empty list as an input.  What is the output when the empty sequence is inputted?  What about the empty list?

6: Define the txp function from Chapter 2 by first defining txp only for odd integers, and then defining txp only for even integers.  Verify that your function does work and show a list of what happens when you iterate the function 40 times for the input 27.

7: Create a function that takes as its input a list.  If the list contains a 1 before a 2, the output should be the list where the 1 and the 2 have changed places.  If the list does not contain a 1 before a 2, the output should be the original list.