Re: Can one define own indexing function/mapping to be
- To: mathgroup at smc.vnet.net
- Subject: [mg113355] Re: Can one define own indexing function/mapping to be
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Mon, 25 Oct 2010 06:39:59 -0400 (EDT)
Nasser, You can certainly implement your own type with the behavior you want. If you insist on overloading Part, here is one possible implementation: Module[{getId}, getId[x_array]:=First@x; array/:array.new[content_List]:= With[{id = Unique[],cont = Unique[]}, id[]:=cont; cont=content; array[id]]; array/:x_array.delete[]:= With[{id = getId[x]}, Remove@@Append[Hold[id[]]/.DownValues[id],id] ]; array/:Part[x_array,i_Integer]:=getId[x][][[i+1]]; Unprotect[Part]; Part/:Set[Part[x_,i_Integer],rhs_]/;Head[x]===array:= With[{id = getId[x]}, Unevaluated[id[][[i+1]]=rhs]/.DownValues[id]]; Protect[Part]; array/:Length[x_array]:=Length[getId[x][]]; ] This will work for both getting and setting parts: Create new array from list of values arr = array.new[{1,2,3}] Ask for the first element arr[[0]] Set first element arr[[0]]=4 Display all elements: Table[arr[[i]],{i,0,Length[arr]-1}] This implementation has problems however, the major one being that we had to modify Part by adding UpValues to it. This can not be avoided in this approach (at least as far as I can see) since the <array> tag is too deep to attach an UpValue to it for Set[Part[x_array,...],...]. This is pretty bad since Part is a very common command, and doing this is both dangerous and costly. So, I provided this implementation just to illustrate how this can be done, definitely not for production. You will be better off implementing your own get and set methods and using them instead. The following modification is much safer (make sure you start this with a fresh kernel so Part has no residual definitions): ClearAll[array]; Module[{getId}, getId[x_array]:=First@x; array/:array.new[content_List]:= With[{id = Unique[],cont = Unique[]}, id[]:=cont; cont=content; array[id]]; array/:x_array.delete[]:= With[{id = getId[x]}, Remove@@Append[Hold[id[]]/.DownValues[id],id] ]; array/:x_array.get[i_Integer]:=getId[x][][[i+1]]; array/:x_array.set[i_Integer,val_]:= With[{id = getId[x]}, Unevaluated[id[][[i+1]]=val]/.DownValues[id]]; array/:Length[x_array]:=Length[getId[x][]]; ] Here is how you use it: arr = array.new[{1,2,3}] arr.get[0] arr.set[0,4] Table[arr.get[i],{i,0,Length[arr]-1}] arr.delete[] As usual in this OO-like style in Mathematica, you have to do manual "memory management" by calling delete[] after the instance is no longer needed, or you will get memory leaks. You also must be careful not to use the instances which has been deleted but may still be referenced somewhere in your program, say kept in a list. Finally, operations on such arrays will be necessarily slower than on lists say. And you will not be able to compile the code using these structures, with Compile. This is a price to pay for this particular form of stateful programming in Mathematica. Regarding Array: you should realize that Array is just a built-in function to produce lists of applied function values, and not some kind of "type". There is no Array type in Mathematica. Hope this helps. Regards, Leonid On Sun, Oct 24, 2010 at 6:05 AM, Nasser M. Abbasi <nma at 12000.org> wrote: > > I am trying to implement something where it is more natural to use an > index that starts at 0 instead of the default 1 for vectors and matrices > as since this will match the problem I am looking at. > > If I write > > u={0,1,2} > u[[0]] > > This will return the Head of u. So have to write u[[1]] to get the first > entry. I'd like to write u[[0]] to get the first entry. > > I thought about using Array: > > In[8]:= u = Array[U[#1] & , 4, 0] > Out[8]= {U[0], U[1], U[2], U[3]} > > But this does not do much, I still have to write u[[1]] to access U[0] > > I could write my own function to implement a 'get' and 'set' operations > as in: > > In[4]:= get[u_, i_] := u[[i + 1]] > > In[5]:= get[u, 0] > Out[5]= U[0] > > So, everywhere in the code, where I would have liked to write u[[i]], I > will replace that by get[u,i], and now my i's will match the textbook > i's since those are implemented using 0-index arrays. > > In an OO setting, I could have defined my own "[[ ]]" function on object > of type Array, then I can write more u[[i]], where now u's own function > "[[ ]]" will be used. > > Other languages also allow one to define an array with different > starting index than the default. > > Is there a way to do something like this for Array at least. For general > Lists, I think that might not be possible? It will break everything I > would imagine. > > I am looking at this report: > > http://library.wolfram.com/conferences/devconf99/lichtblau/ > > "Data Structures and Efficient Algorithms in Mathematica", > > But thought to also ask here, to see if there might be a simple trick to > do this for Array, by unprotecting it, and changing something? and then > protecting the definition again, before I try to implement a data struct > with the help of the above article to do what I want. > > thanks > --Nasser > >