EUREKA Re: Types in Mathematica, a practical example
- To: mathgroup at smc.vnet.net
- Subject: [mg63184] EUREKA Re: [mg62800] Types in Mathematica, a practical example
- From: "Ingolf Dahl" <ingolf.dahl at telia.com>
- Date: Sat, 17 Dec 2005 03:46:16 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
EUREKA! I have found a (for me) new and alternative way to define matrices and list structures, which allows me to define the elements afterwards, and leave some elements undefined. From the Book, 2.5.5: "You can define a list, say a = {x, y, z, ... }, then access its elements using a[[i]], or modify them using a[[i]] = value. This approach has a drawback, however, in that it requires you to fill in all the elements when you first create the list. Often, it is more convenient to set up arrays in which you can fill in only those elements that you need at a particular time. You can do this by making definitions for expressions such as a[i] ...." When I read section 2.5.5, I get the impression that the definition of "Part" in Mathematica is an unfinished issue. An indexed element could have many of the properties that symbols have, but that is not fully implemented. Since we cannot have undefined array elements, array elements cannot be handled symbolically as ordinary variables. Various ways to get around this problem have been suggested: To substitute undefined array elements with zero or some fixed word, or to substitute the array elements with other variables, as is done in section 2.5.5 in the Book. The functionality we obtain by defining an array by g=Array[f,{n1,n2}] could be built into Mathematica in a hidden way, in such a way that g[[1,2]] behaved as f[1,2] in expressions. But it is not so now. None of these methods gives the effect that g[[1,2]] is returned unevaluated if it is undefined, as is done with an undefined variable g. My suggestion to define a 2x2 list of undefined elements is the following: x = {{HoldForm[x[[1,1]]], HoldForm[x[[1,2]]]}, {HoldForm[x[[2,1]]], HoldForm[x[[2,2]]]}}; Then it is possible to use x[[1]] as an usual unset symbol in expressions and assignments: With a = {HoldForm[a[[1]]], HoldForm[a[[2]]]}; b = {HoldForm[b[[1]]], HoldForm[b[[2]]]}; the dot product a.b evaluates to a[[1]] b[[1]] + a[[2]] b[[2]] with an invisible HoldForm around each factor. (If you want to keep everything visible, use Hold instead of HoldForm.) With the assignment a[[1]] = 5; b[[2]]=4; we give a[[1]] and b[[2]] values as usual, and the dot product evaluates to 4 a[[2]] + 5 b[[1]] The big benefit of this approach compared to the Array way suggested in 2.5.5 is that we can use the same name for the whole matrix and its parts. If we use the Array way, we might set a = Array[b,{3}], and must keep a connection between a and b in all assignments and deassignments. If we do any assignment directly to a[[2]], we loose its connection to b. If I want to write a function that should change the value of a, I must know the name b and know or check if there is a full connection between a and b. Occasionally, when you have defined some of the undefined elements, you may convert to Input Form or have to apply ReleaseHold or ReplaceAll[#,HoldForm[Part[a__]]:>Part[a]]& @ to get rid of the invisible HoldForm surrounding the indexed elements. For Set and SetDelayed you can get this automatically by the command Unprotect[HoldForm]; HoldForm /: Set[ HoldForm[ Part[a__]],b_]:= Set[ Part[a],b]; HoldForm /: SetDelayed[ HoldForm[ Part[a__]],b_]:= SetDelayed[ Part[a],b]; Protect[HoldForm]; We might define a function HoldArray, with the same arguments as Array, to help us create arrays with undefined elements: SetAttributes[HoldArray, HoldFirst]; HoldArray[f_, n__] := Module[{g}, Array[g, n] /. {g[a___] :> HoldForm[f[[a]]]}] For the built-in function Array, it is not allowed to do the following: (* NOT ALLOWED: x = Array[ x, {2, 2}] *) but for HoldArray you should normally do exactly that way: x=HoldArray[x,{2,2}] My initial problem with a = {{1, 2}, {3, 4}}; x - a /. {x -> a} can be solved by a = {{1, 2}, {3, 4}}; x = HoldArray[x, {2, 2}]; x - a /. {HoldForm[x[[i__]]] :> a[[i]]} but other methods have also been suggested. ___________________________________________________________ When I played with this, I came across the following: Assume, that the value of axxx is not defined. Then Hold[Part[axxx, 57, 62]] /. {axxx -> b} returns Hold[b[[57,62]]] but if we first assign any value to axxx, e.g. Indeterminate, we instead obtain Hold[axxx[[57,62]]] Can someone explain? _________________________________________________________________ We do not have to wait for Wolfram to accept my suggestion about introduction of the word Undefined in their next release. We can introduce it by the following definitions, at the expense of slowing down Mathematica somewhat: Undefined/: ( (a_)[ [i__]]=Undefined):= a[ [i]]= HoldForm[ a[ [i]]]; Undefined/: ( (a_)[ [i__]]:=Undefined):= a[ [i]]:= HoldForm[ a[ [i]]]; Undefined/: ( x_Symbol=Undefined):= x=.; Undefined/: ( x_Symbol:=Undefined):= x=.; Undefined/: ( x_/; Not[ MemberQ[ { Part,HoldForm}, Head[x]]]=Undefined):= x=.; Undefined/: ( x_/; Not[ MemberQ[ { Part,HoldForm}, Head[x]]]:=Undefined):= x=.; Unprotect[Set]; Set[ a_Symbol, b_/; MemberQ[ b,Undefined, { 1,Infinity}]]:= Set[ a, FixedPoint[ Function[ b1, ReplacePart[ #1, HoldForm@ Part[ a,##2], Flatten[ Position[ #1,Undefined, { 0,\[Infinity]},1]]]&[ b1, Evaluate[ Sequence@@ Flatten[ Position[ b1,Undefined, { 0,\[Infinity]},1]]]]],b]]; Protect[Set]; (Please report any bugs to me!) Then we might use this word in those positions where we want an undefined element to appear, along my suggestion in an earlier message to MathGroup. Then we might represent a triangle, with one side of length 3 and with two angles defined, in the following way: t = triangle[{3, Undefined, Undefined}, {Undefined, Pi/4, Pi/3}] We might then define a function AngleSumTheorem: AngleSumTheorem[a_triangle] := a[[2,1]] + a[[2,2]] + a[[2,3]] == Pi and solve for the unknown angle: t[[2,1]] = t[[2,1]] /. Solve[AngleSumTheorem[t], {t[[2,1]]}][[1]] The new value of t will then be (in Input Form) triangle[{3, HoldForm[t[[1,2]]], HoldForm[t[[1,3]]]}, {(5*Pi)/12, Pi/4, Pi/3}] Some comments for those who have persevered to follow the Sisyphean discussion in this thread: Lo and Behold! In my Eye, with me as Beholder, I have in Idle Curiosity left the Right Mathematica Way and become cognizant of an Alternative very Suitable Mathematica Way, which from my View Point reaches the Goal with great Efficaciousness and Elegance and Illustrates the Beauty and Power of Mathematica. :-) And I wish everybody A Merry Christmas and A Happy New Year! Ingolf Dahl Sweden PS. If I make a package of this, it will appear at http://web.telia.com/~u31815170/Mathematica/