pari_precision=$compute_precision

!for i in points,lines,lineid,circles,chgoal
 pari_$i=!translate $\
$ to ; in $($i)
!next i

pari_header_2=if(pointcnt>0,points=vecextract(Mat([$pari_points]),"1..2"),points=[]);
pari_header_3=if(linecnt>0,lines=vecextract(Mat([$pari_lines]),"1..4"),lines=[]);
pari_header_4=if(linecnt>0,lineid=Mat([$pari_lineid]),lineid=[]);
pari_header_5=if(circlecnt>0,circles=vecextract(Mat([$pari_circles]),"1..3"),circles=[]);
pari_header_6=if(goalcnt>0,goals=Mat([$pari_chgoal]),goals=[]);\

pari_header=pointcnt=$pointcnt;linecnt=$linecnt;circlecnt=$circlecnt;\
goalcnt=$goalcnt;\
closeness=$closeness;compare_precision=$compare_precision;\
range_limit=$range_limit;\
\
\\ Check whether an object is within the goals.\
{\
 goalcheck(t,o)=\
  lastitem=min(goalcnt,matsize(goals)[1]);\
  if(lastitem<=0, return(0));\
  for(k=1,lastitem,\
   if(goals[k,1]==t, cmp=goals[k,];\
    if(t==1, cmp=vecextract(cmp,"2..3");\
     if(vecmax(abs(o-cmp))<compare_precision, return(k));\
    );\
    if(t==2, cmp=vecextract(cmp,"2..4");\
     if(min(vecmax(abs(o-cmp)),vecmax(abs(o+cmp)))<compare_precision, return(k));\
    );\
    if(t==3, cmp=vecextract(cmp,"2..4");\
     if(vecmax(abs(o-cmp))<compare_precision, return(k));\
    );\
   );\
  );\
  return(0);\
}\
\
\\ Check whether a point is already in the list.\
{\
 pointcheck(p)=\
  lastitem=min(pointcnt,matsize(points)[1]);\
  if(lastitem<=0, return(0));\
  for(k=1,lastitem,\
   n=vecmax(abs(p-points[k,]));\
   if(n<compare_precision, return(2));\
   if(n<closeness, return(1));\
  );\
  return(0);\
}\
\
\\ Check whether a line is already in the list.\
{\
 linecheck(ll)=\
  lastitem=min(linecnt,matsize(lines)[1]);\
  if(lastitem<=0, return(0));\
  for(k=1,lastitem,\
   n=min(vecmax(abs(ll-lineid[k,])),vecmax(abs(ll+lineid[k,])));\
   if(n<compare_precision, return(2));\
   if(n<closeness, return(1));\
  );\
  return(0);\
}\
\
\\ Check whether a circle is already in the list.\
{\
 circlecheck(cc)=\
  lastitem=min(circlecnt,matsize(circles)[1]);\
  if(lastitem<=0, return(0));\
  for(k=1,lastitem,\
   n=vecmax(abs(cc-circles[k,]));\
   if(n<compare_precision, return(2));\
   if(n<closeness, return(1));\
  );\
  return(0);\
}\
\
\\ compute line id parameters\
{\
 compute_lineid(x1,y1,x2,y2,cnt)=\
  a=y2-y1;b=x1-x2;c=x2*y1-x1*y2;cnorm=max(abs(a),max(abs(b),abs(c)));\
  if(cnorm<closeness, return("error too_close"));\
  a=a/cnorm;b=b/cnorm;c=c/cnorm;\
  cntbak=linecnt;linecnt=cnt-1;tt=linecheck([a,b,c]);linecnt=cntbak;\
  if(tt==2, return("error already"));\
  if(tt==1, return("error almost_already"));\
  return([a,b,c]);\
}\
\
\\ compute the line through 2 points\
{\
 add_line(i1,i2)=\
  p1=points[i1,];p2=points[i2,];\
  x1=p1[1];x2=p2[1];y1=p1[2];y2=p2[2];\
  a=y2-y1;b=x1-x2;c=x2*y1-x1*y2;cnorm=max(abs(a),max(abs(b),abs(c)));\
  if(cnorm<closeness, return("error too_close"));\
  a=a/cnorm;b=b/cnorm;c=c/cnorm;tt=linecheck([a,b,c]);\
  if(tt==2, return("error already"));\
  if(tt==1, return("error almost_already"));\
  return([x1,y1,x2,y2,a,b,c]);\
}\
\
\\ compute the mid-perpendicular line of 2 points\
{\
 add_midper(i1,i2)=\
  p1=points[i1,];p2=points[i2,];\
  x1=p1[1];x2=p2[1];y1=p1[2];y2=p2[2];\
  a=x1-x2;b=y1-y2;c=(x2^2+y2^2-x1^2-y1^2)/2;cnorm=max(abs(a),max(abs(b),abs(c)));\
  if(cnorm<closeness, return("error too_close"));\
  a=a/cnorm;b=b/cnorm;c=c/cnorm;tt=linecheck([a,b,c]);\
  if(tt==2, return("error already"));\
  if(tt==1, return("error almost_already"));\
  xm=(x1+x2)/2;ym=(y1+y2)/2;xd=x2-x1;yd=y2-y1;\
  return([xm+yd,ym-xd,xm-yd,ym+xd,a,b,c]);\
}\
\
\\ compute the middle of 2 points\
{\
 add_middle(i1,i2)=\
  p1=points[i1,];p2=points[i2,];\
  x=(p1[1]+p2[1])/2;y=(p1[2]+p2[2])/2;\
  tt=pointcheck([x,y]);\
  if(tt==2, return("error already"));\
  if(tt==1, return("error almost_already"));\
  return([x,y]);\
}\
\
\\ compute the intersection point of two lines\
{\
 line_intersect(i1,i2)=\
  l1=lineid[i1,];l2=lineid[i2,];\
  a1=l1[1];b1=l1[2];c1=l1[3];a2=l2[1];b2=l2[2];c2=l2[3];\
  det=a1*b2-a2*b1;\
  if(abs(det)<compare_precision, return("error parallel"));\
  if(abs(det)<closeness, return("error too_close"));\
  x=-(c1*b2-b1*c2)/det;y=-(a1*c2-a2*c1)/det;\
  if(abs(x)>range_limit || abs(y)>range_limit, return("error too_big"));\
  tt=pointcheck([x,y]);\
  if(tt==2, return("error already"));\
  if(tt==1, return("error almost_already"));\
  return([x,y]);\
}\
\
\\ internal computation, intersection point of a lines and a circle\
{\
 lc_int_(data)=\
  a=data[1];b=data[2];c=data[3];xc=data[4];yc=data[5];r=data[6];\
  if(abs(a)>abs(b),\
   b=-b/a;c=-c/a;\
   A=b^2+1;B=b*(c-xc)-yc;C=(c-xc)^2+yc^2-r^2;discr=B^2-A*C;\
   if(discr<-(compare_precision^2), return("error no_intersection"));\
   if(discr<0, discr=0);\
   discr=sqrt(discr);y1=(-B+discr)/A;y2=(-B-discr)/A;\
   x1=b*y1+c;x2=b*y2+c;\
  ,\
   a=-a/b;c=-c/b;\
   A=a^2+1;B=a*(c-yc)-xc;C=(c-yc)^2+xc^2-r^2;discr=B^2-A*C;\
   if(discr<-(compare_precision^2), return("error no_intersection"));\
   if(discr<0, discr=0);\
   discr=sqrt(discr);x1=(-B+discr)/A;x2=(-B-discr)/A;\
   y1=a*x1+c;y2=a*x2+c;\
  );\
  if(abs(x1)<range_limit && abs(y1)<range_limit && pointcheck([x1,y1])==0,\
   out=[x1,y1], out=[]);\
  if(abs(x2)<range_limit && abs(y2)<range_limit && \
   pointcheck([x2,y2])==0 && max(abs(x1-x2),abs(y1-y2))>closeness,\
   out=concat(out,[x2,y2]));\
  if(out==[], return("error no_available"), return(out));\
}\
\
\\ compute the intersection point of a lines and a circle\
{\
 lc_intersect(i1,i2)=\
  return(lc_int_(concat(lineid[i1,],circles[i2,])));\
}\
\
\\ compute the intersection point of two circles\
{\
 circle_intersect(i1,i2)=\
  c1=circles[i1,];c2=circles[i2,];\
  x1=c1[1];y1=c1[2];r1=c1[3];x2=c2[1];y2=c2[2];r2=c2[3];\
  a=2*(x1-x2);b=2*(y1-y2);c=x2^2+y2^2-x1^2-y1^2+r1^2-r2^2;\
  cnorm=max(abs(a),max(abs(b),abs(c)));\
  if(cnorm<closeness, return("error too_close"));\
  if(max(abs(a),abs(b))<closeness, return("error no_intersection"));\
  return(lc_int_([a/cnorm,b/cnorm,c/cnorm,x1,y1,r1]));\
}\
\
\\ compute a circle of center i1 and through i2.\
{\
 add_circle(i1,i2)=\
  p1=points[i1,];p2=points[i2,]; diff=p2-p1;\
  radius=sqrt(diff[1]^2+diff[2]^2);\
  if(radius<compare_precision, return("error too_close"));\
  cir=concat(p1,radius); tt=circlecheck(cir);\
  if(tt==2, return("error already"));\
  if(tt==1, return("error almost_already"));\
  return(cir);\
}\
\
\\ list lines containing given point.\
{\
 incipl(p)=\
  x=p[1]; y=p[2]; out=[];\
  for(i=1,linecnt,\
   a=lineid[i,1];b=lineid[i,2];c=lineid[i,3];discr=sqrt(a^2+b^2);\
   if(abs(a*x+b*y+c)<discr*compare_precision, out=concat(out,i) );\
  );\
  return(out);\
}\
\
\\ list circles containing given point.\
{\
 incipc(p)=\
  x=p[1]; y=p[2]; out=[];\
  for(i=1,circlecnt,\
   cx=circles[i,1];cy=circles[i,2];r=circles[i,3];\
   if(abs(sqrt((x-cx)^2+(y-cy)^2)-r)<compare_precision, out=concat(out,i) );\
  );\
  return(out);\
}\
\
\\ list points in given line.\
{\
 incilp(l)=\
  a=l[5]; b=l[6]; c=l[7]; discr=sqrt(a^2+b^2); out=[];\
  for(i=1,pointcnt,\
   x=points[i,1]; y=points[i,2];\
   if(abs(a*x+b*y+c)<discr*compare_precision, out=concat(out,i) );\
  );\
  return(out);\
}\
\
\\ list circles containing given point.\
{\
 incicp(ci)=\
  cx=ci[1];cy=ci[2];r=ci[3]; out=[];\
  for(i=1,pointcnt,\
   x=points[i,1]; y=points[i,2];\
   if(abs(sqrt((x-cx)^2+(y-cy)^2)-r)<compare_precision, out=concat(out,i) );\
  );\
  return(out);\
}\

