# Gauss-Seidel Qiang A. Zhao, October 92 # # Usage: a.out Size Workers North East South West < Color-file # # Color-file: # <# of colors> # # ... # # ... resource gauss() import MPDWin ### Var declarations/initializations const real EPSILON = 0.0001 const int MAXCV = 65535 const int MINS = 100 const int MINWK = 2 const int MINC = 2 const int SCALE = 5 const int TIMES = 100 int SIZE = MINS; getarg(1, SIZE) int WORKERS = MINWK; getarg(2, WORKERS) real North = 0.0; getarg(3, North) real East = 0.333; getarg(4, East) real South = 0.666; getarg(5, South) real West = 1.0; getarg(6, West) int passes = 0 if ((SIZE < MINS) or (WORKERS < MINWK)) { write(stderr, "Invalid arguments") stop(1) } if (SIZE mod WORKERS != 0) { write(stderr, "Number of workers must evenly divide image size.") stop(1) } const int STRIP = SIZE / WORKERS int COLORS = MINC; bool stay[WORKERS] = ([WORKERS]true) bool changed[WORKERS] = ([WORKERS]false) sem done = 0, continue[WORKERS] = ([WORKERS]0) real image[0:SIZE+1, 0:SIZE+1] winWindow mainwin winImage wim op winEventChannel ec winEvent ev ### open a window, create an image mainwin = WinOpen("", "Gauss-Seidel", ec, UseDefault, SIZE*SCALE, SIZE*SCALE) if (mainwin == null) { write(stderr, "Ouch, can't open window") stop(1) } WinSetEventMask(mainwin, Ev_KeyUp | Ev_ButtonUp) wim = WinCreateImage(mainwin, UseDefault, SIZE*SCALE, SIZE*SCALE) if (wim == null) { write(stderr, "Ouch, can't create image") stop(1) } WinFlush(mainwin) # how many colors? read(COLORS) if (COLORS < MINC) { write(stderr, "Invalid number of colors") WinClose(mainwin) stop(1) } # additional vars winWindow cwins[0:COLORS-1] winPixel cpvs[0:COLORS-1] # initialize the "constant" part of the image for [ i=0 to SIZE+1 ] { image[i, 0] = North image[i, SIZE+1] = South image[0, i] = West image[SIZE+1, i] = East } # initialize colors const int CSTRIP = SIZE*SCALE/COLORS for [ i= 0 to COLORS-1 ] { cwins[i] = WinNewContext(mainwin) if (cwins[i] == null) { write(stderr, "No enough memory... give up") WinClose(mainwin) stop(1) } ### grey-scale # int cv = MAXCV * (i+1) / COLORS # string[5] str # sprintf(str, "%04x", cv) # WinSetForeground(cwins[i], "#" || str || str || str) ### read-in colors int r, g, b string[5] sr, sg, sb read(r, g, b) sprintf(sr, "%04x", r*255) sprintf(sg, "%04x", g*255) sprintf(sb, "%04x", b*255) cpvs[i] = WinSetForeground(cwins[i], "#" || sr || sg || sb) WinFillRectangle(cwins[i], winRectangle(CSTRIP*i, 0, CSTRIP, SIZE*SCALE)) } WinFlush(mainwin) ### Worker processes to compute averages # using checkerboard partitioning process worker [ w = 1 to WORKERS ] { const int R = (w - 1) * STRIP+1 # starting row of strip const int EP = R + STRIP - 1 real tmp int phase = w mod 2 int ptmp1, ptmp2, wk, i, j for [ i= R to R+STRIP-1 ] { for [ j=1 to SIZE ] { image[i, j] = 0.0 } } P(continue[w]) while (stay[w]) { for [ wk = phase to WORKERS-1 by 2 ] { ptmp1 = wk * STRIP + 1 ptmp2 = ptmp1 + STRIP - 1 for [ i= R to EP ] { for [ j= ptmp1 to ptmp2 ] { tmp = (image[i+1, j] + image[i-1, j] + image[i, j+1] + image[i, j-1])/4.0 if (abs(tmp - image[i, j]) > EPSILON) { changed[w] = true if (passes == 0 or passes == 1) { int x = (i-1)*SCALE, y = (j-1)*SCALE for [ l = 0 to SCALE-1, k = 0 to SCALE-1 ] { WinPutPixel(wim, winPoint(x+l, y+k), cpvs[int(tmp*COLORS)]) } } } image[i, j] = tmp } } } # wk V(done) phase = (phase+1) mod 2 P(continue[w]) } V(done) # signal leave }# end of worker ### Coordinator const char Rolling[0:3] = ('-', '\\', '|', '/') int end_time int start_time winPixel lightYellow = WinSetForeground(mainwin, "LightYellow") for [ i = 0 to SIZE * SCALE - 1 ] { for [ j = 0 to SIZE * SCALE - 1 ] { WinPutPixel(wim, winPoint(i, j), lightYellow) } } writes(stderr, "Press a key in the window to start...") receive ec(ev) write(stderr) start_time = age() for [ mm = 1 to WORKERS ] { V(continue[mm]) } # wait to quit bool ac = true while (ac) { # check workers for [ k = 1 to WORKERS ] { P(done) } #writes(stderr, "\r", Rolling[passes mod 4 + 1]) if (passes == 1) { WinPutImage(mainwin, wim, winRectangle(0, 0, SIZE*SCALE, SIZE*SCALE), winPoint(0, 0)) WinFlush(mainwin) } if (ac) { # check convergence ac = false for [ k = 1 to WORKERS ] { ac = ac or changed[k]; changed[k] = false } } if (not ac) { stay = ([WORKERS] false) } passes = (passes + 1) mod TIMES for [ k = 1 to WORKERS ] { V(continue[k]) } } end_time = age() for [ k = 1 to WORKERS ] { P(done) } write(stderr) writes(stderr, "Press a key in the window to quit...") receive ec(ev) stop(0) # final code -- close connection... final { write(stderr) write(stderr, "Computation time: ", end_time - start_time) WinClose(mainwin) } end gauss