How do I "clear" an array?

resolvent's picture

I need to do the following. Suppose I have an array, c[ ]. I need to be able to specialize the elements of this array, and then later "clear" the elements, making them indeterminates again. I attempted to do this by creating a temporary holding array

i:='i': for i from 1 to 5 do d[i]:=c[i] end do;
i:='i': for i from 1 to 5 do c[i]:=i end do;
i:='i': for i from 1 to 5 do c[i]:=d[i] end do;
 

I expected and want the output to be

c[0] c[1] c[2] c[3] c[4] c[5] 1 2 3 4 5 c[0] c[1] c[2] c[3] c[4] c[5]

Instead, my output is

c[0] c[1] c[2] c[3] c[4] c[5] 1 2 3 4 5 1 2 3 4 5

in other words, the c[ ] remain specialized. Any suggestions how to do this?

Comments

evaln

Note that you do not need to clear variables used as loop counters, at least not for the loop.

I think the following does what you want.

A := array(1..3, [a,b,c]):
for i to 2 do A[i] := evaln(A[i]); end do:
print(A);

                           [A[1], A[2], c]
 

resolvent's picture

Need to clear loop counters

One does indeed need to clear variables used as loop counters. I have experimented with that and proven that is necessary many times.
 

Thank you for the evaln function. I will try it.

There is no way I would have been able to look in the Help menu for the "evaln" function unless I already knew that it was able to clear array elements.

please give a counter-example

Please show an example where a loop counter must be cleared.  Here is what I was referring:

i := 23:
for i to 3 do i end do;
                                  1
                                  2
                                  3
 

By "loop counter" I mean the 'for' variable (i, above).  At the exit of the loop i is assigned 4, but its value prior to entering the loop has no effect on the loop counter (unless that value is used in the 'from' or 'to' fields).

FYI I have requested (submitted a bug report) for evaln to be explicitly mentioned in the table help page. Currently there is a link to it there, in the See Also section, however, that does not suffice. Note that arrays (no capital) are deprecated, so do not expect to see that help page, array(deprecated), modified in the future.

resolvent's picture

"Resetting" a counter loop

# Desired output 1, 2, 3 s[i]
# Actual output: 1, 2, 3, s[4]

for i fro 1 to 3 do i end do;
s[i];

I have had more complicated examples than this,
such as when the counter loop is used again as a counter loop
in which I have had to "reset" the "i". I can't dig those up now.
(They're too long to type in.)

edgar's picture

"Resetting" a counter loop

My errors tend to look like this...

for i from 1 to 5 do i; od;
1
2
3
4
5
sum(2,i=1..5);
Error, (in sum) summation variable previously assigned, second argument evaluates to 6 = 1 .. 5
sum(2,'i'=1..5);
10
---
G A Edgar

after, not before

Yes, however, reassigning the for-loop counter before the for-loop does not help here, which was my point.  If you need to reassign the variable after the loop, then do so.  Of course, in the simple example above you would be better served with the add procedure, which does not require resetting the variable, in place of the sum, which does.

 

local counter

Yes, ?add states:

Note also that the index variable i is private to the add or mul invocation. Any local or global variable of the same name visible at the time when the add or mul is executed will not be affected by it.

But why the for-loop cannot be changed to use a local index also? It would be better to adapt the software to the way the users think than adapt the users to think the way the developers did it.

we don't think alike

While it could be done, it would break a lot of code.  It is frequently useful to know the last counter value after exiting from a loop.  Consider, for example

  for i while f(i) < 0 do end do;

When (and if) the loop exits, the value of i is the value that caused the exit. If i were local to the loop, then we would have to do

  cnt := 1: for i while f(i) < 0 do cnt := i; end do; 

or something similar.

An interesting alternative would be to have a finally clause for a loop.  Then one could do

  for i while f(i) < 0 do finally cnt := i; end do;
resolvent's picture

Thank you, Edgar!

THANK you for recreating the error message that I get all the time.
The "evaluates to 6=1..5" thing.

add/sum

If you get this a lot, it might be because you are using sum where you should/could be using add

you have a table, not an array

Your initial construction of c produces a table, not an array.

for i from 1 to 5 do c[i]:=i end do;

type(c,table);
true

type(c,array);
false

Thus you can clear c by simply assigning it to be the null table:

c:=table([ ]);

There is no need for your "holding array" d.

 

resolvent's picture

Thanks to all for your help: next problem...

My next problem is to COLLECT all the like powers of c[0,j,0,l] and c[i,0,k,0]. Actually, there are no powers. My output (all it R) is a LINEAR combination of assorted TABLE elements c[0,j,0,l] and c[i,0,k,0] for i,j,k,l in the range 1 through 5. 5 is about the largest range I can choose before my computer completely hangs up. It has to set up storage space for 5^4 c[i,0,k,0]'s and c[0,j,0,l]'s.
R = Linear combinations of these c[ ] elements over polynomials in indeterminate table elements d[] and e[] and rational in d[0].
For example, I now need to turn R:= (1/d[0])*(c[0,1,0,2] - c[3,0,4,0]) + (5*c[0,1,0,2] - e[1]*c[3,0,4,0]) into (1/d[0] + 5)*c[0,1,0,2] + (-1/d[0] - e[1])*c[3,0,4,0].
 

like this?

R :=(1/d[0])*(c[0,1,0,2] - c[3,0,4,0]) + (5*c[0,1,0,2] - e[1]*c[3,0,4,0]):
vars := indets(R, 'specindex(nonnegint,c)');
                    vars := {c[0, 1, 0, 2], c[3, 0, 4, 0]}

collect(R, vars);
           / 1      \                 /   1         \
           |---- + 5| c[0, 1, 0, 2] + |- ---- - e[1]| c[3, 0, 4, 0]
           \d[0]    /                 \  d[0]       /
resolvent's picture

Exactly! And now..

Exactly, Joe Riel! Thank you!
And now, one more level of complication: I need to make the vars list itself be of indefinite lengths.  Plus, I have a lot of R's to compute, so I'll have to put your code into its own loop.  More specifically, I am computing c[i,j,k,l] for all i,j,k,l in terms of (using my recursion, as linear combinations of) just those of the form c[0,j',0,l'] and c[i',0,k',0] where i',j',k',l' run from 0 to about 2*i,2*j,k,l. Hence, the number of variables c[i',0,k',0] and c[0,j',0,l'] needed increases with i,j,k,l.  I need to compute a sufficient number of c[i,j,k,l], as I mentioned earlier, about 0<=i,j,k,l<=5, to visualize the pattern and hopefully guess a general formula.

I don't quite understand

I don't quite understand what you want.  In the code I gave, vars is computed from R.  In what sense must it be of indefinite length? 

Is the following of use (not directly, but maybe it will give you a clue as to how to do what you really want, efficiently)?

AllVars := proc(i,j,k,l)
local ii,jj,kk,ll;
global c;
    {NULL
     , seq(seq(c[0,jj,0,ll], jj=0..j+1), ll=0..l)
     , seq(seq(c[ii,0,kk,0], ii=0..i+1), kk=0..k)
    };
end proc:

Presumably you have some way of combining them to generate the linear combinations...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
}