} CostContribution;
static const CostContribution costs[]= {
+#define PRECOMP(compute) { 0,(compute) },
#define COST(weight, compute) { (weight),(compute) },
+ PRECOMP(compute_edge_lengths)
+ PRECOMP(compute_vertex_areas)
+
#if XBITS==3
#define STOP_EPSILON 1e-6
COST( 3e3, line_bending_cost)
stop_epsilon= STOP_EPSILON;
}
-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);
+/*---------- energy computation machinery ----------*/
- for (ci=0; ci<NCOSTS; ci++)
- energies[ci]= costs[ci].fn(vs->a, section);
-}
+typedef struct {
+ double total;
+ const CostContribution *cc;
+} CostComputationData;
-/*---------- energy computation machinery ----------*/
+void compute_energy_separately(const struct Vertices *vs,
+ int section, void *energy_v, void *ccd_v) {
+ CostComputationData *ccd= ccd_v;
+ double *energy= energy_v;
+ *energy= ccd->cc->fn(vs->a, section);
+}
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];
+ int section, void *energy_v, void *ccd_v) {
+ CostComputationData *ccd= ccd_v;
+ double *energy= energy_v;
+ ccd->total += *energy;
}
double compute_energy(const struct Vertices *vs) {
static int bests_unprinted;
- double totals[NCOSTS], energy;
+ double energy;
int ci, printing;
+ CostComputationData ccd;
printing= printing_check(pr_cost,0);
if (printing) printf("%15lld c>e |", evaluations);
- 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);
+ for (ci=0; ci<NCOSTS; ci++) {
+ ccd.total= 0;
+ ccd.cc= &costs[ci];
+
+ inparallel(vs,
+ compute_energy_separately,
+ compute_energy_combine,
+ sizeof(energy),
+ &ccd);
+
+ if (ccd.cc->weight != 0)
+ addcost(&energy, costs[ci].weight, ccd.total, printing);
+ }
if (printing) printf("| total %# e |", energy);
/*---------- Precomputations ----------*/
-void compute_edge_lengths(const Vertices vertices, int section) {
+double compute_edge_lengths(const Vertices vertices, int section) {
int v1,e,v2;
FOR_EDGE(v1,e,v2, OUTER)
edge_lengths[v1][e]= hypotD(vertices[v1],vertices[v2]);
+
+ return 0;
}
-void compute_vertex_areas(const Vertices vertices, int section) {
+double compute_vertex_areas(const Vertices vertices, int section) {
int v0,v1,v2, e1,e2;
// int k;
vertex_areas[v0]= total / count;
vertex_mean_edge_lengths[v0]= edges_total / count;
}
+
+ return 0;
}
/*---------- Edgewise vertex displacement ----------*/
(v) < OUTER_PERSECTION_BASE((zero),(n), section + 1) && (v) < (n); \
(v)++)
+/*
+ * OUTER is a loop constructor like INNER (see mgraph.h).
+ *
+ * Constraints on its use:
+ * - must be in exactly one loop of particular function
+ * - function must not modify anything other than
+ * its return value (for cost computation functions, COST()) or
+ * its designated output (for precomputation functions, PRECOMP())
+ * (which latter it may not read)
+ * - function must of course be reentrant
+ */
+
#define nsections NSECTIONS
typedef void Computation(const struct Vertices *vertices,
Computation *separately,
Computation *combine,
size_t secdatasz, void *gendata);
+ /* nsections copies of the computation `separately' are run in parallel
+ * with different values of `section' from 0 to nsections-1.
+ * Each copy is passed the same gendata as passed to inparallel.
+ * Each copy gets its own data block (struct aligned) of size
+ * secdatasz, passed as secdata, uninitialised on entry.
+ * After all the copies have finished, `combine' is invoked
+ * nsections times sequentially, with the same sets of arguments.
+ */
#endif /*PARALLEL_H*/