MathGroup Archive 2010

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

Search the Archive

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
>
>


  • Prev by Date: Re: Suggestions for improving speed
  • Next by Date: how to read Wolfram technology conference 2010 presentations?
  • Previous by thread: Re: How to combine Mathematica graphics and Python code?
  • Next by thread: how to read Wolfram technology conference 2010 presentations?