Hi Gambitters,
I want to use Scheme to implement a computer simulation of the Ising model of spins. Background: http://en.wikipedia.org/wiki/Ising_model
Basically all the algorithm does is allocate a vector of spins and flip them randomly in such a way that a representative sampling at a specified temperature is produced.
Efficiency of the algorithm is very important as it would allow me to study larger samples.
Currently on my own system after compilation: with a sample size of 40x40 I can do 1000 flips/site in a little over 3 seconds. Currently the simulation starts from an all up state and displays some variables and the end configuration of the sample. It looks like this:
$ time gsi ising -e "(main 1000)" D: 2, N: 1600, L: 40, BETA*J: .3, RANDOM-STATE: 10624525222961816100342112271285465503733219408383542344109 E: 72, M: -40 +-++++---++---+-+-+-++++--+----+++-+-+-- +++-+---+-+------++---+-+--+--+++++++--- ----+-+--+--+-+--+-+-+++-++---------++-+ ---+---+--++-++++-++++-+--+++-++---+--+- ++++--++-+----++++----+-++---+----+-+++- -----+++--+---+-+++++-++++-+---+++-+++-+ ++-+--+-+---+--+++++-+-+---+++++-++---+- -+---+--++--++--+---++++--+-----+-+-+--+ ----+-+--+---++--+-++-+--+----+++---++-- --++-++---+-++++--+++-++++----+-+++++--- ++-+-+-+-+-+++-+-++++++-+---+---++-+-+-- +--+---++-++++----+-++-+-+-++-++-------+ +--------+++-+-+++---+-+--+-+---++--+-++ +---++-+-+++++++--+-++--+-+++-++++---++- +--+----+++--+--+-+---+++-+-+---+--+++++ ++-+++-+++--+++--+-++++--++-+---+-+-++++ +-+---+++--+-+--+++-+--+---+-++++++-+++- ++---++---+-+--++-+++----+-+++--+++-+--- ++-++-+--+---+++-----+-+----+--+-+-+-+-+ ++--++--+--+-+++--++++--+++++--++-+--+-+ -+---++--+-++--++-+--++-+-++--+-++++-+-+ +----+-+--+++--+---+--+-+++--++--++-+++- ++++--+-++--++++----+-++-+--------+-++++ +-----+++++++-+-+--++-++-+--+++--++-++++ +--++-+-++-------+-+++-----++-+-++-+-++- +--+++--+-+++--+---+---+-----++-+-++-+++ --+-+-+---+-+++----+-+--------+----+-+-+ -+--+--+-+++-+-----+-+----++++-++-++-++- -+-++-+-+--+--+----+++--+-+-+-++--+++-+- +-+++-+-++-+-+++++-+----+-+-+--+-++----+ +------+-+---+-++-+-++++-++-++-++---++-+ ++----++-+-+--+-+-+++-+-+---+++-----++-+ ++++-++++-++-+-+++--++++-++-+--+++++-++- ++-----+++++--++--+-+-+-++-+-+++------+- ++++-+++---+---+-+-++-+---+-+----++++--+ +---++--++---++-+----------+-----+---++- ---++-++--+--++--+--++-+----+--+-++----+ ++--++--+--++++-+---++-++------++-++---- -++-++-++-++---+----+-++---++++++--++-++ +-----+++++--++-+-+---+-++---+-++--++-+-
real 0m3.507s user 0m3.198s sys 0m0.007s
to compile the program I use:
gsc -cc-options "-O2 -march=native" ising
I do not know enough about Gambit to know what's fast and what's not and I have no experience with profiling, so I would appreciate some pointers on how to go about optimizing the program.
As a side note I was also hoping to compare the performance of various Schemes for this workload, but it seems the ones I tried so far (bigloo and guile) do not support srfi-27 (Sources of Random Bits) much. (It worked in guile until just now when I added a few bits to be able to change the pseudorandom number generator seed.) If anyone knows other implementations where it would run that would be cool.
Finally, the source is attached. Any comments appreciated.
Thanks in advance,
Marijn
Afficher les réponses par date
The purpose of the code may be obvious to you, but I can't tell what you want to do (even knowing roughly what the Ising model is, and after looking at the wikipedia page you pointed to).
Some advice:
1. If you're going to use something again and again, don't recompute it, compute it once and save it. It appears that helical-neighbors is computed over and over again. In accept-flip you compute (energy-jump/J grid site) twice if it turns out to be positive. You can use (time ...) to get information about how much stuff is consed, etc.
2. If you can avoid arithmetic between exact (integer, rational) numbers and inexact (floating-point) numbers, do so. And if you know that computations or comparisons are between fixnums, use the fixnum operations fx+, fx<, ...; if you know that certain operations apply only to flonums use fl+, ...
3. If you've done the things above, then declaring (standard-bindings)(extended-bindings)(block)(not safe) will help (but not before doing those things).
4. If you've done all *those* things, then don't use -O2 (the options that Gambit chooses at configuration time are almost always faster, especially for gcc) and if "-march=native" helps, then use it at configuration time.
Brad
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Bradley Lucier wrote:
The purpose of the code may be obvious to you, but I can't tell what you want to do (even knowing roughly what the Ising model is, and after looking at the wikipedia page you pointed to).
Some advice:
- If you're going to use something again and again, don't recompute
it, compute it once and save it. It appears that helical-neighbors is computed over and over again. In accept-flip you compute (energy-jump/J grid site) twice if it turns out to be positive. You can use (time ...) to get information about how much stuff is consed, etc.
- If you can avoid arithmetic between exact (integer, rational)
numbers and inexact (floating-point) numbers, do so. And if you know that computations or comparisons are between fixnums, use the fixnum operations fx+, fx<, ...; if you know that certain operations apply only to flonums use fl+, ...
- If you've done the things above, then declaring
(standard-bindings)(extended-bindings)(block)(not safe) will help (but not before doing those things).
- If you've done all *those* things, then don't use -O2 (the options
that Gambit chooses at configuration time are almost always faster, especially for gcc) and if "-march=native" helps, then use it at configuration time.
Brad
Hi Brad,
thanks for looking my program over. I'll think about how to apply your advice.
Meanwhile, since I think you implied that you'd be interested in the following: The program simulates a bunch of tiny magnets that are restricted to point in one direction; either up or down. The energy function makes it favorable for them to all point in the same direction. This situation is called ferromagnetic and is an explanation of why a piece of iron can be permanently magnetized. If the spins have more kinetic energy, that is at higher temperatures, then due to the larger thermal energy fluctuations it is more likely that spins point in either direction rather than all in the same direction. That is, if you raise the temperature of a ferromagnet, the permanent magnetic field will disappear. There is a so-called critical temperature at which a transition between these two phases takes place. The program simulates the temperature-dependent energy fluctuations that cause spin flips in the array of spins and thus allows me to measure the average magnetisation at a certain temperature. However the simulation needs to be running long enough such that the sample can be assumed to be in equilibrium before any measurements can be done. There are situations where this can take a long time. For example if you start with a checker-board formation and simulate zero temperature, the sample will end up in either the all-down configuration or in the all-up configuration. Different parts of the sample might make different decisions on which it should be on the road to get to the final configuration. Only spins on the interfaces between differently magnetized areas are really available for spin flips due to the high energy increase for in-area spin flips and the low temperature. Anyway, I hope I haven't gone overboard on details, but that nonetheless it is now more clear what the program should do.
Marijn
- -- Sarcasm puts the iron in irony, cynicism the steel.
Marijn Schouten (hkBst), Gentoo Lisp project, Gentoo ML http://www.gentoo.org/proj/en/lisp/, #gentoo-{lisp,ml} on FreeNode