/* * xquantum (macOS/XQuartz-friendly cleanup) * * Original: Oliver Knill, public domain. * This OS X version modernizes declarations/prototypes and removes a few * non-portable headers so it builds cleanly with clang on macOS. * * Build on macOS (requires XQuartz): * clang -O2 -Wall -Wextra -o xquantum xquantum_osx.c \ * -I/opt/X11/include -L/opt/X11/lib -lX11 -lm * * Or, if you have pkg-config: * clang -O2 -Wall -Wextra -o xquantum xquantum_osx.c \ * $(pkg-config --cflags --libs x11) -lm * * Run: * ./xquantum file.ppm * ./xquantum 1000 file.ppm - version: 22 April 2000, 20 March 2001 add movie export, December 5 2025: removed again as it does no more work 2025, February 11, 2026: This file: Adaptation to OS X by GPT 5.2. - The x-interface was adapted from "xfires" by Michael Creutz creutz@wind.phy.bnl.gov Check out http://thy.phy.bnl.gov/www/xtoys/xtoys.html for other nifty X programs which are (besides incredibly nice "toys") excellent templates for xwindows programs. - The discrete quantum evolution used here was introduced in the paper: O. Knill, "A remark on quantum dynamics", Helvetica Physica Acta, 71, 233-241, 1998 the idea is to replace exp(i t L) by exp(i t H), where cos(L)=H. The exponential becomes then a polynomial, the evolution becomes a "coupled map lattice" (= cellular automaton with continuous state space). - the red and blue color channel in file.ppm represents the wave amplitude, the green color channel implements the Dirichlet boundary condition. */ #include #include #include #include #include #include #include #include #include #define PLAYTOP 120 #define PLAYLEFT 14 #define AMP 20.0f /* [-AMP, AMP] maps to [0,255] */ static char stringbuffer[256]; static Display *display_ = NULL; static int screen_ = 0; static const char *progname_ = NULL; static Window window_ = 0; static Window quitbutton_ = 0; static Window reset_button_ = 0; static Window playground_ = 0; static Colormap cmap_ = 0; static GC gc_ = 0; static GC gcpen_ = 0; static int windowwidth_ = 0; static int windowheight_ = 0; static XFontStruct *font_ = NULL; static int font_height_ = 0; static int font_width_ = 0; static XSizeHints size_hints_; static int darkcolor_ = 0; static int lightcolor_ = 0; static int black_ = 0; static int white_ = 0; static XImage *spinimage_ = NULL; static int reset_ = 0; /* Simulation buffers */ static float *image_ = NULL; static float *image1_ = NULL; static float *current_ = NULL; static float *next_ = NULL; static int x_size_ = 0; static int y_size_ = 0; static int c_size_ = 0; static int now_ = 1; static int it_ = 0; /* Forward declarations (proper prototypes) */ static void openwindow(int argc, char **argv); static void makebuttons(void); static Window makebutton(int xoffset, int yoffset, int xsize, int ysize); static void drawbutton(Window bwindow, int xoffset, int yoffset, int xsize, int ysize, const char *text, int state); static void repaint(void); static void clean_up(void); static void showpic(void); static void quantum_step(void); static void read_ppm_image(const char *filename); static unsigned long color_trans(float r, float g, float b); static inline float color_to_real(int n) { return (AMP / 127.0f) * ((float)n - 127.0f); } static inline unsigned char real_to_color(float r) { int l = (int)floorf((2.0f * r * 127.0f / AMP) + 127.00000001f); if (l > 255) l = 255; if (l < 0) l = 0; return (unsigned char)l; } static inline float dirichlet(float x) { return (x > 5.0f) ? 0.0f : 1.0f; } int main(int argc, char **argv) { int i, j, jj; int time = 0; int frames = 1000; int interupt = 10; float *ptr, *ptr1; const char *filename = NULL; XEvent report; progname_ = (argc > 0 && argv && argv[0]) ? argv[0] : "xquantum"; if ((argc != 2) && (argc != 3)) { fprintf(stderr, "Usage: xquantum \n" " or: xquantum \n"); return 1; } if (argc == 2) { filename = argv[1]; } else { frames = atoi(argv[1]); filename = argv[2]; } read_ppm_image(filename); current_ = image_; next_ = image1_; openwindow(argc, argv); makebuttons(); while (time / interupt < frames) { if (reset_ == 1) { read_ppm_image(filename); now_ = 1; reset_ = 0; } if (now_ == 1) { current_ = image_; next_ = image1_; } else { current_ = image1_; next_ = image_; } now_ = 1 - now_; time++; quantum_step(); if (XPending(display_)) { XNextEvent(display_, &report); /* something happened */ switch (report.type) { case Expose: /* picture was covered */ if (report.xexpose.window != window_) break; if (report.xexpose.count != 0) break; repaint(); break; case ConfigureNotify: /* user resized picture (ignored; fixed-size UI) */ break; case ButtonPress: if (report.xbutton.window == quitbutton_) { clean_up(); } else if (report.xbutton.window == reset_button_) { reset_ = 1; drawbutton(reset_button_, 0, 0, 60, 18, "reset", -(1 - 2 * reset_)); } else { /* clicked in picture */ i = report.xbutton.x; j = report.xbutton.y; if (i >= 0 && i < x_size_ && j >= 0 && j < y_size_) { jj = j * x_size_; ptr = current_ + 3 * (jj + i); ptr1 = next_ + 3 * (jj + i); *ptr = AMP / 10.0f; *ptr1 = AMP / 10.0f; } } break; default: break; } } it_++; if (it_ % 25 == 0) { /* show some information */ ptr = current_ + 3 * (30 * x_size_ + 50); ptr1 = next_ + 3 * (30 * x_size_ + 50); snprintf(stringbuffer, sizeof(stringbuffer), "%d iterations", it_); XDrawImageString(display_, window_, gc_, 8, 62, stringbuffer, (int)strlen(stringbuffer)); snprintf(stringbuffer, sizeof(stringbuffer), "phi=%f,psi=%f", (double)*ptr, (double)*ptr1); XDrawImageString(display_, window_, gc_, 8, 82, stringbuffer, (int)strlen(stringbuffer)); } } clean_up(); return 0; } static void showpic(void) { int i, j, jj; const float *phi; const float *psi; const float *eta; if (!spinimage_) return; for (i = 0; i < x_size_; i++) { for (j = 0; j < y_size_; j++) { jj = j * x_size_; phi = current_ + 3 * (jj + i); psi = phi + 1; eta = phi + 2; XPutPixel(spinimage_, i, j, color_trans(*phi, *psi, *eta)); } } XPutImage(display_, playground_, gc_, spinimage_, 0, 0, 0, 0, (unsigned int)x_size_, (unsigned int)y_size_); } static void repaint(void) { drawbutton(quitbutton_, 0, 0, 68, 18, "quit", 1); drawbutton(reset_button_, 0, 0, 60, 18, "reset", 1 - 2 * reset_); drawbutton(window_, PLAYLEFT - 4, PLAYTOP - 4, x_size_ + 8, y_size_ + 8, NULL, 4); snprintf(stringbuffer, sizeof(stringbuffer), "%d by %d lattice ", x_size_ - 2, y_size_ - 2); XDrawImageString(display_, window_, gc_, 14, 100, stringbuffer, (int)strlen(stringbuffer)); showpic(); } static void openwindow(int argc, char **argv) { const char *window_name = "xquantum"; const char *icon_name = "xquantum"; long event_mask; Pixmap icon_pixmap; const char *display_name = NULL; #define icon_bitmap_width 16 #define icon_bitmap_height 16 static const unsigned char icon_bitmap_bits[] = { 0x1f, 0xf8, 0x1f, 0x88, 0x1f, 0x88, 0x1f, 0x88, 0x1f, 0x88, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; display_ = XOpenDisplay(display_name); if (display_ == NULL) { fprintf(stderr, "%s: cannot connect to X server %s\n", progname_, XDisplayName(display_name)); exit(1); } screen_ = DefaultScreen(display_); cmap_ = DefaultColormap(display_, screen_); /* Original code swaps these; keep behavior */ darkcolor_ = black_ = WhitePixel(display_, screen_); lightcolor_ = white_ = BlackPixel(display_, screen_); { XColor xcolor, colorcell; if (XAllocNamedColor(display_, cmap_, "#0000ff", &colorcell, &xcolor)) darkcolor_ = (int)colorcell.pixel; if (XAllocNamedColor(display_, cmap_, "#000044", &colorcell, &xcolor)) lightcolor_ = (int)colorcell.pixel; } windowwidth_ = x_size_ + PLAYLEFT + 16; windowheight_ = PLAYTOP + y_size_ + 10; window_ = XCreateSimpleWindow(display_, RootWindow(display_, screen_), 0, 0, (unsigned int)windowwidth_, (unsigned int)windowheight_, 4, (unsigned long)black_, (unsigned long)lightcolor_); icon_pixmap = XCreateBitmapFromData(display_, window_, (const char *)icon_bitmap_bits, icon_bitmap_width, icon_bitmap_height); size_hints_.flags = PPosition | PSize | PMinSize; size_hints_.min_width = windowwidth_; size_hints_.min_height = windowheight_ - 160; { XWMHints wm_hints; XClassHint class_hints; XTextProperty windowName, iconName; /* XStringListToTextProperty wants char** */ char *wn = (char *)window_name; char *in = (char *)icon_name; if (XStringListToTextProperty(&wn, 1, &windowName) == 0) { fprintf(stderr, "%s: structure allocation for windowName failed.\n", progname_); exit(1); } if (XStringListToTextProperty(&in, 1, &iconName) == 0) { fprintf(stderr, "%s: structure allocation for iconName failed.\n", progname_); exit(1); } wm_hints.initial_state = NormalState; wm_hints.input = True; wm_hints.icon_pixmap = icon_pixmap; wm_hints.flags = StateHint | IconPixmapHint | InputHint; class_hints.res_name = (char *)progname_; class_hints.res_class = (char *)"Basicwin"; XSetWMProperties(display_, window_, &windowName, &iconName, argv, argc, &size_hints_, &wm_hints, &class_hints); } event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask; XSelectInput(display_, window_, event_mask); font_ = XLoadQueryFont(display_, "9x15"); if (font_ == NULL) font_ = XLoadQueryFont(display_, "fixed"); if (font_ == NULL) { fprintf(stderr, "%s: Sorry, having font problems.\n", progname_); exit(1); } font_height_ = font_->ascent + font_->descent; font_width_ = font_->max_bounds.width; gc_ = XCreateGC(display_, window_, 0, NULL); XSetFont(display_, gc_, font_->fid); XSetForeground(display_, gc_, (unsigned long)black_); XSetBackground(display_, gc_, (unsigned long)lightcolor_); gcpen_ = XCreateGC(display_, window_, 0, NULL); XSetFont(display_, gcpen_, font_->fid); XSetForeground(display_, gcpen_, (unsigned long)darkcolor_); XSetBackground(display_, gcpen_, (unsigned long)lightcolor_); XMapWindow(display_, window_); } static void makebuttons(void) { long event_mask; XEvent report; Cursor cursor; XWindowAttributes attr; XDestroySubwindows(display_, window_); quitbutton_ = makebutton(4, 4, 68, 18); reset_button_ = makebutton(70 + 8, 4, 70, 18); playground_ = XCreateSimpleWindow(display_, window_, PLAYLEFT, PLAYTOP, (unsigned int)x_size_, (unsigned int)y_size_, 0, (unsigned long)black_, (unsigned long)white_); event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask | PointerMotionHintMask | ButtonMotionMask; XSelectInput(display_, playground_, event_mask); XMapWindow(display_, playground_); /* Wait until the playground window is actually exposed */ for (;;) { XNextEvent(display_, &report); if (report.type == Expose && report.xexpose.window == playground_) break; } if (spinimage_ != NULL) { XDestroyImage(spinimage_); spinimage_ = NULL; } /* Get the real size the server ended up using */ XGetWindowAttributes(display_, playground_, &attr); unsigned int w = (unsigned int)attr.width; unsigned int h = (unsigned int)attr.height; spinimage_ = XGetImage(display_, playground_, 0, 0, w, h, AllPlanes, ZPixmap); if (spinimage_ == NULL) { fprintf(stderr, "trouble creating image\n"); exit(1); } cursor = XCreateFontCursor(display_, XC_sb_left_arrow); XDefineCursor(display_, playground_, cursor); cursor = XCreateFontCursor(display_, XC_hand2); XDefineCursor(display_, quitbutton_, cursor); XDefineCursor(display_, reset_button_, cursor); repaint(); } static Window makebutton(int xoffset, int yoffset, int xsize, int ysize) { Window bwindow; long event_mask; bwindow = XCreateSimpleWindow(display_, window_, xoffset, yoffset, (unsigned int)xsize, (unsigned int)ysize, 0, (unsigned long)black_, (unsigned long)lightcolor_); event_mask = ButtonPressMask | ExposureMask; XSelectInput(display_, bwindow, event_mask); XMapWindow(display_, bwindow); return bwindow; } static void drawbutton(Window bwindow, int xoffset, int yoffset, int xsize, int ysize, const char *text, int state) { int textlength, i, j; int cdark, clight, cup, cdown; int cleft, cright, cbutton, ctext; cup = lightcolor_; cdown = darkcolor_; cdark = black_; clight = white_; if (state < 0) { cbutton = cdown; ctext = clight; cleft = cdark; cright = clight; } else { cbutton = cup; ctext = cdark; cleft = clight; cright = cdark; } j = abs(state); XSetForeground(display_, gcpen_, (unsigned long)cbutton); XFillRectangle(display_, bwindow, gcpen_, xoffset + j, yoffset + j, (unsigned int)(xsize - 2 * j), (unsigned int)(ysize - 2 * j)); XSetForeground(display_, gcpen_, (unsigned long)cleft); XFillRectangle(display_, bwindow, gcpen_, xoffset, yoffset, (unsigned int)xsize, (unsigned int)j); XFillRectangle(display_, bwindow, gcpen_, xoffset, yoffset, (unsigned int)j, (unsigned int)ysize); XSetForeground(display_, gcpen_, (unsigned long)cright); for (i = 0; i < j; i++) { XDrawLine(display_, bwindow, gcpen_, xoffset + i, yoffset + ysize - i - 1, xoffset + xsize - i - 1, yoffset + ysize - i - 1); XDrawLine(display_, bwindow, gcpen_, xoffset + xsize - i - 1, yoffset + i, xoffset + xsize - i - 1, yoffset + ysize - i - 1); } if (text != NULL) { textlength = (int)strlen(text); XSetForeground(display_, gcpen_, (unsigned long)ctext); XDrawString(display_, bwindow, gcpen_, xoffset + (xsize - textlength * font_width_) / 2, yoffset + (ysize + font_height_) / 2 - 2, text, textlength); } } static void clean_up(void) { if (display_ != NULL) { if (font_ != NULL) XUnloadFont(display_, font_->fid); if (gc_ != 0) XFreeGC(display_, gc_); if (gcpen_ != 0) XFreeGC(display_, gcpen_); } if (spinimage_ != NULL) { XDestroyImage(spinimage_); spinimage_ = NULL; } if (display_ != NULL) { XCloseDisplay(display_); display_ = NULL; } free(image_); image_ = NULL; free(image1_); image1_ = NULL; exit(0); } static void quantum_step(void) { int i, j; int i_right, j_right; int i_left, j_left; int i_up, j_up; int i_low, j_low; float *phi_cen, *phi_up, *phi_low, *phi_left, *phi_right; float *psi_cen; float *eta_cen; float *phi1, *psi1, *eta1; for (j = 0; j < y_size_; j++) { for (i = 0; i < x_size_; i++) { i_right = (i + 1) % x_size_; j_right = j; i_left = (i - 1 + x_size_) % x_size_; j_left = j; j_up = (j + 1) % y_size_; i_up = i; j_low = (j - 1 + y_size_) % y_size_; i_low = i; /* fixed wrap for y */ (void)j_right; (void)j_left; (void)i_up; (void)i_low; /* silence unused */ phi_cen = current_ + 3 * (j * x_size_ + i); phi_up = current_ + 3 * (j_up * x_size_ + i_up); phi_low = current_ + 3 * (j_low * x_size_ + i_low); phi_left = current_ + 3 * (j_left * x_size_ + i_left); phi_right = current_ + 3 * (j_right* x_size_ + i_right); psi_cen = phi_cen + 1; eta_cen = phi_cen + 2; phi1 = next_ + 3 * (j * x_size_ + i); psi1 = phi1 + 1; eta1 = phi1 + 2; *phi1 = (((*phi_right + *phi_left + *phi_up + *phi_low) / 2.0f) - *eta_cen) * dirichlet(*psi_cen); *psi1 = *psi_cen; *eta1 = (*phi_cen) * dirichlet(*psi_cen); } } showpic(); } static void read_ppm_image(const char *filename) { FILE *in; int i; char buffer[1025]; in = fopen(filename, "rb"); if (in == NULL) { fprintf(stderr, "Can't open file %s\n", filename); exit(1); } if (!fgets(buffer, (int)sizeof(buffer), in)) { fprintf(stderr, "Unsupported file format (need PPM raw)\n"); exit(1); } /* Expect P6 */ if (strncmp(buffer, "P6", 2) != 0) { fprintf(stderr, "Unsupported file format (need P6 PPM)\n"); exit(1); } /* Skip comments to read width/height */ do { if (!fgets(buffer, (int)sizeof(buffer), in)) { fprintf(stderr, "Unexpected EOF while reading PPM size\n"); exit(1); } } while (buffer[0] == '#'); x_size_ = atoi(strtok(buffer, " \t\r\n")); y_size_ = atoi(strtok(NULL, " \t\r\n")); if (x_size_ <= 0 || y_size_ <= 0) { fprintf(stderr, "Invalid image size\n"); exit(1); } if (!fgets(buffer, (int)sizeof(buffer), in)) { fprintf(stderr, "Unexpected EOF while reading PPM maxval\n"); exit(1); } c_size_ = atoi(buffer); if (c_size_ <= 0 || c_size_ > 255) { fprintf(stderr, "Invalid max color value in PPM file\n"); exit(1); } free(image_); free(image1_); image_ = NULL; image1_ = NULL; image_ = (float *)malloc((size_t)(3 * x_size_ * y_size_ + 1) * sizeof(float)); if (image_ == NULL) { fprintf(stderr, "Can't load image (memory allocation error)\n"); exit(1); } i = 0; while (i < 3 * x_size_ * y_size_) { int c = fgetc(in); if (c == EOF) break; image_[i++] = color_to_real(c); } fclose(in); if (i < 3 * x_size_ * y_size_) { fprintf(stderr, "Premature end of image\n"); exit(1); } image1_ = (float *)malloc((size_t)(3 * x_size_ * y_size_ + 1) * sizeof(float)); if (image1_ == NULL) { fprintf(stderr, "Memory allocation error\n"); exit(1); } /* Note: image1_ contents will be overwritten by the first simulation step */ } static unsigned long color_trans(float r, float g, float b) { unsigned long code; float prob; int red, green, blue; /* 0xrrggbb */ if (g == color_to_real(255)) { code = (unsigned long)0xaa; /* boundary dark blue */ } else { prob = r * r + b * b; red = (int)fabsf(1.0f * b * b); if (red > 255) red = 255; blue = (int)fabsf(1.0f * r * r); if (blue > 255) blue = 255; green = (int)fabsf(0.5f * prob); if (green > 255) green = 255; code = (unsigned long)(red * 256 * 256 + green * 256 + blue); } return code; }