Re: prograMing: EquivalenceIndex
- To: mathgroup@smc.vnet.net
- Subject: [mg11190] Re: prograMing: EquivalenceIndex
- From: Clemens Frey <Clemens.Frey@uni-bayreuth.de>
- Date: Mon, 2 Mar 1998 23:10:47 -0500
- Organization: uni-bayreuth.de
- References: <6ctbf1$l5a@smc.vnet.net>
Xah wrote: > > Another fun programing problem. In this problem, I'd be very interested > if someone can come up with a solution that is either purely > functional, or faster. > > Problem: > Write the function EquivalenceIndex. It's usage message is given below. > Hi Xah, so this is my answer... I didnt have enough spare time to recreate on your previous prograMing problems, but now I tried to recode your EquivalenceIndex function. First I made up the following short and fully functional version: Remove[theSameAs,EquivalenceIndexCF1]; theSameAs[y_,li_] := Position[SameQ[#,z/.z->y]& /@ li,True]//Flatten; (*1*) EquivalenceIndexCF1[li_] := theSameAs[#,li]& /@ li //Union; (*2*) The definition on line 1 programs a function that gives you the indexes of all the elements of li_ which are equivalent to y_. You may wonder about the "z/.z->y" thing, but writing just "y" instead doesnt work (why?). Line 2 automatically applies the function of line 1 to all the members of li_. Equal element of the resulting list are deleted ("//Union"). The main drawback of this is that elements of li_ which are already known to be in a equivalent class are tested again. (They are a l l tested !). So I coded a mixture of functional and loop programming: Remove[EquivalenceIndexCF2]; EquivalenceIndexCF2[li_, sameTestQ_:SameQ]:= Module[ { idx={}, l = Transpose@{li,Range@Length@li}, (*3*) elem, theSameAsElemIndexes }, While[ l != {}, elem = First@First@l; (*4*) theSameAsElemIndexes = Flatten @ Position[sameTestQ[elem,First@#]& /@ l, True]; (*5*) AppendTo[ idx, Part[l, theSameAsElemIndexes] /. {__,x_Integer}->x (*6*) ]; l = Part[l, Complement[Range@Length@l, theSameAsElemIndexes] ]; (*7*) ]; idx ]; Here li_ is eventually cut down. First the elements of li_ are supplied with their positions in li_ (see line 3), e.g. f[x] in position 1 ist getting {f[x],1}. Then in each step of the "While"-loop the equivalence class of the first element of the first elem/pos-group (in our example: f[x]) is computed: First you get their elements' positions in the (after previous steps, like in line 1) remaining l-List (line 5), then the indexes of these elements in respect to the original li_ are extracted (line 6). The equivalence class is subtracted from l (line 7). We compare the four versions: (on a Pentium 150 running OS/2, Mathematica 2.2.1 under Warp-Windows 3.11) li=Table[Random[Integer,{1,6}],{200},{3}]; timeList = { Timing@EquivalenceIndexXah1[li], Timing@EquivalenceIndexXah2[li], Timing@EquivalenceIndexCF1[li], Timing@EquivalenceIndexCF2[li] }; We get times that show that the CF2-Version is fastest: First/@timeList {2. Second, 4.12 Second, 3.72 Second, 1.38 Second} where the results (after Mathematica-ordering via Union) are equal: Equal@@Union/@(Part[#,2]& /@ timeList) True regards Clemens