Problem 2:

A photon moving at speed 1 in the x-y  plane starts at t = 0  at (x, y) = (.5, .1)  heading due east.  Around every integer lattice point ``(i,j)  in the plane, a circular mirror of radius 1/3  has been erected.  How far from the origin is the photon at t = 10 ?

Solution:

You have to be careful to use enough digits here, because there are 13 reflections, and each reflection from a curved surface amplifies the error.  We needed 11 additional digits.  

The state of the photon is [x, y, dx, dy, s]  where [x, y]  is the position, [dx, dy]  the velocity, s  the distance travelled.  We always have dx^2+dy^2 = 1 .  

Starting  in this state, you hit a mirror centred at [mx, my]  if abs((mx-x)*dy-(my-y)*dx) < 1/3

(assuming that mirror is in the forward direction, and you don't hit anything else first).

If so, let p = [px, py]  be the point where it hits.  This is [x+t*dx, y+t*dy]  where

(x-mx)^2+(y-my)^2+2*(dx*(x-mx)+dy*(y-my))*t+t^2 = 1/9 .  Then the next state is

[px, py, dx-h*(mx-px), dy-h*(my-py), s+sqrt((px-x)^2+(py-y)^2)]

where h = 18*((mx-px)*dx+(my-py)*dy) .

>    plots[display]([plottools[circle]([0,0],1), plots[arrow]([2,-2],[-1,2],shape=arrow,colour=blue),
plots[arrow]([1,0],[1,2],shape=arrow,colour=blue),
plots[arrow]([1,0],[2,0],shape=arrow,colour=red)
],axes=none,scaling=constrained);

[Maple Plot]

Global variables: x, y, dx, dy, s  for current state;
if going mainly in
x  direction, iy = 0  and ix  is integer to go in x  direction to next mirror;

if going mainly in y  direction, ix = 0  and iy  is integer to go in y  direction to next mirror.

>    move:= proc()
# return true if you hit the mirror or end of path
# and update state in this case,
# false if you don't (leaving state unchanged)
  local mx, my, t, px, py,h,ds;
  global x,y,dx,dy,s,ix,iy;
  if iy = 0 then # going in x direction
    mx:= round(x+ix-.001);
    my:= round(y+dy/dx*ix);
    ds:= sqrt(1+(dy/dx)^2)*abs(mx-x);
  else # going in y direction
    my:= round(y+iy);
    mx:= round(x+dx/dy*iy);
    ds:= sqrt(1+(dx/dy)^2)*abs(my-y);
  fi;
  if abs((mx-x)*dy - (my-y)*dx) < 1/3 then
    t:= min(fsolve((x+t*dx-mx)^2 + (y+t*dy-my)^2=1/9,t));
    px:= x+t*dx; py:= y+t*dy;
    ds:= sqrt((px-x)^2+(py-y)^2);
    if s + ds >= 10 then
      x:= x + (10-s)*dx;
      y:= y + (10-s)*dy;
      s:= 10;
      return true;
    else
      h:= 18*((mx-px)*dx+(my-py)*dy);
      s:= s + ds;
      dx:= dx - h*(mx-px);
      dy:= dy - h*(my-py);
# dx^2 + dy^2 should stay constant, but make sure
      h:= sqrt(dx^2+dy^2);
      dx:= dx/h; dy:= dy/h;
      x:= px; y:= py;
      return true;
    fi
  # no hit, but maybe we'd go too far
  elif s + ds >= 10 then
    x:= x + (10-s)*dx;
    y:= y + (10-s)*dy;
    s:= 10;
    return true;
  fi;
false   
end;

move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...
move := proc () local mx, my, t, px, py, h, ds; global x, y, dx, dy, s, ix, iy; if iy = 0 then mx := round(x+ix-.1e-2); my := round(y+dy/dx*ix); ds := sqrt(1+dy^2/dx^2)*abs(mx-x) else my := round(y+iy)...

Initial conditions.

>    x,y,dx,dy,s:= 0.5, 0.1, 1, 0, 0; path:= [x,y]; ix:= 1; iy:= 0;
_Envsignum0:= 0; Digits:= 50;

x, y, dx, dy, s := .5, .1, 1, 0, 0

path := [.5, .1]

ix := 1

iy := 0

_Envsignum0 := 0

Digits := 50

>    while s < 10 do
  if move() then # reassess directions
    if abs(dx) >= abs(dy) then
      ix:= signum(dx); iy:= 0
    else
      ix:= 0; iy:= signum(dy);
    fi;
    path:= path,[x,y];
  else # go to next mirror in same direction
    ix:= ix+signum(ix);
    iy:= iy+signum(iy);
  fi
od:

The final state:

>    x,y,dx,dy,s;

-.73629269860961831077573717186639172045189580005576, -.66964269636357137519437607096709846686137759186589, .93573371537700371807496188013868503921833738804569, .352707263756714536268364071066345526210...
-.73629269860961831077573717186639172045189580005576, -.66964269636357137519437607096709846686137759186589, .93573371537700371807496188013868503921833738804569, .352707263756714536268364071066345526210...
-.73629269860961831077573717186639172045189580005576, -.66964269636357137519437607096709846686137759186589, .93573371537700371807496188013868503921833738804569, .352707263756714536268364071066345526210...
-.73629269860961831077573717186639172045189580005576, -.66964269636357137519437607096709846686137759186589, .93573371537700371807496188013868503921833738804569, .352707263756714536268364071066345526210...

The answer:

>    ans:=sqrt(x^2+y^2);

ans := .99526291944335416089031180942672162102913212829989

>    with(plots): display({plot([path]),seq(seq(plottools[circle]([i,j],1/3),i=-1..1),j=-1..2)},scaling=constrained,axes=frame);

Warning, the name changecoords has been redefined

[Maple Plot]

Just for comparison, here it is with 40 digits.

>    x,y,dx,dy,s:= 0.5, 0.1, 1, 0, 0: path:= [x,y]: ix:= 1: iy:= 0:
_Envsignum0:= 0: Digits := 40:
while s < 10 do
  if move() then # reassess directions
    if abs(dx) >= abs(dy) then
      ix:= signum(dx); iy:= 0
    else
      ix:= 0; iy:= signum(dy);
    fi;
    path:= path,[x,y];
  else # go to next mirror in same direction
    ix:= ix+signum(ix);
    iy:= iy+signum(iy);
  fi
od:
ans40:= sqrt(x^2+y^2);

ans40 := .9952629194433541608903118094230522093364

>    ans40 - ans;

-.36694116927e-29

And here's what we would have got with a starting point different by 10^(-10)  in the y direction.

>    path0:= path:
x,y,dx,dy,s:= 0.5, 0.1+1e-10, 1, 0, 0: path:= [x,y]: ix:= 1: iy:= 0:
_Envsignum0:= 0: Digits := 40:
while s < 10 do
  if move() then # reassess directions
    if abs(dx) >= abs(dy) then
      ix:= signum(dx); iy:= 0
    else
      ix:= 0; iy:= signum(dy);
    fi;
    path:= path,[x,y];
  else # go to next mirror in same direction
    ix:= ix+signum(ix);
    iy:= iy+signum(iy);
  fi
od:

>    display({plot([path],colour=blue),plot([path0],colour=red),seq(seq(plottools[circle]([i,j],1/3),i=-1..1),j=-1..2)},scaling=constrained,axes=frame);

[Maple Plot]

>    seq(path[i]-path0[i],i=1..nops([path]));

[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...
[0., .1e-9], [.314485451189369692603984284094e-10, .1e-9], [-.2002266980443625698991620031486e-9, .1525938072699685403694714882615e-8], [-.92764022611390379631995935611530e-8, .371322382700575398567055...

>    plots[logplot]([seq([i,sqrt(%[i][1]^2+%[i][2]^2)],i=1..nops([path]))],style=point,symbol=circle);

[Maple Plot]

Back to Solutions to the SIAM $100 Challenge