Listings


Class Cgrid


/**
 * name: Cgrid.java
 * auth: Tijmen Collignon & Arthur van Dam (c) 1998
 * lang: JDK 1.0.2
 * base: from scratch
 * intf: none
 * hist:
 * desc: Controller - Main class that creates the applet and handles any user events.
 * prot: public void    init();
 *       public void    stop();           
 *       public void    start();
 *       public void    initControlPanel();
 *       public void    resetFields(); 
 *       public void    updateParams();
 *       public void    setNotEditable();
 *       public void    setWelEditable();
 *       public boolean action(Event ev, Object obj);
 * usag: Create an html file with an applet tag. Optional parameters:
 *         "app_procs"    - # processors
 *         "app_gridsize" - size of grid
 **/


import java.awt.*;
import java.applet.Applet;

public class Cgrid extends Applet
{
    GridCanv canv;     // canvas voor grafische output
    GridModel model;   // rekenklasse
    GridAnim animatie; // beheert voortdurende optimalisatie
    TextField p, s, costs, cooltemp, coolperiod, coolspeed, result, minimum, dif;
    Panel controlpanel;
    Choice spread;     // keuze voor de verdelingsmethoden
    Button start_stop, pause_resume;
    int nodes,         // aantal processoren
        size;          // grootte grid
    int test;

    public void init(){
        showStatus("Applet.init()");
        setBackground(Color.white);
        nodes = Integer.parseInt(getParameter("app_procs"));
        size = Integer.parseInt(getParameter("app_gridsize"));
        p            = new TextField(nodes+"");
        s            = new TextField(size+"");
        costs        = new TextField("1");
        cooltemp     = new TextField("10");
        result       = new TextField("Just a moment please...");
        coolspeed    = new TextField("0.98");
        coolperiod   = new TextField("1000");
        dif          = new TextField("100 %");
        minimum      = new TextField("Push 'Start'!");
        spread       = new Choice();
        controlpanel = new Panel();
        start_stop   = new Button("Start");
        pause_resume = new Button("");
        model        = new GridModel(size, nodes);
        canv         = new GridCanv(model);
        animatie     = new GridAnim(this);
        test = 0;

        initControlPanel();
        result.setEditable(false);
        dif.setEditable(false);
        minimum.setEditable(false);
        spread.addItem("Random");
        spread.addItem("Balanced");
        spread.select(1);
        model.balancedGrid();   // equal numbers
        
        result.setText(""+model.compCosts(Double.valueOf(costs.getText()).doubleValue()));
        add("East", controlpanel);
        add("Center", canv);
    
    }
    
    public void stop(){         // Wanneer de gebruiker de pagina verlaat
    showStatus("Applet.stop()");
        if(animatie.isAlive())
            animatie.suspend(); //  wordt de eventueel draaiende animatie gepauzeerd
        super.stop();
    }

    public void start(){        // Wanneer de gebruiker de pagina (weer) binnenkomt
        showStatus("Applet.start()");
        if(animatie.isAlive())
            animatie.resume();  // Als er reeds een animatie was aangemaakt, gaat 'ie nu weer lopen
        this.repaint(); this.show();
        canv.repaint(); canv.show();
    }
    
    public void initControlPanel(){
        controlpanel.resize(100,80);

        controlpanel.setLayout(new GridLayout(12, 2));

        controlpanel.add(new Label("gridsize k:")); 
        controlpanel.add(s);
        controlpanel.add(new Label("number of procs:"));
        controlpanel.add(p);
        controlpanel.add(new Label("Communication costs:"));
        controlpanel.add(costs);
        controlpanel.add(new Label("Initial T:"));
        controlpanel.add(cooltemp);
        controlpanel.add(new Label("Cooling speed:"));
        controlpanel.add(coolspeed);
        controlpanel.add(new Label("Cooling period:"));
        controlpanel.add(coolperiod);
        controlpanel.add(new Label("Generated grid:"));
        controlpanel.add(spread);
        controlpanel.add(new Button("Reset"));
        controlpanel.add(new Button("Redistribute"));
        controlpanel.add(start_stop);
        controlpanel.add(pause_resume);
        controlpanel.add(new Label("Total costs:"));
        controlpanel.add(result);
        controlpanel.add(new Label("Difference:"));
        controlpanel.add(dif);
        controlpanel.add(new Label("Minimum costs:"));
        controlpanel.add(minimum);
    }

    public void resetFields(){
        s.setText("4");
        p.setText("4");
        costs.setText("1");
        cooltemp.setText("10");
        spread.select(1);
        coolspeed.setText("0.98");
        coolperiod.setText("1000");
        showStatus("Parameters reset");
        
    }

    public void updateParams(){    // wordt vanuit action aangeroepen wanneer parameters veranderen
        model.refresh(Integer.parseInt(s.getText()), Integer.parseInt(p.getText()));
        String keuze = spread.getSelectedItem();   // Gebruik juiste verspredingsmethode
        if     (keuze.equals("Random"))
            model.randomGrid();
        else if(keuze.equals("Balanced"))
            model.balancedGrid();
        result.setText(""+model.compCosts(Double.valueOf(costs.getText()).doubleValue()));
        canv.getGraphics().clearRect(0,0,canv.realsize, canv.realsize);
	canv.refresh(model);    // nieuwe model ook op canvas weergeven
        
        minimum.setText("Push 'Start'!");
        dif.setText("100 %");
        showStatus("Processors redistributed");
    }
    
    public void setNotEditable(){  // Zodat alle TextFields, behalve koelperiode niet ge-edit kunnen worden.
        for(int i = 1; i <= 9; i +=2){
            ((TextField)controlpanel.getComponent(i)).setEditable(false);
	    ((TextField)controlpanel.getComponent(i)).setBackground(Color.lightGray);
    	}
    }
    
    public void setWelEditable(){  // Zodat alle TextFields, behalve koelperiode wel ge-edit kunnen worden.
        for(int i = 1; i <= 9; i +=2){
            ((TextField)controlpanel.getComponent(i)).setEditable(true);
    	    ((TextField)controlpanel.getComponent(i)).setBackground(Color.white);
    	}
    }
        
    public boolean action(Event ev, Object obj){
            if(ev.target instanceof Button){  // Als het een Button is, ga dan afh. van opschrift reageren                                  
            aktie = (String)obj;
            if     (aktie.equals("Start")){
                animatie = new GridAnim(this);
                animatie.start();                  // Start optimalisatie
                start_stop.setLabel("Stop");       // Maak hier een 'Stop'-knop van
                pause_resume.setLabel("Pause");    // Activeer 'Pause'-knop
                setNotEditable();                  // Tijdens optimalisatie geen aanpassing parameters
                showStatus("Optimization started");
                return true;
            }
            else if(aktie.equals("Stop")){
                animatie.stopit();                 // Stop de optimalisatie
                start_stop.setLabel("Start");      // Maak er weer een 'Stop'-knop van
                pause_resume.setLabel("");         // Deactiveer 'Pause'-knop
                setWelEditable();                  // Parameters mogen weer aangepast worden
                showStatus("Optimization stopped at T = "+animatie.T);
                return true;
            }
            else if(aktie.equals("Pause")){
                animatie.suspend();
                pause_resume.setLabel("Resume");   // Zorg dat deze pauze met een 'Hervat'-knop beeindigd kan worden
                showStatus("Optimization paused at T = "+animatie.T);
                return true;
            }
            else if(aktie.equals("Resume")){
                animatie.resume();
                pause_resume.setLabel("Pause");    // Zorg dat er weer gepauzeerd kan worden
                showStatus("Optimization resumed at T = "+animatie.T);
                return true;
            }
            if(aktie.equals("Reset")){
                if(animatie.isAlive()){            // Als optimalisatie nog loopt...
                    animatie.stop();               // Stop hem dan,
                    start_stop.setLabel("Start");  // Activeer 'Start'-knop
                    pause_resume.setLabel("");     // Deactiveer 'Pause'-knop
                    setWelEditable();              // Parameters kunnen weer aangepast worden.
                }
                resetFields();
                updateParams();                    // Voer nieuwe parameters ook in model en canvas door.
                return true;
            } 
            if(aktie.equals("Redistribute")){      // Zie uitleg bij "Reset"
                if(animatie.isAlive()){
                    animatie.stop();
                    start_stop.setLabel("Start");
                    pause_resume.setLabel("");
                    setWelEditable();
                }
                updateParams();
                return true;
            }
            if(aktie.equals("")){                  // Als Button geen tekst bevat(gedeactiveerde 'Pause'-knop), niet reageren.
                return true;
            }
            
        }
                
        updateParams();
        showStatus("Processors redistributed");
        return true;
    }
}

Class GridAnim


/**
 * name: GridAnim.java
 * auth: Tijmen Collignon & Arthur van Dam (c) 1998
 * lang: JDK 1.0.2
 * base: from scratch
 * intf: none
 * hist:
 * desc: Handles the thread
 * prot: public void run();
 **/


import java.lang.Thread;

class GridAnim extends Thread
{
    Cgrid cgrid;
    double T;
    public GridAnim(Cgrid cg)
    {
        cgrid = cg;      // Thread kan nu overal bij
    }

    public void run()    // methode die wordt gestart en meteen wordt afgesloten terwijl ie op de achtergrond doordraait
    {
        int i = 0, loops = 0, newNoOfLoops = 0;
        double g, v, costs, minimum, startcosts;
        T = Double.valueOf(cgrid.cooltemp.getText()).doubleValue();
        g = Double.valueOf(cgrid.costs.getText()).doubleValue();
        v = Double.valueOf(cgrid.coolspeed.getText()).doubleValue();
        costs = cgrid.model.compCosts(g);
        startcosts = costs;
        minimum = costs;
        cgrid.minimum.setText(""+minimum);
        while(true){
            i++;
            newNoOfLoops = Integer.parseInt(cgrid.coolperiod.getText());
	    costs += cgrid.model.optimize(g, T, newNoOfLoops);
            T *= v;
            loops += newNoOfLoops; // het aantal loops wordt bijgehouden
	    try{ 
	    sleep(100); // het systeem de tijd geven om te repainten
	    }
	    catch(InterruptedException e){}
	    cgrid.canv.repaint();
            cgrid.result.setText(""+costs);
            cgrid.dif.setText(((costs-startcosts)/startcosts*100)+" %"); // verschil in procenten met initiele kosten
            if(costs < minimum){minimum = costs; cgrid.minimum.setText(""+minimum+" = "+(minimum/startcosts*100)+" %");} // minimum kosten worden geupdate
            cgrid.showStatus(getName()+" is still optimizing after "+loops+" potential swaps; T = "+T);
        }
    } 
}

Class GridCanv


/**
 * name: GridCanv.java
 * auth: Tijmen Collignon & Arthur van Dam (c) 1998
 * lang: JDK 1.0.2
 * base: from scratch
 * intf: none
 * hist:
 * desc: View - Graphics class that extends Canvas.
 * prot: public void initColors();
 *       public void refresh(GridModel gm);
 *       public void update(Graphics g);
 *       public void paint(Graphics g);
 **/


import java.awt.*;

class GridCanv extends Canvas{
    int width, realsize;
    Color colors[];    // mogelijke kleuren
    GridModel model;

    public GridCanv(GridModel m){
        colors = new Color[10];
        initColors();
        realsize = 300;
        resize(realsize, realsize);
        refresh(m);
    }

    public void initColors(){
        colors[0] = Color.blue;
        colors[1] = Color.green;
        colors[2] = Color.red;
        colors[3] = Color.yellow;
        colors[4] = Color.black;
        colors[5] = Color.white;
        colors[6] = Color.magenta;
        colors[7] = Color.gray;
        colors[8] = Color.orange;
        colors[9] = Color.cyan;
    }

    public void refresh(GridModel gm){
        model    = gm;
        width    = (int)((double)realsize/(double)model.size);
        repaint();
    }

    public void update(Graphics g){
        paint(g);
    }

    public void paint(Graphics g){ //Tekent afh. van gridsize, vierkantjes met juiste kleur
        for(int i=0; i<gridsize; i++)
        for(int j=0; j<gridsize; j++){
            g.setColor(colors[model.nodes[i][j]]);
            g.fillRect(i*width, j*width, width, width);
        }
    }
}

Class GridModel


/**
 * name: GridModel.java
 * auth: Tijmen Collignon & Arthur van Dam (c) 1998
 * lang: JDK 1.0.2
 * base: from scratch
 * intf: none
 * hist:
 * desc: Model - class that contains simulation subroutines.
 * prot: public void    refresh(int k, int p);
 *       public void    randomGrid();
 *       public void    balancedGrid();
 *       public void    addCellComms(int i, int j);
 *       public void    substractCellComms(int i, int j)l;
 *       public boolean validNode(int i, int j);
 *       public int     findMax(int input[]);
 *       public double  compCosts(double g);
 *       public double  optimize(double g, double T, int peri
 *       public double  swapHorizontal(int i, int j, double g, double T);
 *       public double  swapVertical(int i, int j, double g, double T);
 **/


class GridModel
{
    int nodes[][];      // kleurnr. van alle cellen van het hele grid
    int size, proc;     // grootte grid, aantal kleuren
    int hs[], hr[];     // send, receive-kosten

    public GridModel(int k, int p) //k = gridsize, p=#procs
    {
        refresh(k, p);
    }

    public void refresh(int k, int p) // 'constructor' die ook buiten de klasse aangeroepen kan worden.
    {
        if (p>10) p=10;
        if (k>50) k=50;
        hs     = new int[p];
        hr     = new int[p];
        size   = k;
        proc   = p;
        nodes  = new int[k][k];
    }

    public void randomGrid() // ken aan iedere cel een random kleur toe
    {
        int r;

        for(int i = 0; i < size; i++)
            for(int j = 0; j < size; j++)
                nodes[i][j] = (int)((double)proc*Math.random());
    }

    public void balancedGrid()// verdeelt kleuren random, maar stelt aantal van iedere kleur aan grenzen.
    {
        int p,
            over = size*size;                 // aantal cellen dat nog ingekleurd moet worden.
        double cum_kans[] = new double[proc]; // cumulatieve kans voor een kleur om nog gekozen te worden
        double r;
        for (int i = 0; i < proc; i++)        // Geef aanvankelijk alle procs even veel kans
           cum_kans[i] = (double)(i+1)/(double)proc;
        for(int i = 0; i < size; i++)        // Loop alle cellen langs...
        for(int j = 0; j < size; j++){
            r = Math.random();
            for(p = 0; r >= cum_kans[p]; p++) // bepaal in welke processorcategorie het random getal valt
                cum_kans[p] *= (double)over/(double)(over-1);// pas meteen de kansen aan
            nodes[i][j] = p;                  // ken aan de huidige cel, die gevonden processor toe...
            while(p < proc){
                cum_kans[p] = (cum_kans[p]*(double)over - 1)/(double)(over - 1);// en pas rest van kansen aan.
                p++;
            }
            over--;
	}
    }

    public boolean validNode(int i, int j)    // bepaalt aan de hand van indices of een cel in het grid ligt
    {
        if(i < 0 || i > size-1 || j < 0 || j > size-1)
            return false;
        return true;
    }

    public int findMax(int input[])
    {
        int max = input[0];
        for(int i = 1; i < input.length; i++)
            if(input[i] > max)
                max = input[i];
        return max;
    }

    public void addCellComms(int i, int j)    //berekent alle kosten en voegt ze aan bestaande kosten toe.
    {
        int n, e, s, w;
        if(!validNode(i, j)){return;}
        else{
            if(validNode(i-1, j)){            //is noord geldig?
                n = nodes[i-1][j];            //dan heeft ie zelf een kleur
                if(n != nodes[i][j]){hs[nodes[i][j]]++; hr[n]++;} //vergelijk hem met de andere(n) en pas eventueel kosten aan.
            }
            else n = nodes[i][j];             //als ie niet geldig is krijgt ie dezelfde kleur als de middencel.
            
       /*********
         Dit ook voor oost-, zuid- en westcel doen:
       *********/

            if(validNode(i, j+1)){
                e = nodes[i][j+1];
                if(e != nodes[i][j] && e != n){hs[nodes[i][j]]++; hr[e]++;}
            }
            else e = nodes[i][j];

            if(validNode(i+1, j)){
                s = nodes[i+1][j];
                if(s != nodes[i][j] && s != e && s != n){hs[nodes[i][j]]++; hr[s]++;}
            }
            else s = nodes[i][j];
            
            if(validNode(i, j-1)){
                w = nodes[i][j-1];
                if(w != nodes[i][j] && w != s && w != e && w != n){hs[nodes[i][j]]++; hr[w]++;}
            }
        }
    }

    public void substractCellComms(int i, int j)//berekent alle kosten en trekt ze van bestaande kosten af.
    {
        int n, e, s, w;
        if(!validNode(i, j)){}
        else{
            if(validNode(i-1, j)){            //is noord geldig?
                n = nodes[i-1][j];            //dan heeft ie zelf een kleur
                if(n != nodes[i][j]){hs[nodes[i][j]]--; hr[n]--;} //vergelijk hem met de andere(n) en pas eventueel kosten aan.
            }
            else n = nodes[i][j];             //als ie niet geldig is krijgt ie dezelfde kleur als de middencel.
            
       /*********
         Dit ook voor oost-, zuid- en westcel doen:
       *********/

            if(validNode(i, j+1)){
                e = nodes[i][j+1];
                if(e != nodes[i][j] && e != n){hs[nodes[i][j]]--; hr[e]--;}
            }
            else e = nodes[i][j];

            if(validNode(i+1, j)){
                s = nodes[i+1][j];
                if(s != nodes[i][j] && s != e && s != n){hs[nodes[i][j]]--; hr[s]--;}
            }
            else s = nodes[i][j];
            
            if(validNode(i, j-1)){
                w = nodes[i][j-1];
                if(w != nodes[i][j] && w != s && w != e && w != n){hs[nodes[i][j]]--; hr[w]--;}
            }
        }
    }

    public double compCosts(double g)      //g is maat voor communicatiekosten
    {
        int celsPerProc[] = new int[proc]; // bevat straks het aantal cellen per processor
        for(int i = 0; i < proc; i++)
        {
            hs[i] = 0;                    // zet oude kosten op nul zodat nieuwe bepaald kunnen worden.
            hr[i] = 0;
        }

        for(int i = 0; i < size; i++)
        for(int j = 0; j < size; j++){
            addCellComms(i, j);            // tel kosten voor ieder cel uit het grid op bij reeds bestaande kosten.
	    celsPerProc[nodes[i][j]]++;
	}

        int maxs = findMax(hs);
        int maxr = findMax(hr);
        int maxp = findMax(celsPerProc);

        return (double) 5*maxp + g*(double)Math.max(maxs, maxr); // Vul kostenfunctie in en retourneer.
    }

    public double optimize(double g, double T, int period)
    {
        int b, bi=0, bj=0;  //buur-identifier (n-o-z-w) , buur-coordinaten.
        double kostenverschil = 0;
        for(int i = 0; i < period; i++){
            int ci = (int)(Math.random()*size);  // bepaal middenpunt
            int cj = (int)(Math.random()*size);
            do{
                b  = (int)(Math.random()*4);
                switch(b){
                    case 0 : bi = ci-1; bj = cj; break; // noord
                    case 1 : bi = ci; bj = cj+1; break; // oost
                    case 2 : bi = ci+1; bj = cj; break; // zuid
                    case 3 : bi = ci; bj = cj-1; break; // west
                }
            } while(!validNode(bi, bj)); //zoek een buurcel totdat je een geldige hebt gevonden

            switch(b){ // roep de bewuste wisselmethode aan, afh. van welke buurcel je hebt. 
                case 0 : kostenverschil += swapVertical(bi, bj, g, T); break; 
                case 1 : kostenverschil += swapHorizontal(ci, cj, g, T); break;
                case 2 : kostenverschil += swapVertical(ci, cj, g, T); break;
                case 3 : kostenverschil += swapHorizontal(bi, bj, g, T); break;
            }
        }
        return kostenverschil;
    }


/* horizontal swapping layout:
  _____
__|1|2|__
|3|4|5|6|
  |7|8| 
*/

    public double swapHorizontal(int i, int j, double g, double T)//i, j zijn coords van linkercel (4)
    {
    //*********** zend en ontvangst array back-up'en
        int hs_backup[] = new int[hs.length];
        int hr_backup[] = new int[hr.length];
        System.arraycopy(hs, 0, hs_backup, 0, hs.length);
        System.arraycopy(hr, 0, hr_backup, 0, hr.length);
    //*********** De kosten van de acht betrokken cellen aftrekken
        if(validNode(i-1, j)){  substractCellComms(i-1, j);    // 1
        /*als 1 bestaat, 2 ook*/substractCellComms(i-1, j+1);} // 2
        if(validNode(i, j-1))   substractCellComms(i, j-1);    // 3
                                substractCellComms(i, j);      // 4 (bronpunt)
                                substractCellComms(i, j+1);    // 5 (meewisselaar) 
        if(validNode(i, j+2))   substractCellComms(i, j+2);    // 6
        if(validNode(i+1, j)){  substractCellComms(i+1, j);    // 7
        /*als 7 bestaat, 8 ook*/substractCellComms(i+1, j+1);} // 8
    //*********** De cellen wisselen
        int temp = nodes[i][j];
        nodes[i][j] = nodes[i][j+1];
        nodes[i][j+1] = temp;
    //*********** en de NIEUWE kosten optellen
        if(validNode(i-1, j)){  addCellComms(i-1, j);          // 1
                                addCellComms(i-1, j+1);}       // 2
        if(validNode(i, j-1))   addCellComms(i, j-1);          // 3
                                addCellComms(i, j);            // 4 (bronpunt)
                                addCellComms(i, j+1);          // 5 (meewisselaar)
        if(validNode(i, j+2))   addCellComms(i, j+2);          // 6
        if(validNode(i+1, j)){  addCellComms(i+1, j);          // 7
                                addCellComms(i+1, j+1);}       // 8
    //*********** Nu nieuwe kosten vergelijken met backup van oude
        int max_old = Math.max(findMax(hs_backup), findMax(hr_backup));
        int max_new = Math.max(findMax(hs       ), findMax(hr       ));
        if(max_new >= max_old){
    //********** Kosten zijn vergroot: p = e^(K_voor-K_na)/T
            double p = Math.exp(g*(double)(max_old-max_new)/T);
            if(Math.random() > p){
    //********** Neem random getal, als r>p, dan alsnog wisseling ongedaan maken.
                nodes[i][j+1] = nodes[i][j];
                nodes[i][j] = temp;
                System.arraycopy(hs_backup, 0, hs, 0, hs_backup.length);
                System.arraycopy(hr_backup, 0, hr, 0, hr_backup.length);
                return 0;
            }
        }
        return g*(double)(max_new - max_old);
    }

/* vertical swapping layout:
  ___
__|1|__
|2|3|4|
|5|6|7|
  |8| 
*/
    public double swapVertical(int i, int j, double g, double T)
    {
    //*********** zend en ontvangst array back-up'en
        int hs_backup[] = new int[hs.length];
        int hr_backup[] = new int[hr.length];
        System.arraycopy(hs, 0, hs_backup, 0, hs.length);
        System.arraycopy(hr, 0, hr_backup, 0, hr.length);
    //*********** De kosten van de acht betrokken cellen aftrekken
        if(validNode(i-1, j))   substractCellComms(i-1, j);    // 1
        if(validNode(i, j-1)){  substractCellComms(i, j-1);    // 2
        /*als 2 bestaat, 5 ook*/substractCellComms(i+1, j-1);} // 5
                                substractCellComms(i, j);      // 3(bronpunt)
        if(validNode(i, j+1)){  substractCellComms(i, j+1);    // 4
        /*als 4 bestaat, 7 ook*/substractCellComms(i+1, j+1);} // 7
                                substractCellComms(i+1, j);    // 6(meewisselaar)
        if(validNode(i+2, j))   substractCellComms(i+2, j);    // 8
    //*********** De cellen wisselen
        int temp = nodes[i][j];
        nodes[i][j] = nodes[i+1][j];
        nodes[i+1][j] = temp;
    //*********** en de NIEUWE kosten optellen
        if(validNode(i-1, j))   addCellComms(i-1, j);          // 1
        if(validNode(i, j-1)){  addCellComms(i, j-1);          // 2
                                addCellComms(i+1, j-1);}       // 5
                                addCellComms(i, j);            // 3(bronpunt)
        if(validNode(i, j+1)){  addCellComms(i, j+1);          // 4
                                addCellComms(i+1, j+1);}       // 7
                                addCellComms(i+1, j);          // 6(meewisselaar)
        if(validNode(i+2, j))   addCellComms(i+2, j);          // 8
    //*********** Nu nieuwe kosten vergelijken met backup van oude
        int max_old = Math.max(findMax(hs_backup), findMax(hr_backup));
        int max_new = Math.max(findMax(hs       ), findMax(hr       ));
        if(max_new >= max_old){
    //********** Kosten zijn vergroot: p = e^(K_voor-K_na)/T
            double p = Math.exp(g*(double)(max_old-max_new)/T);
            if(Math.random() > p){
    //********** Neem random getal, als r>p, dan alsnog wisseling ongedaan maken.
                nodes[i+1][j] = nodes[i][j];
                nodes[i][j] = temp;
                System.arraycopy(hs_backup, 0, hs, 0, hs_backup.length);
                System.arraycopy(hr_backup, 0, hr, 0, hr_backup.length);
                return 0;
            }
        }
	return g*(double)(max_new - max_old);
    }
}