// Cluster-size distribution, Evgeny Demidov 14 Nov 2001 import java.awt.*; import java.awt.event.*; public class @file extends java.applet.Applet implements MouseListener, ItemListener, KeyListener, ActionListener{ int L = 25,L1, d, w, maxColor = 18, hd, hBut = 30, nSpan, nFin, avW, iter, cl[][], np[], size[], distr[], maxCl = 100000, periodic = 0; double p = .5, ss, ss2, avP, avS, Pi, Si; Image buffImage; Graphics buffGraphics; Color col[]; boolean painted = false, ln = true; Checkbox cbLn; Button btClear, btPrint; Choice chL,chB; Label lbL, lbP; TextField tfP; long generTime; public void init() { w = getSize().width - 150; cl = new int[w+1][w]; np = new int[maxCl]; size = new int[maxCl]; distr = new int[w]; String s=getParameter("L"); if (s != null) L = Integer.parseInt(s); d = w/L; hd = w-d; L1 = L+1; s=getParameter("p"); if (s != null) p = Double.valueOf(s).doubleValue(); col = new Color[maxColor]; col[0] = Color.red; col[3] = new Color(0,200,0); col[6] = Color.blue; col[9] = new Color(220,220,0); col[12] = new Color(0,220,220); col[15] = new Color(255,0,255); col[1] = new Color(255,150,150); col[4] = new Color(120,255,120); col[7] = new Color(150,150,255); col[10] = new Color(255,255,120); col[13] = new Color(120,255,255); col[16] = new Color(255,150,255); for (int i = 0; i < 18; i += 3) col[i+2] = col[i].darker(); buffImage = createImage(w, w); buffGraphics = buffImage.getGraphics(); addMouseListener(this); lbP = new Label("p"); add(lbP); tfP = new TextField( "" + (float)p, 5); add(tfP); tfP.addKeyListener(this); chL = new Choice(); if (w == 400) for (int i = 0, l = 25; i < 5; i++){ chL.addItem(Integer.toString(l)); l *= 2;} else for (int i = 0, l = 20; i < 6; i++){ chL.addItem(Integer.toString(l)); l *= 2;}; chL.select(""+L); chL.addItemListener(this); lbL = new Label("L"); add(lbL); add(chL); chB = new Choice(); chB.addItem("square "); chB.addItem("cylinder"); chB.addItem("torus "); chB.select(periodic); chB.addItemListener(this); add(chB); cbLn = new Checkbox("ln",ln); add(cbLn); cbLn.addItemListener(this); btClear = new Button("Clear"); btClear.addActionListener(this); add(btClear); btPrint = new Button("Print"); btPrint.addActionListener(this); add(btPrint); } public void destroy() { removeMouseListener(this); } public void mouseClicked(MouseEvent e){} // event handling public void mousePressed(MouseEvent e) { if ( e.isAltDown() ) iter = 100; painted = false; repaint(); e.consume(); } public void mouseReleased(MouseEvent e){} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void keyTyped(KeyEvent e){} public void keyPressed(KeyEvent e){} public void keyReleased(KeyEvent e){ final int keyEnter = 10; if (e.getKeyCode() == keyEnter){ try{ p = Double.valueOf(tfP.getText()).doubleValue(); }catch(NumberFormatException ne){} for (int i = 0; i < 400; i++) distr[i] = 0; avW = 0; avP = avS = 0.; painted = false; repaint(); } e.consume(); } public void actionPerformed(ActionEvent e){ if ( e.getActionCommand().equals("Clear") ){ for (int i = 0; i < 400; i++) distr[i] = 0; avW = 0; avP = avS = 0.; showStatus( "avr="+ distr[0]);} if ( e.getActionCommand().equals("Print") ){ showStatus( "p="+ (float)p +" W="+ (float)avW/distr[0] + " P="+ (float)avP/distr[0] + " S="+ (float)avS/distr[0] +" avr="+ distr[0] ); System.out.println(""+ (float)p +" "+ (float)avW/distr[0] + " "+ (float)avP/distr[0] + " "+ (float)avS/distr[0] ); for (int i = 1; i < 400; i++){ int di = distr[i]; if ( ln ){ if ( di > 0 ) System.out.println(""+i+" "+(float)Math.log(di/((double)distr[0]*L*L)) ); else System.out.println(""+i+" -20");} else System.out.println(""+i+" "+ di/((float)distr[0]*L*L) );}} } public void itemStateChanged(ItemEvent e){ L = Integer.parseInt(chL.getSelectedItem()); d = w/L; hd = w-d; L1 = L+1; periodic = chB.getSelectedIndex(); ln = cbLn.getState(); for (int i = 0; i < 400; i++) distr[i] = 0; avW = 0; avP = avS = 0.; painted = false; repaint(); } public void paint(Graphics g) { do{ if ( !painted || (iter > 0) ){ generTime = System.currentTimeMillis(); showStatus( "labeling clusters"); buffGraphics.setColor(Color.white); buffGraphics.fillRect(0, 0, w, w); for (int i = 0; i < maxCl; i++) size[i] = np[i] = 0; for (int i = 0; i < L1; i++) for (int j = 0; j < L; j++) cl[i][j] = -1; int newCl = 1, maxCl_1 = maxCl-1; for (int i = 1; i < L1; i++){ int leftCl = -1; for (int j = 0; j < L; j++){ if ( Math.random() > p){ leftCl = -1; continue;} int downCl = cl[i-1][j]; if ( downCl == -1){ if (leftCl == -1){ leftCl = cl[i][j] = newCl; if (newCl < maxCl_1) newCl++;} else cl[i][j] = leftCl;} else{ downCl = proper(downCl); if (leftCl == -1){ leftCl = cl[i][j] = downCl; continue;} if (leftCl == downCl){ cl[i][j] = leftCl; continue;} if (leftCl < downCl) cl[i][j] = np[downCl] = leftCl; else{ cl[i][j] = np[leftCl] = downCl; leftCl = downCl;}} }} int clA, clB, L_1 = L-1; if (periodic > 0){ for (int i = 1; i < L1; i++) if (((clA = cl[i][0]) != -1)&&((clB = cl[i][L_1]) != -1)) if ((clA = proper(clA)) != (clB = proper(clB))) if (clA > clB) np[clA] = clB; else np[clB] = clA;} int percCl = -1, topCl; boolean isPercolating = false; perc: for (int i = 0; i < L; i++){ if ((percCl = cl[1][i]) == -1) continue; percCl = proper(percCl); for (int j = 0; j < L; j++){ if ((topCl = cl[L][j]) != -1) if (percCl == proper(topCl)){ isPercolating = true; avW++; break perc;}}} if (periodic > 1){ for (int i = 0; i < L; i++) if (((clA = cl[1][i]) != -1)&&((clB = cl[L][i]) != -1)) if ((clA = proper(clA)) != (clB = proper(clB))) if (clA > clB) np[clA] = clB; else np[clB] = clA; if ( isPercolating ) percCl = proper(percCl);} showStatus( "drawing avr="+ distr[0]); nSpan = nFin = 0; ss = ss2 = 0; for (int i = 0; i < L; i++){ for (int j = 0; j < L; j++){ int c = cl[i+1][j]; if ( c > 0){ c = proper(c); if ( isPercolating && (c == percCl)){ nSpan++; buffGraphics.setColor(Color.black);} else{ nFin++; size[c]++; buffGraphics.setColor(col[c % maxColor]);} buffGraphics.fillRect(j*d,hd-i*d, d,d);} }} for (int i = 0; i < maxCl; i++){ int s = size[i]; if (s > 0){ ss += s; ss2 += (double)s*s; if (s < 400) distr[s]++;}} distr[0]++; Pi = (double)nSpan/(nSpan+nFin); avP += Pi; Si = ss2/ss; avS += Si; generTime = System.currentTimeMillis() - generTime; painted = true;} g.setColor(Color.white); g.fillRect(w,30, 150,w); g.drawImage(buffImage, 0, hBut, this); double m = 149.0/distr[1]; if ( ln ) m = 149/Math.log((double)distr[1]/distr[0]); g.setColor(Color.red); int dy = 2; if (w == 640) dy = 3; for (int i = 1; i < 200; i++){ int di = distr[i], x; if (di != 0){ if ( ln ){ x = (int)(m*Math.log((double)di/distr[0])); if ( x < 0 ) x = 0; x += w;} else x = w + (int)(m*di); g.drawLine(x, dy*(i-1)+30, x, dy*i+30); } } showStatus( "p="+ (float)p +" P="+ (float)Pi +" S="+ (float)Si +" avr="+ distr[0] +" n1="+ ((float)distr[1])/(distr[0]*L*L) +" t="+ generTime +"ms"); }while( --iter > 0); } public int proper(int label ){ int l; while( (l = np[label]) != 0) label = l; return label; } public void update(Graphics g){ paint(g); } }