MathGroup Archive 2005

[Date Index] [Thread Index] [Author Index]

Search the Archive

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/



  • Prev by Date: Re: How to cope with tiny numbers in FindRoot
  • Next by Date: Re: Multiple integration of UnitStep fails
  • Previous by thread: Re: EUREKA Re: Types in Mathematica, a practical example
  • Next by thread: Re: EUREKA Re: Types in Mathematica, a practical example