Sunday, December 20, 2015

Apply a List of Functions to a Corresponding List of Arguments

Here are two ways to apply a List of functions to a List of arguments. The first method, from Maeder, uses Inner. Note the use of a purely symbolic example to reveal what Inner is doing.

Inner[#@#2&,{f1,f2,f3,f4},{arg1,arg2,arg3,arg4},List]

{f1[arg1],f2[arg2],f3[arg3],f4[arg4]}

In #1@# &, Slot1 (#1 or abbreviated #) pulls an argument from the first List, which are the functions, and Slot2 (#2 where you do need the "2") pulls an argument from the second List, which are the arguments.

If you wanted to apply a second function, g, to the results rather than just listing them, Inner provides for that:

Inner[#@#2&,{f1,f2,f3,f4},{arg1,arg2,arg3,arg4},g]

g[f1[arg1],f2[arg2],f3[arg3],f4[arg4]]

The second method, from my Mathematica teacher Harry Calkins, uses MapThread, which requires wrapping the function List and the argument List together in a List:

(arguments={{a,b,c},{d,e,f},{r,s,t},{u,v,w}});

(functions={3 #&,3+#&,#/2&,Plus@@@Partition[#,2,1,{1,1},#]&});

He gave an example using some built-in functions and structured the functions and arguments in matrices.By enclosing the assignments in parentheses he showed them as matrices without inadvertently making the assignment to the MatrixForm-formatted List.

arguments//MatrixForm
functions//MatrixForm

(results=MapThread[#1@#2&,{functions,arguments}])//MatrixForm


Friday, December 11, 2015

String Processing: Validate Email Address Format, Part 1

Here are three approaches to predicates validating that an email address has an "@" sign and a period ".". A true email address validator is much more complicated, so these functions are merely to illustrate some String processing techniques. That said, I did use the first approach to validate thousands of email addresses and flush out bad ones.

The first predicate uses StringMatchQ and the essential idea is to give StringMatchQ a String pattern representing:
  1. An "@" wildcard for at least one but an unknown number of characters
  2. Followed by the "@" sign as used in an email address to separate localpart from domain
  3. Followed by the wildcard again
  4. Followed by the period "." used to separate the mail server name from the top-level domain
  5. Followed by the wildcard
Note that an asterisk wildcard ("*") would not be suitable since each position in the pattern has at least one character.

The first variation illustrates the use of Verbatim, which tells Mathematica to treat the middle "@" sign as an "@" sign  (read it "verbatim") and not as a pattern wildcard.

Clear@emailAddressQ1;emailAddressQ1@aString_String:=StringMatchQ[aString,"@"~~Verbatim@"@"~~"@.@"]

The second variation of StringMatchQ does the same thing but more concisely, using a double backslash. The first backslash tells Mathematica to treat the second one as an 'escape' character, which then tell Mathematica to treat the "@" sign as an "@" sign and not as a wildcard.

Clear@emailAddressQ1a;emailAddressQ1a@aString_String:=StringMatchQ[aString,"*\\@*.*"]

The second basic approach uses StringContainsQ to detect the presence of the "@" sign and period "." in the address. Since it doesn't require additional characters in the correct positions as does the first approach, it is not as good a validator.

Clear@emailAddressQ2;emailAddressQ2@aString_String:=StringContainsQ[aString,"@"]&&StringContainsQ[aString,"."]

The third approach uses StringFreeQ to see if the address has no "@" sign and period ".", and some logic, and suffers the same limitation as the second approach.

Clear@emailAddressQ3;emailAddressQ3@aString_String:=Not[StringFreeQ[aString,"@"]&&StringFreeQ[aString,"."]]

Test Cases


The test cases are 1) valid email format, 2) missing "@" sign, 3) missing "." and 4) missing both "@" and ".".

testCases={"abc@dwxy.anything","abcdwxy.anything","abc@dwxyanything","abcdwxyanything"};

emailAddressQ1/@testCases

{True,False,False,False}

emailAddressQ1a/@testCases

{True,False,False,False}

emailAddressQ2/@testCases

{True,False,False,False}

emailAddressQ3/@testCases

{True,True,True,False}

Aha! The test cases flushed out a logic error. The way the emailAddressQ3 function is written with the AND (&&) conjunction between the two clauses, only if both StringMatchQ tests are FALSE will AND return FALSE and be negated by NOT into TRUE. We need to change the AND to OR so that if either "@" or "." are missing, the OR returns TRUE and is negated by NOT into FALSE.

Clear@emailAddressQ4;emailAddressQ4@aString_String:=Not[StringFreeQ[aString,"@"]||StringFreeQ[aString,"."]]

emailAddressQ4/@testCases

{True,False,False,False}

Thursday, December 3, 2015

Grid - Partition - Identify Primes with Formatting

Starting with an example from Mangano, Mathematica Cookbook, and the Doc Center, here are examples of using Partition with Grid and formatting to highlight the values of interest.

Grid@Partition[If[PrimeQ@#,Framed[#,FrameStyle->Red],#]&/@Range@200,20]



Grid@Partition[If[PrimeQ@#,Style[#,FontColor->Red],#]&/@Range@200,20]



Grid@Partition[If[PrimeQ@#,Style[#,FontColor->Red,FontWeight->Bold],Style[#,FontColor->Gray]]&/@Range@200,20]



This sets up a clickable square from which you can interactively choose a color.

Clear@highlightColor;ColorSetter@Dynamic@highlightColor

Then the selected color is used here:

Grid@Partition[If[PrimeQ@#,Style[#,FontColor->highlightColor,FontSize->16,FontWeight->Bold],Style[#,FontColor->Gray]]&/@Range@200,20]


Grid@Partition[If[!PrimeQ@#,Style[#,FontColor->White],#]&/@Range@200,20]


Change the Partition from 20 to 10 to accommodate larger numbers.

Grid@Partition[If[!PrimeQ@#,Style[#,FontColor->White],#]&/@Range[500000,500200],10]



Run Wolfram BenchmarkReport to Test Your Computer's Peformance

This is kind of neat. The report will compare your computer to a garden variety of others based on some benchmark tests. Your computer's results will be highlighted in blue. Interestingly I found that our more expensive and supposedly fastest computer ranked 7th compared to our standard desktops, which ranked 4th.

The actual tests and code for them are very interesting — see the bottom of the report.

?BenchmarkReport[]

BenchmarkReport[] runs the WolframMark benchmark and produces a report in a separate notebook comparing this system to a selection of reference systems.

BenchmarkReport[system1,system2, ..., data1,data2,...] produces a custom report comparing the specified systems from $BenchmarkSystems and the specified data returned from Benchmark. >>

Needs@"Benchmarking`";
BenchmarkReport[]


WolframMark Benchmark Report


Machine Name: w1bzzg6df934
System: Microsoft Windows (64-bit)
Date: December 3, 2015
Mathematica Version: 10.2.0
Benchmark Result: 1.33


WolframMark Results




WolframMark Sources

Test 1: Data Fitting


Module[{data},AbsoluteTiming[data=Flatten[Table[{x,y,z,Log[120 x]-Abs[Cos[z/300]/(140 y)]},{x,0.2`,10,0.22`},{y,0.2`,10,0.22`},{z,0.2`,10,0.22`}],2];FindFit[data,Log[a x]-Abs[Cos[b z]/(c y)],{a,b,c},{x,y,z},AccuracyGoal->6];]]

Test 2: Digits of Pi


AbsoluteTiming[N[\[Pi],1000000];]

Test 3: Discrete Fourier Transform


Module[{data},AbsoluteTiming[SeedRandom[1];data=RandomReal[{},{1200000}];Do[Fourier[data],{11}]]]

Test 4: Eigenvalues of a Matrix


Module[{a,b,m},AbsoluteTiming[SeedRandom[1];a=RandomReal[{},{420,420}];b=DiagonalMatrix[RandomReal[{},{420}]];m=a.b.Inverse[a];Do[Eigenvalues[m],{6}]]]

Test 5: Elementary Functions


Module[{m1,m2},AbsoluteTiming[SeedRandom[1];m1=RandomReal[{},{2.2`*^6}];m2=RandomReal[{},{2.2`*^6}];Do[Exp[m1];Sin[m1];ArcTan[m1,m2],{30}]]]

Test 6: Gamma Function


Module[{a},AbsoluteTiming[SeedRandom[1];a=RandomInteger[{80000,90000},{55}];Gamma[a]]]

Test 7: Large Integer Multiplication


Module[{a},AbsoluteTiming[SeedRandom[1];a=RandomInteger[{10^1100000,10^(1100000+1)},{}];Do[a (a+1),{20}]]]

Test 8: Matrix Arithmetic


Module[{m},AbsoluteTiming[SeedRandom[1];m=RandomReal[{},{840,840}];Do[(1.` +0.5` m)^127,{50}];]]

Test 9: Matrix Multiplication


Module[{m1,m2},AbsoluteTiming[SeedRandom[1];m1=RandomReal[{},{1050,1050}];m2=RandomReal[{},{1050,1050}];Do[m1.m2,{12}]]]

Test 10: Matrix Transpose


Module[{m},AbsoluteTiming[SeedRandom[1];m=RandomReal[{},{2070,2070}];Do[Transpose[m],{40}]]]

Test 11: Numerical Integration


AbsoluteTiming[NIntegrate[Sin[x^2+y^2],{x,-(2.6` \[Pi]),2.6` \[Pi]},{y,-(2.6` \[Pi]),2.6` \[Pi]}];]

Test 12: Polynomial Expansion


AbsoluteTiming[Expand[Times@@Table[(c+x)^3,{c,350}]];]

Test 13: Random Number Sort


Module[{a},AbsoluteTiming[SeedRandom[1];a=RandomInteger[{1,50000},{520000}];Do[Sort[a],{15}]]]

Test 14: Singular Value Decomposition


Module[{m},AbsoluteTiming[SeedRandom[1];m=RandomReal[{},{860,860}];Do[SingularValueDecomposition[m],{2}]]]

Test 15: Solving a Linear System


Module[{m,v},AbsoluteTiming[SeedRandom[1];m=RandomReal[{},{1150,1150}];v=RandomReal[{},{1150}];Do[LinearSolve[m,v],{16}]]]

Wednesday, December 2, 2015

The Basics of Slot (#) in Pure Functions

Pure Function, as it's called, such as Function[x, x^2] that yields x2 or the beautiful shorthand, #^2&, is extremely useful in Mathematica:
  1. For one-time functions
  2. As an argument in many functional-style commands such as Map, Nest, Fold, Select, Count, etc
  3. In the extended Postfix style of programming I developed to eliminate hard-to-read nested functions
  4. In predicates including those used for argument type-checking: _?(# <= 1 &)
  5. In the general pattern-matching predicate MatchQ
  6. And the new use in Associations in version 10

Slot must be used with the pure Function operator &. They are designed to be the Head of a function:

#1&[a,b,c]

a

When you use the Postfix style just remember that Postfix causes the ampersand abbreviation for Function to wrap around an entire expression preceding it. Thus it has a low precedence of 90; here are its neighbors:

Precedence/@{Set,Postfix,Colon,Function,TimesBy,Rule}

{40.,70.,80.,90.,100.,120.}

It can be confusing if there are nested used of Function, but using that principle, you can figure it out.

Important: What trips up beginners is using Slot with Mathematica's universal container, List. This doesn't work:

#1&{a,b,c}

{a (#1&),b (#1&),c (#1&)}

There are several solutions. Using Apply (@@) will return a Sequence:

args=##&@@{a,b,c,d}

Sequence[a,b,c,d]

A Sequence is a list designed to be fed to any function:

func@args

func[a,b,c,d]

You can wrap SlotSequence in List so it returns a List:

{##}&[a,b,c,d]

{a,b,c,d}

Here are typical uses with Function as the Head or using Apply. Note that you cannot use negative position numbers with Slot or SlotSequence since that would conflict with using Subtract in pure Functions (like #-2&).

"First" (the default position argument for Slot is 1 so you don't need to specify it with "#1")

#&@@{a,b,c}

a

Return the first two arguments:

{#,#2}&@@{1,2,3,4}

{1,2}

Return all arguments:  ## is SlotSequence, which returns a Sequence, which is designed to be given to any function as its argument list.

##&[a,b,c,d]

Sequence[a, b, c, d]

{##}&[a,b,c,d]

{a, b, c, d}

##&@@@[a,b,c,d]

{a, b, c, d}

Return the first and fourth arguments:

{#,#4}&@@{1,2,3,4}

{1,4}

"Rest": Return the 2nd argument to the last:

{##2}&[a,b,c,d]


Sequence[b,c,d]

As of version 10, there is an interesting new usage for Slot with Associations. Slot suffixed with any Key (name) of an Association will automatically return the Value associated with the Key.

cityPopulationAssociation=Association["Tokyo"->"37 million","Jakarta"->"26 million","Seoul"->"17 million","Delhi"->"22 million","Shanghai"->"21 million"];

#Delhi&@cityPopulationAssociation

22 million