Carl Love

Carl Love

28040 Reputation

25 Badges

12 years, 329 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are replies submitted by Carl Love

@emendes Variable C is defined in condition 3 and used in condition 4. Is condition 3 no longer needed?

Here is the "Exclusion conditions" section of code where I've added your condition 5 and commented out condition 3. The order of the conditions is the fastest order to evaluate them in.

	#Exclusion conditions:
	#---------------------
	#Build a table of sets grouped by their 1st index:
	ClassifyI:= proc(S)
	option cache;
		ListTools:-Classify(x-> x[1], S)
	end proc,
	
	TSt:= table([0=(), 1=1, 2=2, 3=3, 4=1, 5=(1,2), 6=(1,3), 7=2, 8=(2,3), 9=3]),
        TS:= proc(j) option remember; TSt[j] end proc,

	#Decide whether a permutation's orbit is allowed to be represented:
	AllowOrbit:= S->
		local J;
		op~(1,S) = Is					    #condition 1
			and
		max((J:= op~(2,S))) >= 4                      	    #condition 2
			and
		TS~(J) = Is                                  	    #condition 5
		(* Comment out condition 3.
			and	
		nops({entries((op~)~(2,(C:= ClassifyI(S))))}) = nIs #condition 3
		*)
			and not                                     #condition 4:
		ormap(k-> op~(2,ClassifyI(S)[k]) subset [{0,1,4}, {0,2,7}, {0,3,9}][k], Is),

Change notes:

  1. ClassifyI should have option cache if condition 3 is removed.
  2. Anything (including line breaks) between (* and *) is a comment. I use this style for commenting out code.
  3. Change C to ClassifyI(S) in condition 4.

Do you want condition 5 to have the same property that you wanted for condition 4, namely that it being false automatically disqualifies the counterpart of S? That's the way that's coded above.

 

@Joe Riel @emendes

Hi Joe,

We need some help with Iterator. We have a very weird bug that's OS dependent, and in the case of Windows or MacIntosh, it only occurs on the first run after a restart. In the case of Linux, it occurs every run. I suspect that it's related to compilation of a rank-split Iterator used under Threads.

On the Linux machine only, the error occurs while trying to Unrank 1470301, which is the first value in the 27th of 36 pairs produced by SplitRanks. On Mac and Windows 10, the error is about the nonexistence of some weirdly (randomly?) named file.

Best regards,
Carl


Eduardo,

Please add option compile= false to the It:-Combination command and test again on all available OS's.

Second thing to test, independently, and only on the server: Add the option numtasks= 26 to the It:-SplitRanks command.

Third thing to test: Use option sequential in the call to OrbitPartition.

Another significant difference between sets and lists is that membership checks in large sets are faster than those in long lists because it makes use of the fact that the set entries are stored sorted. In addition to the differences mentioned by Acer, I think that this is the only other significant difference.

@emendes I had similar weird errors the 1st (and only the 1st after each restart) time that I tried to run it on each of my two computers: one error coming from Iterator about a random-seeming particular iterate, and one about some randomly-generated file name not existing. Funny thing, though: Both of my computers are Windows 10!! So, please just try again. I have a vague suspicion that the issue is related to Iterator compiling its results (perhaps in separate threads).

The box that contains the module code is called a code edit region. You can use the Insert menu to insert one anywhere in a worksheet. To "load" the code in the region, right click on it and select "Execute Code" from the context menu that pops up. If the code has errors, you'll be notified, but you may need a magnifying glass to locate them precisely: Their approximate locations in the code are marked by red squiggles the same size as the red fibers in US currency.

@Kitonum Here is some cleaner and faster code that does the same thing. My only goal was to make it cleaner; the faster came as an unexpected bonus.

restart:
A:= <1,2,2; 2,1,2; 2,2,3>:
T:= <L[1], -L[2], L[3]; L[1], L[2], L[3]; -L[1], L[2], L[3]>:
NextTriples:= subs(R= convert(T.A, listlist)[], L-> R):

T1:= CodeTools:-Usage(seq((NextTriples~@@n)([[3,4,5]])[], n= 1..10)):
memory used=24.48MiB, alloc change=46.01MiB, cpu time=187.00ms,
real time=189.00ms, gc time=46.88ms

nops([T1]);
                             88572

#Compare with:
NextTriple:=proc(L)
local i;
[seq(op([[L[i,1]-2*L[i,2]+2*L[i,3], 2*L[i,1]-L[i,2]+2*L[i,3], 2*L[i,1]-2*L[i,2]+3*L[i,3]], [L[i,1]+2*L[i,2]+2*L[i,3], 2*L[i,1]+L[i,2]+2*L[i,3], 2*L[i,1]+2*L[i,2]+3*L[i,3]],
[-L[i,1]+2*L[i,2]+2*L[i,3], -2*L[i,1]+L[i,2]+2*L[i,3], -2*L[i,1]+2*L[i,2]+3*L[i,3]]]), i=1..nops(L))];
end proc:
T2:= CodeTools:-Usage(seq((NextTriple@@n)([[3,4,5]])[], n= 1..10)):
memory used=37.53MiB, alloc change=-6.01MiB, cpu time=485.00ms, 
real time=495.00ms, gc time=140.62ms

evalb([T1]=[T2]);
                              true

 

@emendes Garbage collection (gc) happens automatically. Every time that you see either number (memory or time) change in the status bar (bottom right of your worksheet window), there has been a gc. With the code that we're working on, you'll notice that that happens about once per second. There's no danger in doing your own gc, but it's unlikely that you'll improve upon the efficiency of the automatic ones, and there's a good chance that you'll decrease the efficiency. That's why it's discouraged.

@JAMET 

There are many ways to do it. The way that I would recommend would depend largely on two conditions:

  1. Do you want to use a very large n, say, n > 1000?
  2. Do you want to return the entire sequence of iterates, or just its final entry?

The commands foldl and foldr can be used to compose a binary operator with itself. If the operator is associative (as the present case is), these commands give the same result. For example,

foldr(`&*`, [3,4,5] $ 9)

The procedure that you were trying to write could be written like this:

Tri:= proc(Y::And(list(algebraic), 3 &under nops), n::posint)
local r:= Y;
    to n-1 do r:= Y &* r od;
    r
end proc:

You shouldn't declare a variable global just because you use it in a procedure. That's only needed if you make an assignment to it.

@emendes If your attempt to use Grid is pursuant to the same problem that we're working on in the other thread, then don't bother. I just finished parallelizing our OrbitPartition with Threads, which is much more memory efficient than Grid (if you can satisfy its rather strict requirements).

@Carl Love I pared my code down to a single regular-expression substitution:

showstat_no_nums:= p->
    `debugger/printf`(
        "%s",  
        StringTools:-RegSubs(
            "\n[ 1-9][^\n][^\n][^\n]"= "\n ", 
            debugopts('procpretty'= p)
        )
    )
:

 

@emendes 

Sorry for the delay in answering. It was because both of your questions require lengthy and technical answers.
 

Re: "Memory used" as reported by CodeTools:-Usage: This number is reported with a dimension of information (bytes or multiples thereof). This is incorrect! What this number actually represents is Int(M(t), t= time program runs) where M(t) is the amount of memory "being actively used" at time t. Thus the correct dimensions are information*time (e.g., GiB-s (gibibyte-seconds)). It is sad and somewhat shocking that no-one at MapleSoft has noticed and corrected this. (The same dimension error is incorrectly documented for kernelopts(bytesused).) Many systems and computer scientists avoid the confusion about this issue by naming this measurement "memory integral" rather than "memory used" and by using the correct dimensions.

I don't know the precise definition of "being actively used"; I am trying to figure that out from experimentation. There is also the issue of how time is measured. Is it real time? cpu time? something else? This is a bit easier to determine by experiment, and my best guess so far is that it's pretty close to kernelopts(cputime) - kernelopts(gctotaltime).

You're justifiably worried about running out of memory when doing the larger tuples. The number that you need to watch is not reported by CodeTools:-Usage. It does however appear on the worksheet status line (the bottom right), along with cputime.

Note that memory is nearly constantly being recycled by garbage collection, so the same chunk of memory may be "used" many times during a program run. Each such re-use adds to the incorrectly named "memory used".
 

Re: option remember and option cache: Both of these are attempts to save the cputime needed to re-call a procedure with arguments that it's already seen at the expense of the memory needed to store those results. The process is technically called memoization in computer science literature.

Consider the subprocedure of OrbitPartition. It may be called millions of times during an execution of the program, but it only has exactly 13 possible pairs of arguments. Thus the memory needed to store the pre-computed results is trivial. Using option remember means any previously computed results will be remembered for as long as the procedure is in the visible scope.

Now consider the procedure ClassifyI in the setup code. It also may be called millions or times, but with millions of different arguments. But it's called twice in succession with the same argument---once in AllowedRep and once in DisallowedOrbit. By using option cache, a scrolling cache of the most recently used results is maintained. You can specify the maximum number of entries in this cache in the option. In this case, option cache(1) would work. The only reason that I didn't put a number is that a default-size cache might supply some useful debugging information if that were needed. The cache or remember table of a procedure P (it can't have both, but it may have neither) can be directly inspected via op(4, eval(P)).
 

Re: Making it a module: Do you want the setup specifications inside (local to) the module?

@JAMET Sorry about that. I had just noticed that myself, and I uploaded a new worksheet a few minutes ago. Try it again.

I have often had trouble with Grid:-Seq when the chunks were too small. I'd recommend that each chunk take at least 2 seconds to process. Your 500 seems both rather arbitrary and way too small.

I don't think that it can be done unless you know the positions of the vertices. If you do know (for example, if you can measure them from an existing picture), then you can use SetVertxPositions. I doubt that there is any algorithm to do it without knowing those vertex positions.

To give you an idea of the problems with constructing an algorithm, consider the triangle inequality.

@mmcdara The output of showstat is equivalent to the output of printf; so, yes, it's "side-effect" output rather than "return value" output. That's why I went one step back through the showstat code to get the output from debugopts(procpretty= ...). This is identical to the standard showstat output, but in string (actually name) form.

@Pascal4QM Thanks. As you can probably tell, I worked it out by deconstructing showstat itself.

First 199 200 201 202 203 204 205 Last Page 201 of 709