Joe Riel

9660 Reputation

23 Badges

20 years, 3 days

MaplePrimes Activity


These are answers submitted by Joe Riel

A problem with your approach is that builds a set by continually appending to it one element at a time; with Maple that is O(n^2) in time and memory.  One way to avoid that is to insert each orbit in a table, as an index, then at the end of the procedure count the number of distinct indices:

   orbits := table();
   ...
   orbits[orbit] := 0;
   ...
   return numelems([indices(orbits,'nolist')]);

With that trivial change the procedure returns the correct result in 12 seconds.

Somewhat surprisingly, the calls to convert(.,base,.) are using much of the remaining time. The computation of d2 should be moved out of the inner loop, no need to recompute it each time. The computation of d3 can be be saved and reused by assigning

base3 := proc(ix)
option remember;
    convert(ix,'base',3);
end proc:

and then using that in the procedure. With that the run time is down to 3 seconds.

The computation of interl can be done in a seq, as can the first computation of orbit. The second computation is trickier to do with a seq.

Consider the generalization of this,

sum(k*i+m,i=1..n)=N;

for k and N fixed and positive. Solving for m gives

m = N/n - (n+1)*k/2

which is monotonic decreasing with n. So if N is odd, the number of unique solutions equals the number of positive divisors of N. In this case, 3375 = 3^3*5^3, so number of divisors is (3+1)*(3+1) = 16.

 isolve(sum(2*(m+i-1)+1,i=1..n) = 3375);

To keep only the solutions with positive n, do

sols := [isolve(sum(2*(m+i-1)+1,i=1..n) = 3375)]:
select(hastype, sols, identical(n) = posint);

The circuit doesn't  make sense.  The 10V source should have its negative side grounded and the positive side connected to the top of both R1 and R3.

If you're serious, you should consider using the emacs maple debugger, available at my github site. The drawback of that is that if you aren't familar with emacs the learning curve will be steep.  The advantage is that with that it is probably quite easy to do what you want.  I would display the stack, which shows up in a buffer with each procedure call on the stack, click on the procedure of interest, which is then displayed in another buffer, set a breakpoint where desired, then click on the call to that procedure, which reexecutes it and stops the debugger at the breakpoint. That isn't guaranteed to work but usually does.  

The problem is that block is a list and the statement

  block[3] := 23;

for example, is assigning directly into the list. Well, that's what appears to happen. In Maple, a list is an immutable structure, its content cannot be modified. What the assignment is actually doing is copying the original list but replacing the third element with 23. This is a rather inefficient method. This seemingly direct assignment into Maple lists wasn't always possible and invariably causes problems. Because it is inefficient, Maple only allows it on lists with less than 100 elements.

An alternative approach is to convert the structure to a mutable object, say a Matrix or Array. That is what Carl does in his solution.

The procedure syntax is incorrect. Try

f := proc(i,j) OrderB(0,i,j+3); end proc:

Be aware that I've only looked at your code, not actually tried it.  The cc procedure is looping on each character, but does not do anything with the shifted character.  You need to assign it it to a new list.  The usual way to do that in Maple is to use the map procedure. Try replacing the for-loop in cc with

   map(cl, string, shift);

That applies cl to each character in string, passing shift as a second argument to cl. The resulting list is then returned.

You might have avoided this issue, or more easily discovered the cause, by using numelems rather than nops. They give the same result when the argument is a list, but numelems raises an error if its input is an unevaluated function call, which was your situation:

L(1):=[1,2,3]:
L(2):=[A,B,C]:
sum(numelems(L(i)),i=1..2);
Error, invalid input: numelems expects its 1st argument, t, to be of type indexable, but received L(i)

add(numelems(L(i)),i=1..2); 6

When writing Maple code it is good practice to use numelems when the argument is a list or other indexable element. The lower level nops returns a value for practically any Maple expression, as such it can mask subtle errors.

Consider using Iterator:-Permute. It will use a minimal amount of memory. As Markiyan points out, there is little reason to generate the entire permutation at once.

P := Iterator:-Permute(11):
# loop through the entire permutation.
CodeTools:-Usage(proc() local p; for p in P do end do; end proc());
memory used=1.49GiB, alloc change=0 bytes, cpu time=65.34s, real time=65.54s, gc time=876.06ms

Here's the non-robust foolish way to do this by directly changing the Maple dag type of the sublists. The idea is that the internal structure for a two-element list of integers is essentially the same as that for a fraction, so we merely have to change the dag type. For this particular example we can do so with a string substitutution in the m-format. I've added an element to the list to show what happens when the integers are not relatively prime.

A := [[2,3], [4,5], [6,7], [3,3]]:
sscanf(StringTools:-SubstituteAll(sprintf("%m",A),"7$","#"),"%m")[1];
              [2/3, 4/5, 6/7, 3/3]

Note that the last element is not in standard form.

If you happen to assign, say in your initialization file, the handy procedure

crossmul := proc(eq :: equation)
local L,R; 
    (L,R) := op(eq);
    numer(L)*denom(R) = numer(R)*denom(L);
end proc:

then you can use it with isolate

eq:= a*x+b*y=c*x+d*y:
crossmul(isolate(eq,x));
               (a-c)*x = -y*(b-d)

Not recommended as it generates a needless intermediate form.

 `/`~(ListTools:-Transpose(A)[]);
                              [2/3, 4/5, 6/7]

Make mass a Vector, not a Matrix.

  mass := Vector([...]);

Change distancevector to return a Vector, not a list:

  distancevector := (i,j) -> Vector([ ... ]):

Finally, change the k in the assignment to ode to q:

  ode := seq(seq((D(D(x[i, q])))(t) = force(i)[q], q = 1 .. 3), i = 0 .. N-1)

With that, dsolve returns a procedure and odeplot returns a plot of the trajectory.

The Do procedure is used to access and assign the value of the component. Use something like

for i to Do(%id) do
   for j from x to y do
      block[i][j] := 1-block[i][j];
   end do;
   ...
   Do(%id = whatever);
end do;
First 24 25 26 27 28 29 30 Last Page 26 of 114