/***** syzygy.asy {{{1 * Andy Hammerlindl 2006/12/02 * * Automates the drawing of braids, relations, and syzygies, along with the * corresponding equations. * * See * http://katlas.math.toronto.edu/drorbn/index.php?title=06-1350/Syzygies_in_Asymptote * For more information. *****/ struct Component { // {{{1 // The number of strings coming in or out of the component. int in; int out; // Which 'out' string each 'in' string is connected to. For deriving // equations. int[] connections; string symbol; // For pullback notation. string lsym; // For linear equations. string codename; // For Mathematica code. guide[] draw(picture pic, guide[] ins); } // Utility functions {{{1 pair[] endpoints(guide[] a) { pair[] z; for (int i=0; i M.x) M=(z[i].x,M.y); if (z[i].y > M.y) M=(M.x,z[i].y); } return M; } // Component Definitions {{{1 real hwratio=1.4; real gapfactor=6; Component bp=new Component; bp.in=2; bp.out=2; bp.connections=new int[] {1,0}; bp.symbol="B^+"; bp.lsym="b^+"; bp.codename="bp"; bp.draw=new guide[] (picture pic, guide[] ins) { pair[] z=endpoints(ins); pair m=min(z), M=max(z); real w=M.x-m.x, h=hwratio*w; pair centre=(0.5(m.x+M.x),M.y+h/2); /* return new guide[] {ins[1]..centre{NW}..z[0]+h*N, ins[0]..centre{NE}..z[1]+h*N}; */ real offset=gapfactor*linewidth(currentpen); draw(pic, ins[1]..(centre-offset*NW){NW}); return new guide[] {(centre+offset*NW){NW}..z[0]+h*N, ins[0]..centre{NE}..z[1]+h*N}; }; Component bm=new Component; bm.in=2; bm.out=2; bm.connections=new int[] {1,0}; bm.symbol="B^-"; bm.lsym="b^-"; bm.codename="bm"; bm.draw=new guide[] (picture pic, guide[] ins) { pair[] z=endpoints(ins); pair m=min(z), M=max(z); real w=M.x-m.x, h=hwratio*w; pair centre=(0.5(m.x+M.x),M.y+h/2); /* return new guide[] {ins[1]..centre{NW}..z[0]+h*N, ins[0]..centre{NE}..z[1]+h*N}; */ real offset=gapfactor*linewidth(currentpen); draw(pic, ins[0]..(centre-offset*NE){NE}); return new guide[] {ins[1]..centre{NW}..z[0]+h*N, (centre+offset*NE){NE}..z[1]+h*N}; }; Component phi=new Component; phi.in=2; phi.out=1; phi.connections=new int[] {0,0}; phi.symbol="\Phi"; phi.lsym="\phi"; phi.codename="phi"; phi.draw=new guide[] (picture pic, guide[] ins) { pair[] z=endpoints(ins); pair m=min(z), M=max(z); real w=M.x-m.x, h=hwratio*w; pair centre=(0.5(m.x+M.x),M.y+h/2); //real offset=4*linewidth(currentpen); draw(pic, ins[0]..centre{NE}); draw(pic, ins[1]..centre{NW}); draw(pic, centre,linewidth(5*linewidth(currentpen))); dot(pic, centre); return new guide[] {centre..centre+0.5h*N}; }; Component wye=new Component; wye.in=1; wye.out=2; wye.connections=null; // TODO: Fix this! wye.symbol="Y"; wye.lsym="y"; wye.codename="wye"; wye.draw=new guide[] (picture pic, guide[] ins) { pair z=endpoint(ins[0]); real w=10, h=hwratio*w; // The 10 is a guess here, and may produce badness. pair centre=(z.x,z.y+h/2); draw(pic, ins[0]..centre); draw(pic, centre,linewidth(5*linewidth(currentpen))); return new guide[] {centre{NW}..centre+(-0.5w,0.5h), centre{NE}..centre+(0.5w,0.5h)}; }; struct Braid { // {{{1 // Members {{{2 // Number of lines initially. int n; struct Placement { Component c; int place; Placement copy() { Placement p=new Placement; p.c=this.c; p.place=this.place; return p; } } Placement[] places; void add(Component c, int place) { Placement p=new Placement; p.c=c; p.place=place; places.push(p); } void add(Braid sub, int place) { for (int i=0; i= minheight ? ins[i] : ins[i]..(z[i].x,minheight)); } } void draw(picture pic, guide[] ins, real minheight=0) { int steps=places.length; guide[] nodes=ins; for (int i=0; ij) return swap(j,i); else { assert(j==i+1); assert(swapable(places[i],places[j])); Placement p=places[i].copy(); Placement q=places[j].copy(); /*write("swap:"); write("p originally at " + (string)p.place); write("q originally at " + (string)q.place); write("p.c.in: " + (string)p.c.in + " p.c.out: " + (string)p.c.out); write("q.c.in: " + (string)q.c.in + " q.c.out: " + (string)q.c.out);*/ if (q.place + q.c.in <= p.place) // q is left of p - adjust for q renumbering strings. p.place+=q.c.out-q.c.in; else if (p.place + p.c.out <= q.place) // q is right of p - adjust for p renumbering strings. q.place+=p.c.in-p.c.out; else // q is directly on top of p assert(false, "swapable"); /*write("q now at " + (string)q.place); write("p now at " + (string)p.place);*/ Braid b=this.copy(); b.places[i]=q; b.places[j]=p; return b; } } // Tests if the component at index 'start' can be moved to index 'end' // without interfering with other components. bool moveable(int start, int end) { assert(start= sub.places.length) return true; // The next component to match. Placement p=sub.places[acc.length]; // Start looking immediately after the last match. for (int step=acc[acc.length-1]+1; step= sub.places.length) return true; // The next component to match. Placement p=sub.places[acc.length]; // Start looking immediately after the last match. for (int step=acc[acc.length-1]+1; step place && q.place < place + size) { // It's in the window, so it must match the next component in the // subbraid. if (p.c==q.c && p.place+place==q.place) { // A match - go on to the next component. acc.push(step); return tryMatch(sub, place, size, acc); // TODO: Adjust place/size. } else return false; } // TODO: Adjust place and size. } // We've run out of components to match. return false; } // This attempts to find a subbraid within the braid. It allows other // components to be interspersed with the components of the subbraid so long // as they don't occur on the same string as the ones the subbraid lies on. // Returns null on failure. int[] match(Braid sub, int place) { for (int i=0; i<=this.places.length-sub.places.length; ++i) { // Find where the first component of the subbraid matches and try to // match the rest of the braid starting from there. if (matchComponent(sub, 0, place, i)) { int[] result; result.push(i); if (tryMatch(sub,place,sub.n,result)) return result; } } return null; } // Equations {{{2 // Returns the string that 'place' moves to when going through the section // with Placement p. static int advancePast(Placement p, int place) { // If it's to the left of the component, it is unaffected. return place=0 && place=0 && step0) s+=" "; s+=stepToFormula(step); } return s; } } string windowToLinear(int step, int w_place, int w_size) { int[] a=pullbackWindow(step, w_place, w_size); string s="("; for (int arg=1; arg<=w_size+1; ++arg) { if (arg>1) s+=","; bool first=true; for (int var=0; var1) s+=", "; bool first=true; for (int var=0; var1) s+=","; bool first=true; for (int var=0; var0) s+= subtract ? " - " : " + "; s+=stepToLinear(step); } return s; } } string toCode(bool subtract=false) { if (places.length==0) return subtract ? "0" : ""; // or "1" ? else { string s = subtract ? " - " : ""; for (int step=0; step0) s+= subtract ? " - " : " + "; s+=stepToCode(step); } return s; } } } struct Relation { // {{{1 Braid lhs, rhs; string lsym, codename; bool inverted=false; string toFormula() { return lhs.toFormula() + " = " + rhs.toFormula(); } string linearName() { assert(lhs.n==rhs.n); assert(lsym!=""); string s=(inverted ? "-" : "") + lsym+"("; for (int i=1; i<=lhs.n+1; ++i) { if (i>1) s+=","; s+="x_"+(string)i; } return s+")"; } string fullCodeName() { assert(lhs.n==rhs.n); assert(codename!=""); string s=(inverted ? "minus" : "") + codename+"["; for (int i=1; i<=lhs.n+1; ++i) { if (i>1) s+=", "; s+="x"+(string)i+"_"; } return s+"]"; } string toLinear() { return linearName() + " = " + lhs.toLinear() + rhs.toLinear(true); } string toCode() { return fullCodeName() + " :> " + lhs.toCode() + rhs.toCode(true); } void draw(picture pic=currentpicture) { picture left; lhs.draw(left); frame l=left.fit(); picture right; rhs.draw(right); frame r=right.fit(); real xpad=30; add(pic, l); label(pic, "=", (max(l).x + 0.5xpad, 0.25(max(l).y+max(r).y))); add(pic, r, (max(l).x+xpad,0)); } } Relation operator- (Relation r) { Relation opposite; opposite.lhs=r.rhs; opposite.rhs=r.lhs; opposite.lsym=r.lsym; opposite.codename=r.codename; opposite.inverted=!r.inverted; return opposite; } Braid apply(Relation r, Braid b, int step, int place) { bool valid=b.exactMatch(r.lhs,place,step); if (valid) { Braid result=new Braid; result.n=b.n; for (int i=0; i M.x) M=(z.x,M.y); if (z.y > M.y) M=(M.x,z.y); } picture pic; real xpad=2.0, ypad=1.3; void place(int index, real row, real column) { pair z=((M.x*xpad)*column,(M.y*ypad)*row); add(pic, cards[index], z); if (number) { label(pic,(string)index, z+(0.5M.x,0), S); } } // Handle small collections. if (n<=4) { for (int i=0; i1) s+=","; s+="x_"+(string)i; } return s+")"; } string fullCodeName() { assert(codename!=""); string s=codename+"["; for (int i=1; i<=initial.n+1; ++i) { if (i>1) s+=", "; s+="x"+(string)i+"_"; } return s+"]"; } string toLinear() { string s=linearName()+" = "; Braid b=initial; bool first=true; for (int i=0; i "; Braid b=initial; bool first=true; for (int i=0; i