Showing posts with label Cases. Show all posts
Showing posts with label Cases. Show all posts

Friday, July 10, 2015

How to See the Equivalence of Select and Cases

MatchQ and PatternTest Equate Cases and Select

Select and Cases are essential Mathematica filtering functions. Select filters expressions, usually Lists, with predicates, such as ones that end with Q (evaluate ?*Q to see them) or those that don't, such as Greater, Less, and others that I list here. Cases uses patterns such as testing for a Head (e.g. _Integer) or a more general pattern (e.g. for a 2-element List, {x_,y_}.

Cases and Select are equivalent and a versatile Mathematica programmer knows how to use either one in any circumstance according to the need of the moment. The keys to seeing their equivalence are MatchQ, which translates a pattern into a predicate, and PatternTest (_?test), which translates a predicate into a pattern.

MatchQ[4.1,_Real]

True

MatchQ[{2,2.1},{_Integer,_Real}]

True

Thus you can take any usage of Cases and translate it into Select.

Cases[{a,4,4.2,6,7.5,8},x_Integer/;x>4]

{6,8}

integerGreaterThan4Q@n_:=MatchQ[n,_Integer&&n>4];
Select[{a,4,4.2,6,7.5,8},integerGreaterThan4Q]

{6,8}

And you can take any usage of Select and translate it into Cases.

Select[{1,2,4,7,6,2},EvenQ]

{2,4,6,2}

Cases[{1,2,4,7,6,2},_?EvenQ]

{2,4,6,2}

If we built our own predicate for EvenQ using MatchQ, it works the same way.

Select[{1,2,3,4},MatchQ[#/2,_Integer]&]

{2,4}

However note the need for parentheses around the test, which is often the case with PatternTest - the no parens usage fails.

Cases[{1,2,3,4},_?(MatchQ[#/2,_Integer]&)]

{2,4}

Cases[{1,2,3,4},_?MatchQ[#/2,_Integer]&]

{}

The reason is that Blank and PatternTest both have a higher Precedence ('stickiness') than Function, and so they stick together and PatternTest ends up inside the pure Function instead of using the pure Function as the pattern test. You don't need to worry about that — just as a rule of thumb put parens around any 'homemade' test.

Precedence/@{PatternTest,Blank,Function}

{680.,730.,90.}

The Q Predicates


This is a handy way to use Partition, especially using {} so a final short sublist won't be dropped from a 'ragged' List. The syntax says

Partition[list, sublist length, offset length, start Position, padding]

and here means divide the List into Partitions of length 4, moving the window that same length 4 with each Partition so there is no overlap, start the List at Position 1,  and the empty set {} for padding tells Partition to return the final sublist even if it's shorter than what is specified by the 2nd argument, and don't pad that final short list. Evaluate this code in your Notebook:

Qpredicates=Names@"*Q";
Print@Length@Qpredicates;
Partition[Qpredicates,4,4,1,{}]//TableForm

Here's the same result in a List.

Names@"*Q"

{AcyclicGraphQ,AlgebraicIntegerQ,AlgebraicUnitQ,AntihermitianMatrixQ,AntisymmetricMatrixQ,ArgumentCountQ,ArrayQ,AssociationQ,AtomQ,BinaryImageQ,BipartiteGraphQ,BooleanQ,BoundaryMeshRegionQ,BoundedRegionQ,BusinessDayQ,ColorQ,CompatibleUnitQ,CompleteGraphQ,CompositeQ,ConnectedGraphQ,ConstantRegionQ,ContinuousTimeModelQ,ControllableModelQ,CoprimeQ,DateObjectQ,DaylightQ,DayMatchQ,DeviceOpenQ,DiagonalizableMatrixQ,DigitQ,DirectedGraphQ,DirectoryQ,DiscreteTimeModelQ,DisjointQ,DispatchQ,DistributionParameterQ,DuplicateFreeQ,EdgeCoverQ,EdgeQ,EllipticNomeQ,EmptyGraphQ,EulerianGraphQ,EvenQ,ExactNumberQ,FileExistsQ,firedQ,FreeQ,GeoWithinQ,GraphQ,GroupElementQ,HamiltonianGraphQ,HermitianMatrixQ,HypergeometricPFQ,ImageQ,IndefiniteMatrixQ,IndependentEdgeSetQ,IndependentVertexSetQ,InexactNumberQ,integerGreaterThan4Q,IntegerQ,IntersectingQ,IntervalMemberQ,InverseEllipticNomeQ,IrreduciblePolynomialQ,IsomorphicGraphQ,KEdgeConnectedGraphQ,KeyExistsQ,KeyFreeQ,KeyMemberQ,KnownUnitQ,KVertexConnectedGraphQ,LeapYearQ,LegendreQ,LetterQ,LinkConnectedQ,LinkReadyQ,ListQ,LoopFreeGraphQ,LowerCaseQ,MachineNumberQ,ManagedLibraryExpressionQ,MandelbrotSetMemberQ,MarcumQ,MatchLocalNameQ,MatchQ,MatrixQ,MemberQ,MeshRegionQ,MixedGraphQ,MultigraphQ,NameQ,NegativeDefiniteMatrixQ,NegativeSemidefiniteMatrixQ,NormalMatrixQ,NumberQ,NumericQ,ObservableModelQ,OddQ,OptionQ,OrderedQ,OrthogonalMatrixQ,OutputControllableModelQ,PartitionsQ,PathGraphQ,PermutationCyclesQ,PermutationListQ,PlanarGraphQ,PolynomialQ,PositiveDefiniteMatrixQ,PositiveSemidefiniteMatrixQ,PossibleZeroQ,PrimePowerQ,PrimeQ,ProcessParameterQ,QHypergeometricPFQ,QuadraticIrrationalQ,QuantityQ,RegionQ,RegularlySampledQ,RootOfUnityQ,SameQ,SatisfiableQ,ScheduledTaskActiveQ,SimpleGraphQ,SquareFreeQ,SquareMatrixQ,StringFreeQ,StringMatchQ,StringQ,SubsetQ,SymmetricMatrixQ,SyntaxQ,TautologyQ,TensorQ,TreeGraphQ,TrueQ,UnateQ,UndirectedGraphQ,UnitaryMatrixQ,UnsameQ,UpperCaseQ,URLExistsQ,ValueQ,VectorQ,VertexCoverQ,VertexQ,WeaklyConnectedGraphQ,WeightedGraphQ}


 

Friday, May 29, 2015

String Processing: StringCases and StringMatchQ

I recently got inconsistent results from StringCases and StringMatchQ (and used Pick instead of Cases). When using Cases or Select, you typically debug issues by mapping MatchQ onto the List that you're sifting for patterns. Similarly, StringMatchQ is the tool used to debug StringCases. However - while I don't believe there is any difference between patterns accepted by MatchQ vs. Cases, there is a significant difference between patterns accepted by StringMatchQ vs. StringCases.

StringMatchQ will accept what are called 'abbreviated String metacharacters'. These are the asterisk wildcard "*" for 0 or more characters, the @ wildcard for one or more non-upper case characters ("@@@@" matches any 4-non-upper case character Expression), and double-backslashes for literal characters (e.g. \\* to match an asterisk).

But StringCases will not; it will only accept StringExpression patterns or RegularExpressions. Here is an example. I want to extract all the "VCathode*" values from this datafile header:

data = {"%", "cln1x", "V", "(V)", "@", "VCathode=2.75392", "V", "(V)", "@", "VCathode=2.29025", "V", "(V)", "@", "VCathode=1.86092", "V", "(V)", "@", "VCathode=1.59846", "V", "(V)", "@", "VCathode=1.40122", "V", "(V)", "@", "VCathode=1.28137", "V", "(V)", "@", "VCathode=1.15876", "V", "(V)", "@", "VCathode=1.06451", "V", "(V)", "@", "VCathode=1.0037", "V", "(V)", "@", "VCathode=0.950678", "V", "(V)", "@", "VCathode=0.881652"};

StringCases with an asterisk fails:

In[190]:= StringCases[data,"VCathode*"]
Out[190]= {{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}}

StringMatchQ with an asterisk works:

In[191]:= StringMatchQ[data,"VCathode*"]
Out[191]= {False,False,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True,False,False,False,True}

Here is the solution for StringCases using StringExpressions. I use Flatten to remove nulls ("{}").

In[192]:= StringCases[#,"VCathode"~~___]&/@data//Flatten
Out[192]= {VCathode=2.75392,VCathode=2.29025,VCathode=1.86092,VCathode=1.59846,VCathode=1.40122,VCathode=1.28137,VCathode=1.15876,VCathode=1.06451,VCathode=1.0037,VCathode=0.950678,VCathode=0.881652}

And here is the solution for StringCases using a RegularExpression. Here I use DeleteCases instead of Flatten to remove nulls, but leave sets of List brackets around the returned values.

In[195]:= StringCases[#,RegularExpression["VCathode.*"]]&/@data//DeleteCases[#,{}]&
Out[195]= {{VCathode=2.75392},{VCathode=2.29025},{VCathode=1.86092},{VCathode=1.59846},{VCathode=1.40122},{VCathode=1.28137},{VCathode=1.15876},{VCathode=1.06451},{VCathode=1.0037},{VCathode=0.950678},{VCathode=0.881652}}

Thank you to Xin Xiao from Wolfram Technical Support.



Wednesday, May 27, 2015

An Example Using Pick to Select Data by Pattern Instead of Cases, Select, or StringCases

Pick

Prefatory remark: To learn Mathematica efficiently you should focus on the most-frequently-used functions. I will provide a list of those soon. For most users Pick[] will not be a frequently-used function. You can learn "esoteric" Mathematica functions just for fun or because in your work certain esoteric functions are handy.

Here, nonetheless, is an example spawned from my not being able to get StringCases to work (solved and explained here), altho strangely StringMatchQ does work, which is the standard way to see if StringCases will work.

This is a file header from a parameter sweep I did in the finite element modeling program COMSOL. The goal is to select the different parameters used in the sweep, which are voltages such as "VCathode=2.29025"; I don't need all the other noise in there.

The way the command works is: 1) StringMatchQ is mapped onto data, which is a List of Strings, and returns True if the target matches the String with "*" wildcard, or False otherwise; 2) Pick then scans data to find instances matching the selection pattern. In this case since Pick's default selection pattern is True, I didn't need to use its 3rd argument that specifies a different selection pattern (such as "1" vs. "0").

data = {"%","cln1x","V","(V)","@","VCathode=2.75392","V","(V)","@","VCathode=2.29025","V","(V)","@","VCathode=1.86092","V","(V)","@","VCathode=1.59846","V","(V)","@","VCathode=1.40122","V","(V)","@","VCathode=1.28137","V","(V)","@","VCathode=1.15876","V","(V)","@","VCathode=1.06451","V","(V)","@","VCathode=1.0037","V","(V)","@","VCathode=0.950678","V","(V)","@","VCathode=0.881652","V","(V)","@","VCathode=0.836608","V","(V)","@","VCathode=0.795234","V","(V)","@","VCathode=0.753297","V","(V)","@","VCathode=0.73737","V","(V)","@","VCathode=0.725229","V","(V)","@","VCathode=0.703015","V","(V)","@","VCathode=0.68059","V","(V)","@","VCathode=0.646921","V","(V)","@","VCathode=0.62848"};

Pick[data,StringMatchQ[#,"VCathode*"]&/@data]

{VCathode=2.75392,VCathode=2.29025,VCathode=1.86092,VCathode=1.59846,VCathode=1.40122,VCathode=1.28137,VCathode=1.15876,VCathode=1.06451,VCathode=1.0037,VCathode=0.950678,VCathode=0.881652,VCathode=0.836608,VCathode=0.795234,VCathode=0.753297,VCathode=0.73737,VCathode=0.725229,VCathode=0.703015,VCathode=0.68059,VCathode=0.646921,VCathode=0.62848}

My next step will be to use Table and Join to insert the correct parameter in the header of the its matching data file from COMSOL.

Trivia: Pick was originally called BinarySelect and Stephen Wolfram re-named it, as is his want, to a short Anglo-Saxon term (a large metal rod is called a pick, or think of using toothpick to pick up food). I ran into him at a ice cream shop and complimented him on the function and asked if he had re-named it. When he was much younger Stephen ate a lot of chocolate and didn't take care of himself physically. But that has changed, he is careful with his diet and spends a lot of time on the treadmill staying in good physical condition.

Friday, May 10, 2013

Flat (Function Attribute of associativity; removes brackets and parentheses)

Why does this function works for more than the two arguments for which it is defined?

In[100]:= log[a_ b_]:=log@a+log@b

In[101]:= log[2 x y]

Out[101]= log[2]+log[x]+log[y]

The answer is that Times has the Attribute Flat, which is Mathematica's interesting name for the mathematical property of associativity. I.e., as we learned in school, (2 + 3) + 4 = 2 + (3 + 4). We can remove the parentheses. So the Attribute is called Flat since, after the name for the function Flatten that removes List brackets, Mathematica knows that for some functions it's valid to remove all parentheses or List brackets. What is handy is to automatically remove all brackets from a user-defined function, use SetAttributes[ function, Flat].

Thus Time's Attributes show it to be more profound than we might expect. We check function Attributes like this:

In[102]:= Attributes@Plus

Out[102]= {Flat,Listable,NumericFunction,OneIdentity,Orderless,Protected}

And we can find all built-in functions with a given attribute like this, first taking all function Names from the System context where they live, using the wildcard "*", then using a pattern in Cases:

In[103]:= Names@"System`*"//Cases[#,_?(MemberQ[Attributes@#,Orderless]&)]&

Out[103]= {ArithmeticGeometricMean,BitAnd,BitOr,BitXor,CoprimeQ,DiracDelta,DiscreteDelta,Equivalent,GCD,HeavisideTheta,KroneckerDelta,LCM,Majority,Max,Min,Multinomial,Plus,Times,UnitStep,Xnor,Xor}

Last, Trace shows how the Flat Attribute affects the operation of Times in the simple example. Mathematica knows it can split up a function applied to two arguments times each other, and, typically for the evaluator, keeps applying the rule to split up all arguments of Times until there are no lists of more than two left.

In[104]:= log[2x y]//Trace

Out[104]= {log[2 x y],log[2]+log[x y],{log[x y],log[x]+log[y]},log[2]+(log[x]+log[y]),log[2]+log[x]+log[y]}

Saturday, March 9, 2013

Introduction to Strings in Mathematica

A format convention in Mathematica is to show quotation marks around strings in input cells, but not in output cells. To show them in output cells, use FullForm.

In[18]:= "I've entered a string by using quotation marks."

Out[18]= I've entered a string by using quotation marks.

In[19]:= Head@%

Out[19]= String

In[20]:= FullForm@%%

Out[20]//FullForm= "I've entered a string by using quotation marks."

In programming languages, "String" is the name for the data type of text expressions. In other words, unlike symbols in a general expression, the symbols in a String, like a, b, c, do not refer to places in memory that store a variable, like a function or value. Symbols in a String do not refer to anything, or you could say they only refer to themselves as "literals", that is, the literal characters or tokens "a", "b", "c". An "a" is just a blank token with nothing behind it; hence the terms "literal" or "token" for a String symbol.

In[21]:= a = 5534.7; a

Out[21]= 5534.7

Trying to use a String as a variable gives an error message.

In[22]:= "a" = "Lookee here."

During evaluation of In[22]:= Set::setraw: Cannot assign to raw object a. >>

Out[22]= "Lookee here."

Consequently, Strings are not evaluated in the usual way that other Expressions are. Wellin et al. in their excellent book suggest that we think of a String as being broken up by Mathematica into a sequence of its characters and then functions are applied to the sequence.

In[8]:= aSentence = "The quick brown fox jumped over the 742 lazy white dogs.";

In[11]:= aSentenceCharacters = aSentence // Characters

Out[11]= {T,h,e, ,q,u,i,c,k, ,b,r,o,w,n, ,f,o,x, ,j,u,m,p,e,d, ,o,v,e,r, ,t,h,e, ,7,4,2, ,l,a,z,y, ,w,h,i,t,e, ,d,o,g,s,.}

Functions, like MatchQ, Cases, Position, etc., that work on non-String expressions do not work on Strings but do work on their sequence of characters.

In[14]:= Position[aSentence, "e"]

Out[14]= {}

So perhaps as Wellin et al suggest, Mathematica first breaks a String into a sequence of characters and applies some of the regular built-in functions as well as some specialized String functions to the sequence.


In[25]:= MatchQ[#, "e"] & /@ aSentenceCharacters

Out[25]= {False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, True, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False}

In[24]:= StringMatchQ[aSentenceCharacters, "e"]

Out[24]= {False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, True, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False}


In[15]:= Position[aSentenceCharacters, "e"]

Out[15]= {{3}, {25}, {30}, {35}, {50}}

In[16]:= StringPosition[aSentence, "e"]

Out[16]= {{3, 3}, {25, 25}, {30, 30}, {35, 35}, {50, 50}}

The position index is repeated in StringPosition since it shows the beginning and ending positions of the matched String.

In[20]:= StringPosition[aSentence, "lazy"]

Out[20]= {{41, 44}}

When working with Strings, you do not need to enclose a String in List brackets:

In[3]:= aString = {"abcd"}

Out[3]= {abcd}

In[4]:= aString2 = "abcd"

Out[4]= abcd

In[5]:= Head@aString2

Out[5]= String

The String is delimited by invisible quotation marks. As usual FullForm and InputForm reveal the way Mathematica sees the String.

In[6]:= FullForm@aString2

Out[6]="abcd"

In[7]:= InputForm@aString2

Out[7]="abcd"

Next we will look at the variety of String functions in Mathematica.

Monday, January 2, 2012

Predicates, Tests, and Test Patterns: How to Build Your Own

Build Your Own: User-defined Examples

Xiangdong Wen of Tech Support noted that the hard part of constructing Predicates is considering all the possible inputs and exceptions. To do a thorough job, we might need to do a Piecewise definition of a Predicate, or define a Predicate with Which, and if desired leave an error message as the final condition at the bottom to catch any exceptions that escaped us.

Limit a Built-in Predicate: lessThanOneQ

lessThanOneQ@x_ := If[ x1 < 1, True, False]

testSet = Range[0, 1.5, .3]

{0., 0.3, 0.6, 0.9, 1.2, 1.5}

lessThanOneQ /@ testSet

{True, True, True, True, False, False}

Test for Specified Length: lengthTwoQ

Clear@lengthTwoQ; lengthTwoQ@x_ := If[Length@x == 2, True, False]

lengthTwoQ /@ {{x, y}, {y, x}, {x, y, z}}

{True, True, False}

Test for Meeting Boolean Combination of Conditions: BinaryQ

By setting the Attributes of our Predicate to Listable, we shortcut the need to use Map over a List.

ClearAll@BinaryQ; SetAttributes[BinaryQ, Listable];
BinaryQ@x_ := If[x === 1 || x === 0, True, False ]

BinaryQ@{0, 3, 1, 1., 2}

{True, False, True, False, False}

One can also use Boolean And (&&) similarly, or any combination of And and Or in a compound Expression.

Test for Membership in a Set: integerLessThan10Q

Here we make a Predicate from a test for an element's membership in a defined set.

integerLessThan10 = Range@10

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

integerLessThan10Q@x_ := If[MemberQ[integerLessThan10, x], True, False]

integerLessThan10Q /@ {4, 4/5, Pi, 3, 11, 251/25}

{True, False, False, True, False, False}

More Examples: maxEqualQ, maxNearQ, valueAtQ, positionNearQ

Different Predicates can test for a variety of related conditions. These are functions I used to test properties of book bestseller lists but here I use random lists for illustration. The first one tests to see if the maximum value of two lists of numbers are the same.

maxEqualQ[x_List, y_List] := If[Max@x == Max@y, True, False]

list1 = RandomInteger[{0, 25}, 20] // Sort

{0, 2, 2, 4, 5, 6, 8, 8, 9, 9, 9, 11, 15, 16, 16, 17, 17, 19, 19, 19}

list2 = RandomInteger[{0, 25}, 20] // Sort

{1, 2, 5, 6, 6, 6, 9, 12, 13, 14, 17, 17, 18, 18, 23, 23, 24, 24, 25, 25}

maxEqualQ[list1, list2]

False

This tests to see if difference between the maximum of two lists is less than a specified magnitude.

maxNearQ[x_List, y_List, nearness_Integer] :=
 If[Abs[Max@x - Max@y] <= nearness, True, False]

maxNearQ[list1, list2, 10]

True

maxNearQ[list1, list2, 1]

False

This tests to see if the Position of the maxima of two lists is the same.

maxPositionEqualQ[x_List, y_List] :=
 If[Position[list1, Max@x] == Position[list2, Max@y], True, False]

maxPositionEqualQ[list1, list2]

False

Using Predicates in Select, Cases, and Related Filter Functions

As you look at these simple examples realize they are but a glimpse of the power of this type of usage that I mentioned at the start of this section. The Predicates, Conditions and Boolean conjunctions used in these filter functions can be arbitrarily complex, and as Mangone notes we are only restricted to anything that Mathematica can compute.

First we define a Predicate and use pure Function since those are idioms that Select uses, then we just use Condition in Cases, since that is the syntax that Cases uses. Consequently I recommend using the Q suffix when naming a Predicate used in Select. Note in the Cases example the additional restriction to Reals using a Head test.

Consider using Predicates in the related filter functions Count, Position, Tally, Gather, Sort, SortBy, etc.

Clear@lessThanOneQ; lessThanOneQ@x_ := If[ x < 1, True, False]

Select[Range[-0.2, 1.1, 0.2], lessThanOneQ]

{-0.2, 0., 0.2, 0.4, 0.6, 0.8}

Select[Range[-0.2, 1.1, 0.2], # < 1 &]

{-0.2, 0., 0.2, 0.4, 0.6, 0.8}

Function[x, x < 1] /@ Range[-0.2, 1.1, 0.2]

{True, True, True, True, True, True, False}

Cases[Range[-0.2, 1.1, 0.2], x_Real /; x < 1]

{-0.2, 0., 0.2, 0.4, 0.6, 0.8}

lessThanOnePositiveQ@x_ :=
 If[0 < x < 1 , True, False](* version restricted to positive numbers *)

lessThanOnePositiveQv2@x_ :=
 If[x < 1 && Positive@x, True, False] (* alternate version *)

Select[Range[-0.2, 1.1, 0.2], lessThanOnePositiveQ]

{0.2, 0.4, 0.6, 0.8}

Select[Range[-0.2, 1.1, 0.2], lessThanOnePositiveQv2]

{0.2, 0.4, 0.6, 0.8}

Predicate Using a Piecewise Function

Note the usage in the Named Pattern variable of a NumberQ predicate to allow both Reals and Integers. This example is intended to illustrate that a Piecewise-defined Predicate can include an unlimited number of orthogonal conditions.

Clear@pieceWiseElementQ; pieceWiseElementQ@number_?NumberQ :=
 Piecewise[{{False, number < -3}, { True, -3 < number < 0}, {False,
    0 <= number <= 6}, {True, number > 6}, {True, number === 4.5}}]

pieceWiseElementQ /@ {-3.00001, -0.0000000001, -4/5, 0, 0.000000001, 4/5, 4.5,
   6, 6.01, 9}

{False, True, True, False, False, False, False, False, True, True}