Math in applescript: Handler gets stuck and CPU is at 0%

OK, Here’s what I’m trying now. Is this the right way to implement the logs? Also, since I’m using the same name for the log in each call to logit, is the log file being overwritten or appended to?

to logit(log_string, log_file)
	do shell script ¬
		"echo `date '+%Y-%m-%d %T: '`\"" & log_string & ¬
		"\" >> $HOME/Library/Logs/" & log_file & ".log"
end logit

on directionality(cpInfo)
	set outputList to {}
	set i to 1
	repeat with CP in cpInfo
		set eigenvalues to eigenvalues of CP
		set eigenvalues to sortlist (eigenvalues)
		try
			set theta to (atan ((abs ((item 3 of eigenvalues) / (item 2 of eigenvalues))) ^ (1 / 2)))
		on error
			logit("theta", "directionality")
			display dialog "theta" & i
		end try
		try
			set phi to (atan ((abs ((item 3 of eigenvalues) / (item 1 of eigenvalues))) ^ (1 / 2)))
		on error
			logit("phi", "directionality")
			display dialog "phi" & i
		end try
		try
			set end of outputList to CP & {theta:theta, phi:phi}
		on error
			logit("set list", "directionality")
			display dialog "set list" & i
		end try
		set i to i + 1
	end repeat
	return outputList
end directionality

logit("run handler", "directionality")

set cpInfo to directionality(*big list of records*)

logit("finish handler", "directionality")

return cpInfo

Also, that.

It will be appended, and look for the log file in the sidebar of your Console.app.

You can also go to /Users/You/LIbrary/Logs and doubleclick it to make it open in Console.app.

It seems correct to me, but as I said earlier, you really shouldn’t have the statements within the loop. start with one before, and one after if the one before turns up, and not the one after, then you know it is within the handler, which looks nothing like the one I fixed for you.

You use eigenvalues as a variable, but it is indeed a property, doesn’t it turn up with a different color in your editor? :slight_smile:

I am heading out, good luck!

You said that the handler I posted originally was working fine for you right? So I thought I’d try to isolate the problem with that handler. I set the value of the eigenvalues property to a variable called eigenvalues and then use that in the calculations.

edit Sorry McUsr, I didn’t’ note your comment before you posted your script about using the property name as a variable.

Hi McUsr,

So it seems the handler craps out after around 20 iterations of the loop. I did it three times, and it lasted 24, 18, and 16 iterations respectively. When I tried it with your script, it makes it to 20-30 iterations and fails. There’s never any indication of failure other than that nothing else happens. Sometimes it fails after theta is found but before phi, and sometimes it fails before theta is found. Here’s the scripts I’m testing now:

Mine:

to logit(log_string, log_file)
	do shell script ¬
		"echo `date '+%Y-%m-%d %T: '`\"" & log_string & ¬
		"\" >> $HOME/Library/Logs/" & log_file & ".log"
end logit

on directionality(cpInfo)
	set outputList to {}
	set i to 1
	logit("before loop", "directionality")
	repeat with CP in cpInfo
		
		set eigenvalues to eigenvalues of CP
		logit("variable set " & i, "directionality")
		set eigenvalues to sortlist (eigenvalues)
		logit("variable sorted", "directionality")
		set theta to (atan ((abs ((item 3 of eigenvalues) / (item 2 of eigenvalues))) ^ (1 / 2)))
		logit("theta found", "directionality")
		set phi to (atan ((abs ((item 3 of eigenvalues) / (item 1 of eigenvalues))) ^ (1 / 2)))
		logit("phi found", "directionality")
		set end of outputList to CP & {theta:theta, phi:phi}
		logit("data appended", "directionality")
		set i to i + 1
	end repeat
	logit("after loop", "directionality")
	return outputList
end directionality

logit("run handler", "directionality")

set cpInfo to directionality(*big list of records*))

logit("finish handler", "directionality")

return cpInfo

and McUsr’s:

set outputlist to {}

set cpInfo to (*big list of records*)

logit("before handler", "McUsr_directionality")

set outputlist to directionality(cpInfo, outputlist)

logit("after handler", "McUsr_directionality")

log outputlist

to logit(log_string, log_file)
	do shell script ¬
		"echo `date '+%Y-%m-%d %T: '`\"" & log_string & ¬
		"\" >> $HOME/Library/Logs/" & log_file & ".log"
end logit


on directionality(cpInfo, outputlist)
	script o
		property L : cpInfo
	end script
	set outputlist to {}
	set {c, i, fail} to {count cpInfo, 1, false}
	logit("before try", "McUsr_directionality")
	set iteration to 1
	try
		repeat c times
			logit("loop iteration " & iteration, "McUsr_directionality")
			set MyEigenValues to eigenvalues of item i of o's L
			set MyEigenValues to sortlist (MyEigenValues)
			set theta to (atan ((abs ((item 3 of MyEigenValues) / (item 2 of MyEigenValues))) ^ (1 / 2)))
			logit("theta found " & iteration, "McUsr_directionality")
			set phi to (atan ((abs ((item 3 of MyEigenValues) / (item 1 of MyEigenValues))) ^ (1 / 2)))
			logit("phi found " & iteration, "McUsr_directionality")
			set end of outputlist to item i of o's L & {theta:theta, phi:phi}
			set iteration to iteration + 1
		end repeat
	on error e number n
		-- Christopher Stone
		set {cr, sep} to {return, "------------------------------------------"}
		set errmsg to sep & cr & "Error: " & e & cr & sep & cr & "Error 
Number: " & n & cr & sep
		tell application "SystemUIServer"
			activate
			display dialog errmsg
		end tell
		set fail to true
	end try
	logit("after try", "McUsr_directionality")
	if fail then return null
	return outputlist
end directionality

and what the log looks like for each:

mine:

and McUsr’s:

Hello! I was curious, and had to come back to have a look! :slight_smile: I see it, and your statement about it being able to last fewer and fewer iterations, gives me some clues about more and more memory being consumed.

I wonder if you have any script objects, or if you copy script objects and properties somewhere in your code.

It is really time for you to declare variables local, and declare property parent : AppleScript.

you main even take everything out of your run handler, and put it inside a main() handler to avoid global - free variables, that are saved with your script during each run. And then call the main() handler from your run handler.

All this to avoid the consumption of memory, due to the context of the script being saved with it every time it is run, as it adds up recursively.

Please do try that! :slight_smile:

Of the things which could be causing the congestion, the Satimage commands do seem to be the main culprits. The more they’re used, the slower the script subsequently becomes and the slower all other scripts in AppleScript Editor subsequently become until I quit it and start again.

Here’s an alternative using Regulus6633’s “bc” suggestion:

on directionality(cpInfo)
	script o
		property inputList : cpInfo
		property outputList : {}
	end script
	
	repeat with i from 1 to (count cpInfo)
		set CP to item i of o's inputList
		set {a, b, c} to CP's eigenvalues
		if (a > b) then set {a, b} to {b, a}
		if (b > c) then set {b, c} to {c, b}
		if (a > b) then set {a, b} to {b, a}
		set {theta, phi} to paragraphs of (do shell script "echo \"a(" & (((c / b) ^ 2) ^ 0.25) & ") ;  a(" & (((c / a) ^ 2) ^ 0.25) & ")\" | bc -l")
		set end of o's outputList to CP & {theta:theta as number, phi:phi as number}
	end repeat
	
	return o's outputList
end directionality

The vanilla replacements for ‘sortlist’ and ‘abs’ are faster, but the shell script makes the handler slower overall. However, it doesn’t then progressively slow down, so it’s effectively faster!

Another thing you could do to save memory (if it’s compatible with your aims) is to substitute the new records for the old ones in the original list instead of creating another list for them.

This may not be relevant here, but just for interest: in record concatenations, the values of the properties of the left-hand record are retained in the result:

-- The values used below are for demo purposes only!
{eigenvalues:{1, 2, 3}} & {theta:6, phi:7} --> {eigenvalues:{1, 2, 3}, theta:6, phi:7}
{eigenvalues:{1, 2, 3}, theta:4, phi:5} & {theta:6, phi:7} --> {eigenvalues:{1, 2, 3}, theta:4, phi:5} -- Values from left record retained.

{theta:6, phi:7} & {eigenvalues:{1, 2, 3}} --> {theta:6, phi:7, eigenvalues:{1, 2, 3}} -- Records aren't ordered, so this result is equal to the first one.
{theta:6, phi:7} & {eigenvalues:{1, 2, 3}, theta:4, phi:5} --> {theta:6, phi:7, eigenvalues:{1, 2, 3}} -- Values from left record retained.

I thought that in applescript you had to explicitly declare a variable global for it to be so. Aren’t variables that are declared during their first use local if they’re declared within a handler? Also, I don’t explicitly use a run handler in any of my scripts, rather everything, including my main script, is a handler, and to initiate the script I make an automator service with just commands for setting the main handler file and calling the main handler. In doing it my current way, shouldn’t all the variables of each handler get dumped once the respective handler has finished?

My only background is some modest programming in C++, so I can only assume the same rules apply as to global and local variables. It’s not my fault! It’s my lousy American education, I swear!!

Also, could 8GB of ram get used so quickly? Seems wrong and scary, and somehow exciting…

I’ll read up on the use of the parent property, as this is the first time I’ve seen it, and I’m sure it’s one of the many things I should be more familiar with if I want to applescript effectively.

Thanks Nigel.

I notice that you and McUsr, both pros, have a script blocks declaring properties at the beginning of the script. Is this similar to passing the cpinfo list by reference rather than making a copy in memory? (obviously, I haven’t read up on properties yet…)

Thanks,

Tim

That’s basically right.

¢ Variables explicitly declared local are local to the handler in which they’re declared. They and their values cease to exist when the handler returns.
¢ Variables declared global in the ‘run’ handler (whether it’s implicit or explicit) are accessible throughout the script.
¢ Variables declared global in other kinds of handler are only global between the handlers in which they’re so declared.
¢ Undeclared variables in ordinary handlers are local to that handler unless they’ve been declared global in the ‘run’ handler.
¢ Undeclared variables in ‘run’ handlers are a strange, in-between type which can only be accessed from within ordinary handlers by referencing them through the script. As with globals and properties, their values persist by being saved back into the script file when the script’s finished running (unless the script was loaded as a library into another.)
¢ Properties are global throughout the script and any “child” scripts

It’s just a speed hack here. It’s not as effective as it used to be (normal list access appears to have speeded up now), but it seemed just to have the edge when I tried it here.

Hello.

If you search for “Applemods” you should find a very decent math library at sourecforge.net (AppleMods | Introduction), though I see no reasons for changing Nigels solution, as that is the fastest.

To use the math library.

Don’t let the loader stuff in the math library intimidate you, just rip out the handlers, and any properties you need! :slight_smile:

Hhas’s math functions look like the real thing, with precomputed tables, and are not the development of series, iterated over, to get the value. I think we all should have a copy, if Satimage.osax slows down.

I didn’t believe that to be happening really, Satimage.osax slowing down. :frowning:

You are perfectly safe by not using local declared variables, until the day comes that you have one declared as a property in a script, or in a script that calls your script and so on. The difference between a property, and a global, and an implicit globlal, declared either in the explicit or implicit runhandler is its visibility.

Conclusion
An undeclared variable in a handler in a script, will use a property with the same name.
A property declared at the toplevel of a script is visible from within every handler in that script.

bc is terrible to use interactively, but may be the perfect tool here, I think it will be the fastest alternative to vanilla solutions, as soon as a few iterations are needed. I see a great future for bc indeed! :smiley:

@ The pro thing, flattering to be mentioned with Nigel, but not true.

Nigel,

I wonder if the problem is actually with AppleScript Editor. I tried the original script with 1500-odd values and it works fine in Script Debugger (4.5 and 5.x) and AppleScriptObjC Editor, and also seems to run OK if saved as an app from ASE (running 10.8.1 here). It only causes problems here in ASE.

So it is causing problems on someone else’s ASE!! Oh good, I thought I was going crazy. The problem was also occurring when running the script in its intended form as a service. I also notice that things like “choose file” have some strange behavior when ran inside of ASE, not showing the contents of folders and such.

I’ll research these math libraries for future use (they can’t be much more process-intensive than Satimage.osax functions if they achieve the same result right? They’re both having to do similar operations to compute the same thing, I would think), and for now I’ll go with the bc solution.

Thanks so much for all your help guys.

There may be varying levels of pro, but you’re at least semi-pro McUsr.

Thanks again,

Tim

Hi!

The same goes for me, I used some 1700 values, with no problem at all, I didn’t time the loops though.

Now if that is a problem with ASEditor in whatever version, it would seem like it leaks memory, or has memory errors, it would be nice to know if any of those turns up in the console?

There should be some evidence to be had there, if part of AS Editor isn’t working properly. with regards to memory managment.

I believe it to be memory managment, since it seems it isn’t able to reclaim memory that I presume should have been freed. Which would lead to a smaller and smaller memory pool, and slower and slower execution, due to more and more overhead with the memory managment.

This is just uneducated speculations.

I don’t think it’s a memory leak. It looks more like at some stage an event is sent and no reply is received, so the script just sits there waiting. The rest of the app works fine.

Maybe it is possible to do the calls to the osax from within a tell block then, to “SystemUIServer” or similiar as me isn’t much good from within the editor, in order to see if it is AS Editor that stalls the events.

I read that there are new security guidelines for osaxen’s, that they now are routed differently, and not allowed to call applications, but I think that doesn’t pertain to this case.

And if it does, I think there will be something in the log about what has happened.

Or possibly it’s something unique to the interaction between ASE and Satimage (the latter’s ‘atan’ command, at least) since they’re both needed for the cumulative slow-down to be seen. Tim’s original script works fine for me on the first run with a list 32 times as long as his example and is faster than my vanilla/bc alternative; but after each run, everything in AppleScript Editor slows down a bit more ” including, eventually, window navigation. Recompiling the script doesn’t make any difference.

No doubt Emmanuel would recommend switching to Smile. :wink:

Could be. Are you running 10.8.x? I found I could still open other ASE windows and work on happily. I wonder if it’s some of the new security-related stuff in AS.

No. I’m still on 10.6.8 (ASE 2.2, AS 2.1.2).

Ah – that points the finger a bit more at Satimage.