chiark / gitweb /
Merge multiprocessor support; fix up Makefile runes
authorIan Jackson <ian@davenant.relativity.greenend.org.uk>
Sat, 27 Sep 2008 23:12:47 +0000 (00:12 +0100)
committerIan Jackson <ian@davenant.relativity.greenend.org.uk>
Sat, 27 Sep 2008 23:12:47 +0000 (00:12 +0100)
1  2 
Makefile
common.c
energy.c
minimise.h
primer.c

diff --combined Makefile
index b41c543b25f800691cda9c7b3c198b39a76faea8,9443d70dc9241974290d08ee973b243854564fba..927f45d1a8e60855abc87ebb43f1652cc1f26387
+++ b/Makefile
@@@ -11,9 -11,12 +11,10 @@@ SGTATHAM=sgtatha
  CWARNS=       -Wall -Wwrite-strings -Wpointer-arith -Werror -Wshadow
  CXXWARNS= $(CWARNS) -Wno-shadow -Wno-error
  
 -NPROCCFLAGS := -DNPROCESSORS=$(shell ./nprocessors)
 -
  OPTIMISE=     -O2
- CFLAGS=               -MMD $(OPTIMISE) -g $(CWARNS) $(DIMCFLAGS)
+ CFLAGS_UNIPROC=       -MMD $(OPTIMISE) -g $(CWARNS) $(DIMCFLAGS)
  CXXFLAGS=     -MMD $(OPTIMISE) -g $(CXXWARNS)
+ CFLAGS=               $(CFLAGS_UNIPROC) $(NPROCCFLAGS)
  
  LIBGSL= -lgsl -lgslcblas
  
@@@ -31,10 -34,15 +32,22 @@@ minimise:  energy.o graph.o common.o mgr
  primer:               primer.o common.o
                $(CC) $(CFLAGS) -o $@ $^ $(LIBGSL)
  
+ nprocessors:  nprocessors.o common.o
+               $(CC) $(CFLAGS_UNIPROC) -o $@ $^ $(LIBGSL)
+ common.o nprocessors.o: %.o: %.c
+               $(CC) -c $(CPPFLAGS) $(CFLAGS_UNIPROC) $< -o $@
++.nprocessors.make: ./nprocessors
++      set -e; n=`./nprocessors`; \
++      echo "NPROCCFLAGS := -DNPROCESSORS=$$n" $o
++
++include .nprocessors.make
++
++
  prime.data:   primer
                ./$^ $o
  
  sgtatham.cfm: sgtatham-regenerator prime.data $(SGTATHAM)/z.typescript
                ./$^ -T -o$@
  
@@@ -44,7 -52,6 +57,6 @@@ lumpy.cfm: oldmoebius-converter prime.d
  ring.cfm: oldmoebius-converter prime.data /dev/null ../moebius/a.out
                ./$^ -o$@
  
  best-33.CFM:
                ./minimise-33 sgtatham.cfm -iwip-33.cfm -o$@
  
@@@ -73,8 -80,9 +85,9 @@@ output-%:     output+%.o mgraph+%.o common.
  interpolate-%:        interpolate+%.o mgraph+%.o common.o
                $(CC) $(CFLAGS) -o $@ $^ $(LIBGSL)
  
- minimise-%:   energy+%.o graph+%.o mgraph+%.o minimise+%.o half+%.o common.o
-               $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBGSL)
+ minimise-%:   energy+%.o graph+%.o mgraph+%.o minimise+%.o \
+                       half+%.o parallel.o common.o
+               $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBGSL) -lpthread
  
  # this ridiculous repetition is due to make being too lame
  
diff --combined common.c
index cc72ed3341dfd9f8c2f56cf82259e7fcaf3a899d,fe58990f2c76888b5189682e76e988966b486149..3b036aaa29f54508a5708a1965347734dc5cfa5e
+++ b/common.c
@@@ -15,14 -15,6 +15,14 @@@ double magnD(const double pq[D3]) 
    return gsl_blas_dnrm2(&v);
  }
  
 +double magnD2(const double pq[D3]) {
 +  int k;
 +  double d2= 0;
 +  
 +  K d2= ffsqa(pq[k], d2);
 +  return d2;
 +}
 +
  double hypotD(const double p[D3], const double q[D3]) {
    int k;
    double pq[D3];
@@@ -51,18 -43,6 +51,18 @@@ void xprod(double r[D3], const double a
    r[2]= a[0]*b[1] - a[1]*b[0];
  }
  
 +void normalise(double v[D3], double one, double absepsilon) {
 +  int k;
 +  double multby= one/(magnD(v) + absepsilon);
 +  K v[k] *= multby;
 +}
 +
 +void xprod_norm(double r[D3], const double a[D3], const double b[D3],
 +              double one, double absepsilon) {
 +  xprod(r,a,b);
 +  normalise(r, absepsilon, one);
 +}
 +
  double dotprod(const double a[D3], const double b[D3]) {
    int k;
    double result= 0;
@@@ -82,4 -62,4 +82,4 @@@ void gsldie(int l, const char *what, in
  
  void diee(const char *what) { perror(what); exit(16); }
  void fail(const char *emsg) { fputs(emsg,stderr); exit(12); }
- void flushoutput(void) { if (fflush(stdout)||ferror(stdout)) diee("stdout"); }
+ void flushoutput(void) { if (ferror(stdout)||fflush(stdout)) diee("stdout"); }
diff --combined energy.c
index 540f6a909e7509926f9b62329a65917e2fed0b84,5aa1c602b8387cd75f6c0e75437f7f63bd6f3edc..e43ecede21c987bdc638805ccc069d2ab10eff6a
+++ b/energy.c
  #include "common.h"
  #include "minimise.h"
  #include "mgraph.h"
+ #include "parallel.h"
  
  double vertex_areas[N], vertex_mean_edge_lengths[N], edge_lengths[N][V6];
  
  static double best_energy= DBL_MAX;
  
  static void addcost(double *energy, double tweight, double tcost, int pr);
- #define COST(weight, compute) addcost(&energy, (weight), (compute), printing)
+ /*---------- main energy computation, weights, etc. ----------*/
+ typedef double CostComputation(const Vertices vertices, int section);
+ typedef struct {
+   double weight;
+   CostComputation *fn;
+ } CostContribution;
+ static const CostContribution costs[]= {
+ #define COST(weight, compute) { (weight),(compute) },
+ #if XBITS==3
 -#define STOP_EPSILON 1e-6;
 -    COST(  3e2,   line_bending_cost)
 -    COST(  1e3,   edge_length_variation_cost)
 -    COST( 0.2e3,  rim_proximity_cost)
 -    COST(  1e8,   noncircular_rim_cost)
++#define STOP_EPSILON 1e-6
++    COST(  3e3,   line_bending_cost)
++    COST(  3e3,   edge_length_variation_cost)
++    COST( 0.4e3,  rim_proximity_cost)
++    COST(  1e6,   edge_angle_cost)
++                  #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.7)
++//    COST(  1e1,   small_triangles_cost)
++    COST(  1e12,   noncircular_rim_cost)
+ #endif
+ #if XBITS==4
 -#define STOP_EPSILON 1e-5;
 -    COST(  3e2,   line_bending_cost)
 -    COST(  3e3,   edge_length_variation_cost)
 -    COST( 3.8e1,  rim_proximity_cost) // 5e1 is too much
 -                                       // 2.5e1 is too little
++#define STOP_EPSILON 1e-6
++    COST(  3e5,   line_bending_cost)
++    COST( 10e2,   edge_length_variation_cost)
++    COST( 9.0e1,  rim_proximity_cost) // 5e1 is too much
++                                    // 2.5e1 is too little
+     // 0.2e1 grows compared to previous ?
+     // 0.6e0 shrinks compared to previous ?
 -    COST(  1e12,   noncircular_rim_cost)
++
++    COST(  1e12,   edge_angle_cost)
++                  #define EDGE_ANGLE_COST_CIRCCIRCRAT (0.5/1.3)
++    COST(  1e18,   noncircular_rim_cost)
+ #endif
+ };
+ #define NCOSTS ((sizeof(costs)/sizeof(costs[0])))
++const double edge_angle_cost_circcircrat= EDGE_ANGLE_COST_CIRCCIRCRAT;
 +
  void energy_init(void) {
+   stop_epsilon= STOP_EPSILON;
  }
  
- /*---------- main energy computation and subroutines ----------*/
+ void compute_energy_separately(const struct Vertices *vs,
+                        int section, void *energies_v, void *totals_v) {
+   double *energies= energies_v;
+   int ci;
+     
+   compute_edge_lengths(vs->a, section);
+   compute_vertex_areas(vs->a, section);
+   for (ci=0; ci<NCOSTS; ci++)
+     energies[ci]= costs[ci].fn(vs->a, section);
+ }
+ /*---------- energy computation machinery ----------*/
+ void compute_energy_combine(const struct Vertices *vertices,
+                        int section, void *energies_v, void *totals_v) {
+   int ci;
+   
+   double *energies= energies_v;
+   double *totals= totals_v;
+   for (ci=0; ci<NCOSTS; ci++)
+     totals[ci] += energies[ci];
+ }
  
  double compute_energy(const struct Vertices *vs) {
    static int bests_unprinted;
  
-   double energy;
-   int printing;
-   compute_edge_lengths(vs->a);
-   compute_vertex_areas(vs->a);
-   energy= 0;
+   double totals[NCOSTS], energy;
+   int ci, printing;
  
    printing= printing_check(pr_cost,0);
  
    if (printing) printf("%15lld c>e |", evaluations);
  
-   if (XBITS==3) {
-     COST(  3e3,   line_bending_cost(vs->a));
-     COST(  3e3,   edge_length_variation_cost(vs->a));
-     COST( 0.4e3,  rim_proximity_cost(vs->a));
-     COST(  1e6,   edge_angle_cost(vs->a, 0.5/1.7));
- //    COST(  1e1,   small_triangles_cost(vs->a));
-     COST(  1e12,   noncircular_rim_cost(vs->a));
-     stop_epsilon= 1e-6;
-   } else if (XBITS==4) {
-     COST(  3e5,   line_bending_cost(vs->a));
-     COST( 10e2,   edge_length_variation_cost(vs->a));
-     COST( 9.0e1,  rim_proximity_cost(vs->a)); // 5e1 is too much
-                                                 // 2.5e1 is too little
-     // 0.2e1 grows compared to previous ?
-     // 0.6e0 shrinks compared to previous ?
-     COST(  1e12,   edge_angle_cost(vs->a, 0.5/1.3));
-     COST(  1e18,   noncircular_rim_cost(vs->a));
-     stop_epsilon= 1e-6;
-   } else {
-     abort();
-   }
+   inparallel(vs,
+            compute_energy_separately,
+            compute_energy_combine,
+            sizeof(totals) /* really, size of energies */,
+            totals);
+   energy= 0;
+   for (ci=0; ci<NCOSTS; ci++)
+     addcost(&energy, costs[ci].weight, totals[ci], printing);
  
    if (printing) printf("| total %# e |", energy);
  
@@@ -92,18 -135,18 +143,18 @@@ static void addcost(double *energy, dou
  
  /*---------- Precomputations ----------*/
  
- void compute_edge_lengths(const Vertices vertices) {
+ void compute_edge_lengths(const Vertices vertices, int section) {
    int v1,e,v2;
  
-   FOR_EDGE(v1,e,v2)
 -  FOR_EDGE(v1,e,v2,OUTER)
++  FOR_EDGE(v1,e,v2, OUTER)
      edge_lengths[v1][e]= hypotD(vertices[v1],vertices[v2]);
  }
  
- void compute_vertex_areas(const Vertices vertices) {
+ void compute_vertex_areas(const Vertices vertices, int section) {
    int v0,v1,v2, e1,e2;
  //  int k;
  
-   FOR_VERTEX(v0) {
 -  FOR_VERTEX(v0,OUTER) {
++  FOR_VERTEX(v0, OUTER) {
      double total= 0.0, edges_total=0;
      int count= 0;
  
     *          Q,e
     */
  
- double line_bending_cost(const Vertices vertices) {
+ double line_bending_cost(const Vertices vertices, int section) {
    static const double axb_epsilon= 1e-6;
 -  static const double exponent_r= 3;
 +  static const double exponent_r= 4;
  
    int pi,e,qi,ri, k;
    double  a[D3], b[D3], axb[D3];
    double total_cost= 0;
  
-   FOR_EDGE(qi,e,ri) {
+   FOR_EDGE(qi,e,ri, OUTER) {
      pi= EDGE_END2(qi,(e+3)%V6); if (pi<0) continue;
  
 +//if (!(qi&XMASK)) fprintf(stderr,"%02x-%02x-%02x (%d)\n",pi,qi,ri,e);
 +
      K a[k]= -vertices[pi][k] + vertices[qi][k];
      K b[k]= -vertices[qi][k] + vertices[ri][k];
  
      double delta= atan2(magnD(axb) + axb_epsilon, dotprod(a,b));
      double cost= pow(delta,exponent_r);
  
 -    if (!e && !(qi & ~XMASK))
 -      cost *= 10;
 -
      total_cost += cost;
    }
    return total_cost;
     *           Q,e
     */
  
- double edge_length_variation_cost(const Vertices vertices) {
+ double edge_length_variation_cost(const Vertices vertices, int section) {
    double diff, cost= 0, exponent_r= 2;
    int q, e,r, eback;
  
-   FOR_EDGE(q,e,r) {
+   FOR_EDGE(q,e,r, OUTER) {
      eback= edge_reverse(q,e);
      diff= edge_lengths[q][e] - edge_lengths[q][eback];
      cost += pow(diff,exponent_r);
@@@ -227,11 -271,11 +278,11 @@@ static void find_nearest_oncircle(doubl
    oncircle[1] *= mult;
  }
  
- double rim_proximity_cost(const Vertices vertices) {
+ double rim_proximity_cost(const Vertices vertices, int section) {
    double oncircle[3], cost=0;
    int v;
  
-   FOR_VERTEX(v) {
+   FOR_VERTEX(v, OUTER) {
      int y= v >> YSHIFT;
      int nominal_edge_distance= y <= Y/2 ? y : Y-1-y;
      if (nominal_edge_distance==0) continue;
  
  /*---------- noncircular rim cost ----------*/
  
- double noncircular_rim_cost(const Vertices vertices) {
+ double noncircular_rim_cost(const Vertices vertices, int section) {
    int vy,vx,v;
    double cost= 0.0;
    double oncircle[3];
  
-   FOR_RIM_VERTEX(vy,vx,v) {
+   FOR_RIM_VERTEX(vy,vx,v, OUTER) {
      find_nearest_oncircle(oncircle, vertices[v]);
  
      double d2= hypotD2(vertices[v], oncircle);
    }
    return cost;
  }
- double edge_angle_cost(const Vertices vertices, double circcircrat) {
 +
 +/*---------- overly sharp edge cost ----------*/
 +
 +  /*
 +   *
 +   *                      Q `-_
 +   *              / |    `-_                         P'Q' ------ S'
 +   *             /  |       `-.                            _,' `.       .
 +   *            /   |           S               _,'     :      .
 +   *           /    |      _,-'                _,'        :r    .r
 +   *          /     |  _,-'              R' '           `.   .
 +   *         /    , P '                              ` .   r     :  .
 +   *        /  ,-'                                `  .   : 
 +   *       /,-'                                                ` C'
 +   *      /'
 +   *           R
 +   *
 +   *
 +   *
 +   *  Let delta =  angle between two triangles' normals
 +   *
 +   *  Giving energy contribution:
 +   *
 +   *                                   2
 +   *    E             =  F   .  delta
 +   *     vd, edge PQ      vd
 +   */
 +
-   FOR_EDGE(pi,e,qi) {
++double edge_angle_cost(const Vertices vertices, int section) {
 +  double pq1[D3], rp[D3], ps[D3], rp_2d[D3], ps_2d[D3], rs_2d[D3];
 +  double a,b,c,s,r;
 +  const double minradius_base= 0.2;
 +
 +  int pi,e,qi,ri,si, k;
 +//  double our_epsilon=1e-6;
 +  double total_cost= 0;
 +
-     double minradius= minradius_base + circcircrat*(a+b);
++  FOR_EDGE(pi,e,qi, OUTER) {
 +//    if (!(RIM_VERTEX_P(pi) || RIM_VERTEX_P(qi))) continue;
 +
 +    si= EDGE_END2(pi,(e+V6-1)%V6);  if (si<0) continue;
 +    ri= EDGE_END2(pi,(e   +1)%V6);  if (ri<0) continue;
 +
 +    K {
 +      pq1[k]= -vertices[pi][k] + vertices[qi][k];
 +      rp[k]=  -vertices[ri][k] + vertices[pi][k];
 +      ps[k]=  -vertices[pi][k] + vertices[si][k];
 +    }
 +
 +    normalise(pq1,1,1e-6);
 +    xprod(rp_2d, rp,pq1); /* projects RP into plane normal to PQ */
 +    xprod(ps_2d, ps,pq1); /* likewise PS */
 +    K rs_2d[k]= rp_2d[k] + ps_2d[k];
 +    /* radius of circumcircle of R'P'S' from Wikipedia
 +     * `Circumscribed circle' */
 +    a= magnD(rp_2d);
 +    b= magnD(ps_2d);
 +    c= magnD(rs_2d);
 +    s= 0.5*(a+b+c);
 +    r= a*b*c / sqrt((a+b+c)*(a-b+c)*(b-c+a)*(c-a+b) + 1e-6);
 +
- double small_triangles_cost(const Vertices vertices) {
++    double minradius= minradius_base + edge_angle_cost_circcircrat*(a+b);
 +    double deficit= minradius - r;
 +    if (deficit < 0) continue;
 +    double cost= deficit*deficit;
 +
 +    total_cost += cost;
 +  }
 +
 +  return total_cost;
 +}
 +
 +/*---------- small triangles cost ----------*/
 +
 +  /*
 +   *
 +   *                      Q `-_
 +   *              / |    `-_
 +   *             /  |       `-.
 +   *            /   |           S
 +   *           /    |      _,-'
 +   *          /     |  _,-'
 +   *         /    , P '
 +   *        /  ,-'
 +   *       /,-'
 +   *      /'
 +   *           R
 +   *
 +   *  Let delta =  angle between two triangles' normals
 +   *
 +   *  Giving energy contribution:
 +   *
 +   *                                   2
 +   *    E             =  F   .  delta
 +   *     vd, edge PQ      vd
 +   */
 +
-   FOR_EDGE(pi,e,qi) {
++double small_triangles_cost(const Vertices vertices, int section) {
 +  double pq[D3], ps[D3];
 +  double x[D3];
 +  int pi,e,qi,si, k;
 +//  double our_epsilon=1e-6;
 +  double total_cost= 0;
 +
++  FOR_EDGE(pi,e,qi, OUTER) {
 +//    if (!(RIM_VERTEX_P(pi) || RIM_VERTEX_P(qi))) continue;
 +
 +    si= EDGE_END2(pi,(e+V6-1)%V6);  if (si<0) continue;
 +
 +    K {
 +      pq[k]= vertices[qi][k] - vertices[pi][k];
 +      ps[k]= vertices[si][k] - vertices[pi][k];
 +    }
 +    xprod(x, pq,ps);
 +
 +    double cost= 1/(magnD2(x) + 0.01);
 +
 +//double cost= pow(magnD(spqxpqr), 3);
 +//assert(dot>=-1 && dot <=1);
 +//double cost= 1-dot;
 +    total_cost += cost;
 +  }
 +
 +  return total_cost;
 +}
diff --combined minimise.h
index a8a2288f5c14b38a1993ab84b4133070ce317fbc,097b8ac42bedc42942799c8919792822e074872b..c2e13e7b40fef83169495c5b2754fc91333c90d1
  double compute_energy(const struct Vertices *vs);
  void energy_init(void);
  
- double graph_layout_cost(const Vertices v);
+ double graph_layout_cost(const Vertices v, int section);
  void graph_layout_prepare();
  
- void compute_vertex_areas(const Vertices vertices);
- void compute_edge_lengths(const Vertices vertices);
+ void compute_vertex_areas(const Vertices vertices, int section);
+ void compute_edge_lengths(const Vertices vertices, int section);
  extern double vertex_areas[N], vertex_mean_edge_lengths[N], edge_lengths[N][V6];
  
- double line_bending_cost(const Vertices vertices);
- double noncircular_rim_cost(const Vertices vertices);
- double edge_length_variation_cost(const Vertices vertices);
- double rim_proximity_cost(const Vertices vertices);
- double edge_angle_cost(const Vertices vertices, double circcircrat);
- double small_triangles_cost(const Vertices vertices);
++extern const double edge_angle_cost_circcircrat;
++
+ double line_bending_cost(const Vertices vertices, int section);
+ double noncircular_rim_cost(const Vertices vertices, int section);
+ double edge_length_variation_cost(const Vertices vertices, int section);
+ double rim_proximity_cost(const Vertices vertices, int section);
++double edge_angle_cost(const Vertices vertices, int section);
++double small_triangles_cost(const Vertices vertices, int section);
  
  extern const char *input_file, *best_file;
  extern char *best_file_tmp;
diff --combined primer.c
index 70cbcfeda45883205414c05c6b285df43fbb790c,70cbcfeda45883205414c05c6b285df43fbb790c..76939a6356b9911dc59e29913603cf8af5ee671b
+++ b/primer.c
@@@ -17,7 -17,7 +17,7 @@@ int main(int argc, const char **argv) 
         X*Y, N, X, Y, D3,
         prec+5,prec);
  
--  FOR_VERTEX(vi) {
++  FOR_VERTEX(vi, INNER) {
      int x= vi & XMASK; /* distance along strip */
      int y= vi >> YSHIFT; /* distance across strip */
      double u= y * 1.0 / (Y-1); /* SGT's u runs 0..1 across the strip */