From eef943717e684b6713d306f59ac369edb4104387 Mon Sep 17 00:00:00 2001 From: Vasco Pedro <vp@di.uevora.pt> Date: Mon, 4 Jul 2016 17:08:17 +0100 Subject: [PATCH] Update to PaCCS version 0.91 --- Makefile | 12 +++++++----- README | 11 +++++++++-- TUNING | 15 ++++++++++----- bench/all.c | 2 +- bench/bibd.c | 14 +++++++------- bench/c-exactly.c | 5 +++-- bench/change.c | 14 ++++---------- bench/costas.c | 17 +++++------------ bench/golfers.c | 2 +- bench/golomb.c | 10 +++++----- bench/graphs.c | 1 + bench/k-queens.c | 16 +++++++++------- bench/langford.c | 8 +++++--- bench/magic-seq.c | 6 ++++-- bench/magic-square.c | 7 ++++--- bench/money.c | 2 +- bench/partition.c | 5 +++-- bench/qap.c | 41 +++++++++++++++++------------------------ bench/queens.c | 9 +++++---- bench/queens2.c | 19 +++++++++++-------- bench/sudoku.c | 11 +++++++---- bench/times.c | 5 ++--- src/VERSION | 2 +- src/agents-splitgo-mpi.c | 370 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ src/agents-splitgo.c | 62 +++++++++++++++++++++++++++++++++----------------------------- src/bound.c | 10 +++++----- src/constraints.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------- src/constraints.h | 39 +++++++++++++++++++++------------------ src/constraints/all-different.c | 10 +++------- src/constraints/element-var.c | 7 ++----- src/constraints/element.c | 7 ++----- src/constraints/eq.c | 8 ++------ src/constraints/exactly-one.c | 7 ++----- src/constraints/exactly-var.c | 7 ++----- src/constraints/exactly-vars.c | 7 ++----- src/constraints/exactly.c | 7 ++----- src/constraints/knapsack.c | 7 ++----- src/constraints/knapsack2.c | 122 ++++++++++---------------------------------------------------------------------------------------------------------------- src/constraints/le.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- src/constraints/lt.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- src/constraints/max.c | 7 ++----- src/constraints/min.c | 7 ++----- src/constraints/minus-eq.c | 8 ++------ src/constraints/minus-ne.c | 8 ++------ src/constraints/ne.c | 8 ++------ src/constraints/nogoods.c | 7 ++----- src/constraints/plus-gt.c | 7 ++----- src/constraints/poly-eq-k.c | 329 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- src/constraints/poly-eq.c | 532 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- src/constraints/poly-le-k.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/constraints/poly-ne-k.c | 13 ++++++------- src/constraints/poly-ne.c | 13 ++++++------- src/constraints/sum-prod.c | 7 ++----- src/constraints/sum.c | 7 ++----- src/constraints/sum2.c | 7 ++----- src/constraints/var-eq-minus.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------- src/constraints/var-eq-times.c | 7 ++----- src/dsearch-sg.c | 31 +++++++++++++------------------ src/fdc_int.h | 29 +++++++---------------------- src/matching.c | 24 ++++++++++++++---------- src/options.c | 4 ++-- src/paccs.h | 3 +++ src/packed.c | 10 ++++------ src/packed.h | 2 +- src/pool.c | 140 +++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------- src/problem.c | 8 ++++---- src/revisions.c | 14 +++++++------- src/splitting.c | 10 ++++++---- src/util.c | 12 +++++++----- src/util.h | 8 ++++++++ src/values-bitmap.c | 16 ++++++++-------- src/values-intervals.c | 30 +++++++++++++++--------------- src/values.c | 2 ++ src/variables.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- src/variables.h | 17 +++++++++-------- 75 files changed, 1655 insertions(+), 1467 deletions(-) create mode 100644 src/constraints/poly-le-k.c create mode 100644 src/util.h diff --git a/Makefile b/Makefile index 2585811..b8f006a 100644 --- a/Makefile +++ b/Makefile @@ -34,11 +34,11 @@ CPPFLAGS = -I$(SRC) $(ALL_DEFINES) EXTRA_DEFINES = -DEFINES = -DFAST # -DNDEBUG -DEFAULTS = -DREVISION_IS_VAR -DGROWABLE_POOL -DINDEX_IN_POOL -DSTORE_IN_POOL \ +DEFINES = # -DTRACE -DNDEBUG +DEFAULTS = -DREVISION_IS_VAR -DGROWABLE_POOL -DSTORE_IN_POOL \ -DNEW_ENTRANCE -DRANDOM_VICTIM -DDOMAIN_BOUNDS -REQUIRED = -DDISTRIBUTED_SOLVER -DSPLITGO -DCOMPACT_DOMAINS -DCONSTRAINT_CLASS \ - -DUSE_STORE -DPACK_PROBLEM +REQUIRED = -DDISTRIBUTED_SOLVER -DSPLITGO -DCOMPACT_DOMAINS -DUSE_STORE \ + -DPACK_PROBLEM ALL_DEFINES = $(REQUIRED) $(DEFAULTS) $(DEFINES) $(EXTRA_DEFINES) @@ -119,6 +119,8 @@ list.o: $(SRC)/list.c $(SRC)/list.h values.o: values.h values-bitmap.c values-intervals.c fdc_int.h +queens queens-mpi : override DEFAULTS += -DDISABLE_ENTAILED + costas costas-mpi : override DEFAULTS += -DCONSTRAINT_TEMPS qap qap-mpi : override DEFAULTS += \ @@ -131,7 +133,7 @@ graphs graphs-mpi : matching.c partition partition-mpi : override DEFAULTS += -DCONSTRAINT_TEMPS -golomb golomb-mpi : override DEFAULTS += -DDOMAIN_BOUNDS +golomb golomb-mpi : override DEFAULTS += -DDOMAIN_BOUNDS -DDOMAIN_BITS=128 langford langford-mpi : override DEFAULTS += \ -UDOMAIN_BOUNDS -DINLINE_DOMAINS -DCONSTRAINT_TEMPS -DDISABLE_ENTAILED diff --git a/README b/README index 6ef4482..fc141fd 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -PaCCS version 0.90d +PaCCS version 0.91 All files Copyright (C) 2009-2016 Vasco Pedro <vp@di.uevora.pt> All rights reserved. @@ -38,7 +38,7 @@ Useful options include: -DDOMAIN_BOUNDS include the domain's current minimum and maximum values in its representation (DEFAULT) - -DFAST be quiet (DEFAULT) + -DTRACE show what's happening (part of it, anyway) For other options, take a look at the Makefile, at src/options.c, or at the full solver source. @@ -150,6 +150,8 @@ Integer constants fd_int fd_new(int min, int max) create a new variable with domain [min, max] + fd_int fd_const(int value) create a new variable with domain + [value, value] fd_label(fd_int vars[], int nvars) set variables to be labelled (the DEFAULT is to label all variables) fd_var_single(fd_int var, int *val) tests whether the variable domain @@ -181,6 +183,10 @@ Global constraints fd_all_different(fd_int X[], int n) all n variables in X have different values + fd_fake_all_different(fd_int X[], int n) + all-different implemented with pairwise fd_ne() constraints + between the variables in X + fd_element(fd_int X[], int n, fd_int y, int k) X[y] = k fd_element_var(fd_int X[], int n, fd_int y, fd_int z) X[y] = z @@ -191,6 +197,7 @@ Global constraints fd_poly_eq(int C[], fd_int Y[], int n, fd_int z) z <= C . Y <= z fd_poly_eq_k(int C[], fd_int Y[], int n, int k) C . Y = k + fd_poly_le_k(int C[], fd_int Y[], int n, int k) C . Y <= k fd_poly_ne(int C[], fd_int Y[], int n, fd_int z) C . Y != z fd_poly_ne_k(int C[], fd_int Y[], int n, int k) C . Y != k fd_knapsack2(fd_int X[], fd_int Y[], int n, fd_int z) z <= X . Y <= z diff --git a/TUNING b/TUNING index d7e2a52..989a7b3 100644 --- a/TUNING +++ b/TUNING @@ -11,11 +11,14 @@ qap costas -DCONSTRAINT_TEMPS -DDOMAIN_BOUNDS --label --most-constrained + (--label --first-var performs better in some cases, at least for the 1st solution) + --split-even (first solution) N <= DOMAIN_BITS / 2 queens + -DDISABLE_ENTAILED -DDOMAIN_BOUNDS ??? [not ism] --first-fail @@ -41,7 +44,7 @@ golomb -DDOMAIN_BOUNDS (-DCONSTRAINT_TEMPS -DDISABLE_ENTAILED [cri-lima]) --label{, --most-connected, --most-constrained} --split-eager - (--split-even is generally slower, but more regular) + (--split-even is generally slower, but more stable) langford [bicho] @@ -59,13 +62,15 @@ langford -DINLINE_DOMAINS -DCONSTRAINT_TEMPS (third best) -DDOMAIN_BOUNDS -DCONSTRAINT_TEMPS -DDISABLE_ENTAILED (fourth best) -DDOMAIN_BOUNDS (fifth best) - - --first-fail --val-max (--count-solutions or failure) - --size-degree --val-max (first solution, not always but when - it works, the effect is dramatic) + [*] + ? -DDOMAIN_BOUNDS --split-eager + --first-fail {,--val-max} (--count-solutions or inconsistent instances) + --size-degree (first solution) + (--first --val-max is a good overall compromise) + golfers -D? --label --val-max? diff --git a/bench/all.c b/bench/all.c index b884130..e18eea5 100644 --- a/bench/all.c +++ b/bench/all.c @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) NV = atoi(argv[i]); if (NV > MAX_VARIABLES) - _fd_fatal("more than MAX_VARIABLES variables requested"); + fd__fatal("more than MAX_VARIABLES variables requested"); for (i = 0; i < NV; ++i) vars[i] = fd_new(0, MV); diff --git a/bench/bibd.c b/bench/bibd.c index bc8d4d6..b4eb355 100644 --- a/bench/bibd.c +++ b/bench/bibd.c @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) #ifndef GECODE_STYLE else if (argc - i < 3) { - _fd_debug("must give V, B, and K (or nothing)\n"); + fd__error("must give V, B, and K (or nothing)\n"); return 1; } else @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) if (R * V != K * B) { - _fd_debug("%d * %d / %d must be an integer\n", K, B, V); + fd__error("%d * %d / %d must be an integer\n", K, B, V); return 1; } @@ -55,13 +55,13 @@ int main(int argc, char *argv[]) if (lambda * (V - 1) != R * (K - 1)) { - _fd_debug("%d * (%d - 1) / (%d - 1) must be an integer\n", R, K, V); + fd__error("%d * (%d - 1) / (%d - 1) must be an integer\n", R, K, V); return 1; } #else /* GECODE_STYLE */ else if (argc - i < 3) { - _fd_debug("must give V, K, and lambda (or nothing)\n"); + fd__error("must give V, K, and lambda (or nothing)\n"); return 1; } else @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) if (B * K * (K - 1) != lambda * V * (V - 1)) { - _fd_debug("warning: %d * %d * (%d - 1) / %d / (%d - 1) must be an integer\n", + fd__error("warning: %d * %d * (%d - 1) / %d / (%d - 1) must be an integer\n", lambda, V, V, K, K); // return 1; } @@ -84,12 +84,12 @@ int main(int argc, char *argv[]) if (R * V != K * B) { - _fd_debug("warning: %d * %d / %d must be an integer\n", K, B, V); + fd__error("warning: %d * %d / %d must be an integer\n", K, B, V); // return 1; } #endif /* GECODE_STYLE */ - _fd_debug("V = %d, B = %d, K = %d, R = %d, lambda = %d\n", V, B, K, R, lambda); + fd__info("V = %d, B = %d, K = %d, R = %d, lambda = %d\n", V, B, K, R, lambda); vs = calloc(V * B, sizeof(fd_int)); ts = calloc(V > B ? V : B, sizeof(fd_int)); diff --git a/bench/c-exactly.c b/bench/c-exactly.c index cc6adab..33a1447 100644 --- a/bench/c-exactly.c +++ b/bench/c-exactly.c @@ -1,10 +1,11 @@ #include <stdio.h> +#include <string.h> -#include "fdc_int.h" +#include <paccs.h> #define N 3 -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { fd_int vs[N], cardinal; int solutions = 0, one_solution = 1; diff --git a/bench/change.c b/bench/change.c index dad765e..977b051 100644 --- a/bench/change.c +++ b/bench/change.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include <fcntl.h> #include <errno.h> #include <ctype.h> @@ -6,13 +7,6 @@ #include "fdc_int.h" -// try to save on variables -static fd_int fd_const[MAX_VALUE + 1]; - -#define FD_CONST(n) (fd_const[n] ? fd_const[n] : (fd_const[n] = fd_new(n, n))) - -//#define FD_CONST(n) fd_new(n, n) - #define NCOINS (sizeof(coins_value) / sizeof(*coins_value)) int coins_value[] = { 1, 2, 5, 10, 20, 50 }; @@ -33,15 +27,15 @@ int main(int argc, char *argv[]) else if (isdigit(*argv[i])) am = atoi(argv[i]); else - _fd_error("%s: unknown argument `%s'\n", argv[0], argv[i]); + fd__error("%s: unknown argument `%s'\n", argv[0], argv[i]); for (i = 0; i < NCOINS; ++i) - coins[i] = FD_CONST(coins_value[i]); + coins[i] = fd_const(coins_value[i]); for (i = 0; i < NCOINS; ++i) change[i] = fd_new(0, MAX_VALUE); - amount = FD_CONST(am); + amount = fd_const(am); fd_knapsack2(change, coins, NCOINS, amount); ncoins = fd_new(0, MAX_VALUE); diff --git a/bench/costas.c b/bench/costas.c index b9d2960..cd0136c 100644 --- a/bench/costas.c +++ b/bench/costas.c @@ -3,17 +3,10 @@ //#include <fcntl.h> //#include <errno.h> -//#include <ctype.h> +#include <ctype.h> #include <string.h> -#include "fdc_int.h" - -// try to save on variables -static fd_int fd_const[MAX_VALUE + 1]; - -#define FD_CONST(n) (fd_const[n] ? fd_const[n] : (fd_const[n] = fd_new(n, n))) - -//#define FD_CONST(n) fd_new(n, n) +#include <paccs.h> /* Costas arrays (communicated by Daniel Diaz) @@ -57,7 +50,7 @@ int main(int argc, char *argv[]) break; } else - _fd_error("%s: unknown option `%s'\n", argv[0], argv[i]); + fd__error("%s: unknown option `%s'\n", argv[0], argv[i]); array = calloc(N, sizeof(*array)); @@ -69,7 +62,7 @@ int main(int argc, char *argv[]) if (strchr(argv[i], '-')) b = atoi(strchr(argv[i], '-') + 1); - array[j] = (a == b) ? FD_CONST(a - 1) : fd_new(a - 1, b - 1); + array[j] = fd_new(a - 1, b - 1); } for (; j < N; ++j) @@ -91,7 +84,7 @@ int main(int argc, char *argv[]) for (j = 0; j < N - 1 - i; ++j) diffs(i, j) = fd_new(0, 2 * (N - 1)); - diffeq[0] = FD_CONST(N - 1); + diffeq[0] = fd_const(N - 1); for (k = 1; k < N - 1; ++k) { diff --git a/bench/golfers.c b/bench/golfers.c index 1d897e7..168ca59 100644 --- a/bench/golfers.c +++ b/bench/golfers.c @@ -34,7 +34,7 @@ int main(int argc, char *argv[]) use_label = 1; else if (argc - i < 3) { - _fd_debug("must give G, K, and W (or nothing)\n"); + fd__error("must give G, K, and W (or nothing)\n"); return 1; } else diff --git a/bench/golomb.c b/bench/golomb.c index 17a1506..b9ff094 100644 --- a/bench/golomb.c +++ b/bench/golomb.c @@ -74,17 +74,17 @@ int main(int argc, char *argv[]) seed = time(0); #else if ((dev_random = open("/dev/urandom", O_RDONLY)) == -1) - _fd_fatal("/dev/urandom: %s\n", strerror(errno)); + fd__fatal("/dev/urandom: %s\n", strerror(errno)); read(dev_random, &seed, sizeof(seed)); #endif srandom(seed); - _fd_debug("seed = %u\n", seed); + fd__trace("seed = %u\n", seed); #endif if (!fixed) - _fd_debug("length upper bound is %d\n", DOMMAX); + fd__trace("length upper bound is %d\n", DOMMAX); D = M * (M - 1) / 2; @@ -147,7 +147,7 @@ int main(int argc, char *argv[]) j = 0; for (d = 1; d < M; ++d) { - fd_int s = fd_new(d * (d + 1) / 2, d * (d + 1) / 2); + fd_int s = fd_const(d * (d + 1) / 2); for (i = d; i < M; ++i) fd_ge(differences[j++], s); @@ -157,7 +157,7 @@ int main(int argc, char *argv[]) j = 0; for (d = 1; d < M; ++d) { - fd_int grl = fd_new(minimum_length[d + 1], minimum_length[d + 1]); + fd_int grl = fd_const(minimum_length[d + 1]); for (i = d; i < M; ++i) fd_ge(differences[j++], grl); diff --git a/bench/graphs.c b/bench/graphs.c index 58b9e2e..3655b7c 100644 --- a/bench/graphs.c +++ b/bench/graphs.c @@ -1,6 +1,7 @@ /* graph colouring � la Gecode */ #include <stdio.h> +#include <stdlib.h> #include <stdint.h> #include <string.h> diff --git a/bench/k-queens.c b/bench/k-queens.c index d923f27..d3192f7 100644 --- a/bench/k-queens.c +++ b/bench/k-queens.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h> @@ -16,8 +17,6 @@ int main(int argc, char *argv[]) fd_int queens[NMAX]; int solutions = 0, one_solution = 1; int i, j; - int seed; - int dev_random; fd_int copy; int ncopies = 4; @@ -41,7 +40,7 @@ int main(int argc, char *argv[]) } if (N > NMAX) - _fd_fatal("queens: more than NMAX queens requested"); + fd__fatal("queens: more than NMAX queens requested"); if (ncopies < 1) ncopies = 1; @@ -49,20 +48,23 @@ int main(int argc, char *argv[]) copy = fd_new(0, ncopies - 1); // XXX: only allows MAX_VALUE+1 copies #ifdef LOCAL_SEARCH + int seed; #if 01 seed = time(0); seed = 1206987119; //seed = 1207917731; // N = 6, best improvement termina //seed = 0; #else - if ((dev_random = open("/dev/urandom", O_RDONLY)) == -1) - _fd_fatal("/dev/urandom: %s\n", strerror(errno)); + int dev_random; + + if ((dev_random = open("/dev/urandom", O_RDONLY)) == -1) + fd__fatal("/dev/urandom: %s\n", strerror(errno)); read(dev_random, &seed, sizeof(seed)); #endif srandom(seed); - _fd_debug("seed = %u\n", seed); + fd__trace("seed = %u\n", seed); #endif /* @@ -118,7 +120,7 @@ int main(int argc, char *argv[]) { int j; - _fd_error("\nsolution contains non-singleton variable\n"); + fd__error("\nsolution contains non-singleton variable\n"); for (j = 0; j < N; ++j) { diff --git a/bench/langford.c b/bench/langford.c index 82d8898..b78a5c7 100644 --- a/bench/langford.c +++ b/bench/langford.c @@ -1,7 +1,9 @@ #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <ctype.h> -#include "fdc_int.h" +#include <paccs.h> // Langford's number problem (CSPLib 024) @@ -58,7 +60,7 @@ int main(int argc, char *argv[]) break; else { - _fd_error("%s: invalid argument `%s'\n", argv[0], argv[arg]); + fd__error("%s: invalid argument `%s'\n", argv[0], argv[arg]); return 2; } @@ -74,7 +76,7 @@ int main(int argc, char *argv[]) //seed = 1206468701; //seed = 1208196137; // converges to a local minimum with MCH srandom(seed); - _fd_debug("seed = %u\n", seed); + fd__trace("seed = %u\n", seed); #endif for (i = 0; arg < argc; ++arg, ++i) diff --git a/bench/magic-seq.c b/bench/magic-seq.c index 1890a2a..24dae1d 100644 --- a/bench/magic-seq.c +++ b/bench/magic-seq.c @@ -1,6 +1,8 @@ #include <stdio.h> +#include <stdlib.h> +#include <string.h> -#include "fdc_int.h" +#include <paccs.h> #define MAX_N 512 @@ -20,7 +22,7 @@ main(int argc, char *argv[]) N = atoi(argv[i]); if (N > MAX_N) - _fd_fatal("N > MAX_N"); + fd__fatal("N > MAX_N"); for (i = 0; i < N; ++i) vs[i] = fd_new(0, N - 1); diff --git a/bench/magic-square.c b/bench/magic-square.c index 9e5e4d9..2baf020 100644 --- a/bench/magic-square.c +++ b/bench/magic-square.c @@ -1,9 +1,10 @@ #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h> -#include "fdc_int.h" +#include <paccs.h> // (CSPLib 019) @@ -37,7 +38,7 @@ int main(int argc, char *argv[]) } if (N > NMAX) - _fd_fatal("magic-square: maximum order exceeded"); + fd__fatal("magic-square: maximum order exceeded"); j = 0; for (++i; i < argc; ++i) @@ -158,7 +159,7 @@ int main(int argc, char *argv[]) for (l = 0; l < N; ++l) for (c = 0; c < N; ++c) if (!fd_var_single(square[l][c], NULL)) - _fd_fatal("solution contains non-singleton variable"); + fd__fatal("solution contains non-singleton variable"); #endif for (l = 0; l < N; ++l) diff --git a/bench/money.c b/bench/money.c index 9355c77..0187ff6 100644 --- a/bench/money.c +++ b/bench/money.c @@ -2,7 +2,7 @@ #include <string.h> #include <ctype.h> -#include "fdc_int.h" +#include <paccs.h> #define LETTERS 26 #define MAX_SIZE (10 * LETTERS) // whatever diff --git a/bench/partition.c b/bench/partition.c index 2ae1cb9..92553e1 100644 --- a/bench/partition.c +++ b/bench/partition.c @@ -3,8 +3,9 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> -#include "fdc_int.h" +#include <paccs.h> int main(int argc, char *argv[]) { @@ -25,7 +26,7 @@ int main(int argc, char *argv[]) if ((vs = malloc(2 * N * sizeof(*vs))) == NULL || (sqs0 = malloc(N * sizeof(*sqs0))) == NULL) - _fd_fatal("could not allocate enough memory"); + fd__fatal("could not allocate enough memory"); values = 2 * N; sum = N * (2 * N + 1); diff --git a/bench/qap.c b/bench/qap.c index df0584d..efa9be7 100644 --- a/bench/qap.c +++ b/bench/qap.c @@ -21,13 +21,6 @@ #include "fdc_int.h" -// try to save on variables -static fd_int fd_const[MAX_VALUE + 1]; - -#define FD_CONST(n) (fd_const[n] ? fd_const[n] : (fd_const[n] = fd_new(n, n))) - -//#define FD_CONST(n) fd_new(n, n) - #define NMAX 128 typedef struct { @@ -249,7 +242,7 @@ int main(int argc, char *argv[]) ; else { - _fd_error("%s: invalid argument `%s'\n", argv[0], argv[j]); + fd__error("%s: invalid argument `%s'\n", argv[0], argv[j]); return 2; } @@ -260,10 +253,10 @@ int main(int argc, char *argv[]) N = P->size; if (N > NMAX) - _fd_fatal("qap: problem too big (increase NMAX)"); + fd__fatal("qap: problem too big (increase NMAX)"); #ifdef QAP_MODEL_B if (N * N > DOMAIN_BITS) - _fd_fatal("qap: problem too big (model B) (increase DOMAIN_BITS)"); + fd__fatal("qap: problem too big (model B) (increase DOMAIN_BITS)"); #endif if (swap) @@ -272,7 +265,7 @@ int main(int argc, char *argv[]) } if (P->name) - _fd_debug("%s\n", P->name); + fd__trace("%s\n", P->name); { int diag_cost = 0, tb = 0; @@ -284,7 +277,7 @@ int main(int argc, char *argv[]) for (c = 0; c < N; ++c) tb += Pflow(l, c) * Pdist(l, c); - _fd_debug("tight bound %d (diagonal %d)\n", tb, diag_cost); + fd__trace("tight bound %d (diagonal %d)\n", tb, diag_cost); } // see if the problem is symmetric @@ -317,11 +310,11 @@ int main(int argc, char *argv[]) if (symmetrical) if (symmetrical0) - _fd_debug("symmetrical problem with 0 diagonal\n"); + fd__trace("symmetrical problem with 0 diagonal\n"); else - _fd_debug("symmetrical problem\n"); + fd__trace("symmetrical problem\n"); else - _fd_debug("asymmetrical problem (%d, %d)\n", l, c); + fd__trace("asymmetrical problem (%d, %d)\n", l, c); if (generic) symmetrical0 = 0; @@ -405,7 +398,7 @@ int main(int argc, char *argv[]) // the *transpose* of the distance matrix for (l = 0; l < N; ++l) for (c = 0; c < N; ++c) - distt[l][c] = FD_CONST(Pdist(c, l)); + distt[l][c] = fd_const(Pdist(c, l)); for (l = 0; l < N; ++l) for (c = 0; c < N; ++c) @@ -430,7 +423,7 @@ int main(int argc, char *argv[]) for (l = 0; l < N; ++l) for (c = 0; c < N; ++c) - distt[l][c] = FD_CONST(Pflow(l, c)); + distt[l][c] = fd_const(Pflow(l, c)); for (l = 0; l < N; ++l) fd_knapsack2(ndist[l], distt[l], N, sums[l]); @@ -443,7 +436,7 @@ int main(int argc, char *argv[]) for (c = 0; c < N; ++c) { prods[0][i] = ndist[l][c]; - prods[1][i] = FD_CONST(Pflow(l, c)); + prods[1][i] = fd_const(Pflow(l, c)); ++i; } @@ -471,7 +464,7 @@ int main(int argc, char *argv[]) for (l = 1; l < N; ++l) for (c = 0; c < l; ++c) - distt[l][c] = FD_CONST(Pflow(l, c)); + distt[l][c] = fd_const(Pflow(l, c)); for (l = 1; l < N; ++l) fd_knapsack2(ndist[l], distt[l], l, sums[l - 1]); @@ -484,7 +477,7 @@ int main(int argc, char *argv[]) for (c = 0; c < l; ++c) { prods[0][i] = ndist[l][c]; - prods[1][i] = FD_CONST(Pflow(l, c)); + prods[1][i] = fd_const(Pflow(l, c)); ++i; } @@ -499,7 +492,7 @@ int main(int argc, char *argv[]) for (c = 0; c < l; ++c) { prods[0][i] = ndist[l][c]; - prods[1][i] = FD_CONST(Pflow(l, c)); + prods[1][i] = fd_const(Pflow(l, c)); ++i; } @@ -540,7 +533,7 @@ int main(int argc, char *argv[]) // distances for (i = 0; i < N * N; ++i) - dist[i] = FD_CONST(P->dist[i]); + dist[i] = fd_const(P->dist[i]); // costs @@ -585,8 +578,8 @@ int main(int argc, char *argv[]) for (l = 0; l < N; ++l) { - new_dist[l * N + l] = FD_CONST(0); - npos[l * N + l] = FD_CONST(0); + new_dist[l * N + l] = fd_const(0); + npos[l * N + l] = fd_const(0); } for (l = 1; l < N; ++l) diff --git a/bench/queens.c b/bench/queens.c index 4b6b4c0..7ba9077 100644 --- a/bench/queens.c +++ b/bench/queens.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h> @@ -32,7 +33,7 @@ int main(int argc, char *argv[]) } if (N > NMAX) - _fd_fatal("queens: more than NMAX queens requested"); + fd__fatal("queens: more than NMAX queens requested"); #ifdef LOCAL_SEARCH #if 01 @@ -42,13 +43,13 @@ int main(int argc, char *argv[]) //seed = 0; #else if ((dev_random = open("/dev/urandom", O_RDONLY)) == -1) - _fd_fatal("/dev/urandom: %s\n", strerror(errno)); + fd__fatal("/dev/urandom: %s\n", strerror(errno)); read(dev_random, &seed, sizeof(seed)); #endif srandom(seed); - _fd_debug("seed = %u\n", seed); + fd__trace("seed = %u\n", seed); #endif /* @@ -104,7 +105,7 @@ int main(int argc, char *argv[]) { int j; - _fd_error("\nsolution contains non-singleton variable\n"); + fd__error("\nsolution contains non-singleton variable\n"); for (j = 0; j < N; ++j) diff --git a/bench/queens2.c b/bench/queens2.c index 48e82e0..1750391 100644 --- a/bench/queens2.c +++ b/bench/queens2.c @@ -1,10 +1,12 @@ /* solves two unconnected queens problems */ #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <fcntl.h> #include <errno.h> -#include "fdc_int.h" +#include <paccs.h> #define NMAX 200 // maximum number of queens @@ -75,8 +77,6 @@ int main(int argc, char *argv[]) fd_int queens[2 * NMAX]; int solutions = 0, one_solution = 1; int i, j; - int seed; - int dev_random; fd_init(&argc, &argv); @@ -92,20 +92,23 @@ int main(int argc, char *argv[]) } #ifdef LOCAL_SEARCH + int seed; #if 01 seed = time(0); seed = 1206987119; //seed = 1207917731; // N = 6, best improvement termina //seed = 0; #else - if ((dev_random = open("/dev/urandom", O_RDONLY)) == -1) - _fd_fatal("/dev/urandom: %s\n", strerror(errno)); + int dev_random; + + if ((dev_random = open("/dev/urandom", O_RDONLY)) == -1) + fd__fatal("/dev/urandom: %s\n", strerror(errno)); read(dev_random, &seed, sizeof(seed)); #endif srandom(seed); - _fd_debug("seed = %u\n", seed); + fd__trace("seed = %u\n", seed); #endif init_queens(queens, N1); @@ -120,7 +123,7 @@ int main(int argc, char *argv[]) #if 01 for (i = 0; i < N1; ++i) if (!fd_var_single(queens[i], NULL)) - _fd_fatal("solution contains non-singleton variable"); + fd__fatal("solution contains non-singleton variable"); #endif for (i = 0; i < N1; ++i) @@ -135,7 +138,7 @@ int main(int argc, char *argv[]) #if 01 for (i = N1; i < N1 + N2; ++i) if (!fd_var_single(queens[i], NULL)) - _fd_fatal("solution contains non-singleton variable"); + fd__fatal("solution contains non-singleton variable"); #endif for (i = N1; i < N1 + N2; ++i) diff --git a/bench/sudoku.c b/bench/sudoku.c index 2506915..02cd2ea 100644 --- a/bench/sudoku.c +++ b/bench/sudoku.c @@ -1,6 +1,8 @@ #include <stdio.h> +#include <stdlib.h> +#include <string.h> -#include "fdc_int.h" +#include <paccs.h> #define floor_sqrt(s, n) {for ((s) = 0; (s) * (s) <= (n); ++(s)); --(s);} @@ -316,7 +318,7 @@ void constrain_piece(fd_int *variables, int nvariables) #endif } -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { fd_int board[N][N]; sudoku_i *problem; @@ -324,16 +326,17 @@ main(int argc, char *argv[]) int sqrN; int solutions = 0, one_solution = 1; int i, j, np = -1; - int seed; fd_init(&argc, &argv); #ifdef LOCAL_SEARCH + int seed; + seed = time(0); //seed = 1206468701; seed = 1208196137; // converges to a local minimum with MCH srandom(seed); - _fd_debug("seed = %u\n", seed); + fd__trace("seed = %u\n", seed); #endif for (i = 1; i < argc; ++i) diff --git a/bench/times.c b/bench/times.c index 8fd7047..18bb4b0 100644 --- a/bench/times.c +++ b/bench/times.c @@ -1,9 +1,8 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> -#include <fdc_int.h> -#include "variables.h" -#include "values.h" +#include <paccs.h> int main(int argc, char *argv[]) { diff --git a/src/VERSION b/src/VERSION index ecde812..0ac647c 100644 --- a/src/VERSION +++ b/src/VERSION @@ -1 +1 @@ -0.90d +0.91 diff --git a/src/agents-splitgo-mpi.c b/src/agents-splitgo-mpi.c index 9d2add4..9188b28 100644 --- a/src/agents-splitgo-mpi.c +++ b/src/agents-splitgo-mpi.c @@ -17,6 +17,8 @@ #include "splitting.h" #include "bound.h" +#include "util.h" + #ifndef COMPACT_DOMAINS #error "only works with COMPACT_DOMAINS" #endif @@ -135,7 +137,7 @@ void _fd_statistics_msgs() { extern int tid; - _fd_output("[%d] messages: %lu sent, %lu received\n", tid, _fd_msgs_sent, + fd__output("[%d] messages: %lu sent, %lu received\n", tid, _fd_msgs_sent, _fd_msgs_received); } #else /* STATS_MSGS */ @@ -214,7 +216,7 @@ int _fd_agent(int n) int result; struct timeval ti, tis, to, tos; - _fd_debug("[%d.%d] agent starting\n", tid, n); + fd__trace("[%d.%d] agent starting\n", tid, n); gettimeofday(&ti, NULL); @@ -238,17 +240,17 @@ int _fd_agent(int n) gettimeofday(&to, NULL); timersub(&to, &tis, &tos); timersub(&to, &ti, &to); - _fd_debug("[%d.%d] took %d.%06ds (%d.%06ds)\n", tid, n, + fd__trace("[%d.%d] took %d.%06ds (%d.%06ds)\n", tid, n, tos.tv_sec, tos.tv_usec, to.tv_sec, to.tv_usec); while (result == FD_OK) { - _fd_debug("[%d.%d] agent was successful\n", tid, n); + fd__trace("[%d.%d] agent was successful\n", tid, n); // ensure that only one agent signals its success // XXX: only good (?) if only looking for the 1st solution pthread_mutex_lock(&success_mutex); - _fd_debug("[%d.%d] acquired success mutex\n", tid, n); + fd__trace("[%d.%d] acquired success mutex\n", tid, n); // tell the main thread that this agent is done if (sem_wait(&ready_semaphore)) @@ -260,14 +262,14 @@ int _fd_agent(int n) perror("sem_post"); pthread_mutex_unlock(&success_mutex); - _fd_debug("[%d.%d] released success mutex\n", tid, n); + fd__trace("[%d.%d] released success mutex\n", tid, n); if (!_fd_optimising) break; if (sem_wait(&resume_semaphore)) perror("sem_post (resume)"); - _fd_debug("[%d.%d] resuming, new bound is %d\n", tid, n, _fd_bound_value()); + fd__trace("[%d.%d] resuming, new bound is %d\n", tid, n, _fd_bound_value()); // find the next solution gettimeofday(&tis, NULL); @@ -277,7 +279,7 @@ int _fd_agent(int n) gettimeofday(&to, NULL); timersub(&to, &tis, &tos); timersub(&to, &ti, &to); - _fd_debug("[%d.%d] took %d.%06ds (%d.%06ds)\n", tid, n, + fd__trace("[%d.%d] took %d.%06ds (%d.%06ds)\n", tid, n, tos.tv_sec, tos.tv_usec, to.tv_sec, to.tv_usec); } @@ -286,7 +288,7 @@ int _fd_agent(int n) break; // eventually, the agent will fail to find a solution - _fd_debug("[%d.%d] agent was unsuccessful\n", tid, n); + fd__trace("[%d.%d] agent was unsuccessful\n", tid, n); // tell the main thread that this agent is done if (sem_wait(&ready_semaphore)) @@ -304,7 +306,7 @@ int _fd_agent(int n) #if STEAL_WORK >= 2 do { // wait for more work - _fd_debug("[%d.%d] waiting for more work\n", tid, n); + fd__trace("[%d.%d] waiting for more work\n", tid, n); pthread_cond_wait(&continue_cond, &continue_mutex); } while(n >= agents_to_run); @@ -325,7 +327,7 @@ int _fd_agent(int n) unsigned long long solutions; struct timeval ti, tis, to, tos; - _fd_debug("[%d.%d] agent starting\n", tid, n); + fd__trace("[%d.%d] agent starting\n", tid, n); gettimeofday(&ti, NULL); @@ -346,10 +348,10 @@ int _fd_agent(int n) gettimeofday(&to, NULL); timersub(&to, &tis, &tos); timersub(&to, &ti, &to); - _fd_debug("[%d.%d] took %d.%06ds (%d.%06ds)\n", tid, n, + fd__trace("[%d.%d] took %d.%06ds (%d.%06ds)\n", tid, n, tos.tv_sec, tos.tv_usec, to.tv_sec, to.tv_usec); - _fd_debug("[%d.%d] found %llu solutions\n", tid, n, solutions); + fd__trace("[%d.%d] found %llu solutions\n", tid, n, solutions); // tell the main thread that this agent is done if (sem_wait(&ready_semaphore)) @@ -370,7 +372,7 @@ int _fd_agent(int n) #if STEAL_WORK >= 2 do { // wait for more work - _fd_debug("[%d.%d] waiting for more work\n", tid, n); + fd__trace("[%d.%d] waiting for more work\n", tid, n); pthread_cond_wait(&continue_cond, &continue_mutex); } while (n >= agents_to_run); @@ -406,7 +408,7 @@ static void _fd_send(int to, int tag) MPI_Request mpi_request = MPI_REQUEST_NULL; if (MPI_Isend(NULL, 0, MPI_CHAR, to, tag, MPI_COMM_WORLD, &mpi_request)) - _fd_fatal("MPI_Isend failed"); + fd__fatal("MPI_Isend failed"); } /* send TO a message with data (non-blocking) */ @@ -415,7 +417,7 @@ static void _fd_send_data(int to, int tag, void *buf, int n, MPI_Datatype type) MPI_Request mpi_request = MPI_REQUEST_NULL; if (MPI_Isend(buf, n, type, to, tag, MPI_COMM_WORLD, &mpi_request)) - _fd_fatal("MPI_Isend failed"); + fd__fatal("MPI_Isend failed"); } #if STEAL_WORK >= 2 @@ -427,26 +429,26 @@ static void _fd_ssend_data(int to, int tag, void *buf, int n, MPI_Datatype type, { #ifndef MAD_MPI if (MPI_Issend(buf, n, type, to, tag, MPI_COMM_WORLD, request)) - _fd_fatal("MPI_Issend failed"); + fd__fatal("MPI_Issend failed"); #if 0 { int mpi_flag; - _fd_debug("[%d] MPI_Test = %d\n", tid, + fd__debug("[%d] MPI_Test = %d\n", tid, MPI_Test(request, &mpi_flag, MPI_STATUS_IGNORE)); if (mpi_flag) - _fd_debug("[%d] send completed\n", tid); + fd__debug("[%d] send completed\n", tid); else - _fd_debug("[%d] send didn't complete yet\n", tid); + fd__debug("[%d] send didn't complete yet\n", tid); } #endif #else /* MAD_MPI */ // XXX: NMAD doesn't have MPI_Issend // XXX: no record of the sending is left if (MPI_Ssend(buf, n, type, to, tag, MPI_COMM_WORLD)) - _fd_fatal("MPI_Send failed"); + fd__fatal("MPI_Send failed"); *request = MPI_REQUEST_NULL; #endif /* MAD_MPI */ @@ -456,7 +458,7 @@ static void _fd_ssend_data(int to, int tag, void *buf, int n, MPI_Datatype type, MPI_Request mpi_request = MPI_REQUEST_NULL; if (MPI_Isend(buf, n, type, to, tag, MPI_COMM_WORLD, &mpi_request)) - _fd_fatal("MPI_Isend failed"); + fd__fatal("MPI_Isend failed"); } } #endif /* STEAL_WORK >= 2 */ @@ -466,7 +468,7 @@ static void fd__send_empty_store(int to, int tag, _fd_store buffer, { if (MPI_Isend(buffer, 0, MPI_DOMAIN_TYPE, to, tag, MPI_COMM_WORLD, request)) - _fd_fatal("MPI_Isend failed"); + fd__fatal("MPI_Isend failed"); } static void _fd_send_store(int to, int tag, _fd_store buffer, @@ -481,7 +483,7 @@ static void _fd_send_store(int to, int tag, _fd_store buffer, { if (MPI_Isend(buffer, fd_variables_count * DOMAIN_WORDS, MPI_DOMAIN_TYPE, to, tag, MPI_COMM_WORLD, request)) - _fd_fatal("MPI_Isend failed"); + fd__fatal("MPI_Isend failed"); } } @@ -492,7 +494,7 @@ static int _fd_recv_store(int from, int tag, _fd_store buffer) if (MPI_Recv(buffer, fd_variables_count * DOMAIN_WORDS, MPI_DOMAIN_TYPE, from, tag, MPI_COMM_WORLD, &status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); MPI_Get_count(&status, MPI_DOMAIN_TYPE, &count); @@ -511,7 +513,7 @@ static void _fd_broadcast(int msg, int processes, int from) mpi_request = malloc(sizeof(MPI_Request)); if (MPI_Isend(NULL, 0, MPI_CHAR, i, msg, MPI_COMM_WORLD, mpi_request)) - _fd_fatal("MPI_Isend failed"); + fd__fatal("MPI_Isend failed"); fd_list_append(pending_requests, mpi_request); } @@ -522,7 +524,7 @@ static void _fd_broadcast(int msg, int processes, int from) for (i = 0; i < processes; ++i) if (i != from) if (MPI_Isend(NULL, 0, MPI_CHAR, i, msg, MPI_COMM_WORLD, &mpi_request)) - _fd_fatal("MPI_Isend failed"); + fd__fatal("MPI_Isend failed"); #endif } @@ -560,9 +562,9 @@ static bool _fd_probe_external(int tag, char *name, int *source, bool consume) if (s) { char es[1024]; int _; - _fd_debug("MPI_Iprobe %s returned %d\n", name, s); + fd__debug("MPI_Iprobe %s returned %d\n", name, s); MPI_Error_string(s, es, &_); - _fd_debug("%s\n", es); + fd__debug("%s\n", es); } #endif @@ -570,13 +572,13 @@ static bool _fd_probe_external(int tag, char *name, int *source, bool consume) { *source = mpi_status.MPI_SOURCE; - _fd_debug("[%d] got %s from %d\n", tid, name, *source); + fd__trace("[%d] got %s from %d\n", tid, name, *source); // consume message if (consume) if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, tag, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); return true; } @@ -590,7 +592,7 @@ static int _fd_get_event(int running, int *source, int *timeout) double tin, tmout = 0; int event; - _fd_debug("[%d] getting next event\n", tid); + fd__trace("[%d] getting next event\n", tid); if (timeout && *timeout) { @@ -606,14 +608,14 @@ static int _fd_get_event(int running, int *source, int *timeout) if (sem_trywait(¬ify_semaphore)) { if (errno == EAGAIN) - ; //_fd_debug("[%d] notify semaphore is busy\n", tid); + ; //fd__trace("[%d] notify semaphore is busy\n", tid); else perror("sem_trywait (notify)"); } else { // got something from one of the agents - _fd_debug("[%d] got something from an agent\n", tid); + fd__trace("[%d] got something from an agent\n", tid); if (!_fd_counting_solutions) { @@ -622,7 +624,7 @@ static int _fd_get_event(int running, int *source, int *timeout) if (sem_post(&ready_semaphore)) perror("sem_post"); - _fd_debug("[%d] got an answer from %s%d\n", tid, + fd__trace("[%d] got an answer from %s%d\n", tid, s == -1 ? "-" : "", s + (s < 0)); if (s >= 0) @@ -719,17 +721,17 @@ static int _fd_get_event(int running, int *source, int *timeout) event = EV_EXT_READY; break; default: - _fd_debug("[%d] unknown tag %d\n", tid, mpi_status.MPI_TAG); - _fd_fatal("unknown tag in message"); + fd__debug("[%d] unknown tag %d\n", tid, mpi_status.MPI_TAG); + fd__fatal("unknown tag in message"); } - _fd_debug("[%d] got %s from %d\n", tid, name, *source); + fd__trace("[%d] got %s from %d\n", tid, name, *source); // consume message if (consume) if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, mpi_status.MPI_TAG, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); break; } @@ -862,22 +864,22 @@ static void _fd_flush_events(int procno) while (mpi_request = fd_list_remove(pending_requests)) { if (MPI_Test(mpi_request, &mpi_flag, MPI_STATUS_IGNORE)) - _fd_debug("[%d] MPI_Test failed\n", procno); + fd__debug("[%d] MPI_Test failed\n", procno); if (!mpi_flag) { #if 0 // this is probably the solution just sent, not cancelling it - _fd_debug("[%d] cancelling request\n", procno); + fd__trace("[%d] cancelling request\n", procno); if (MPI_Cancel(mpi_request)) - _fd_debug("[%d] MPI_Cancel failed\n", procno); + fd__debug("[%d] MPI_Cancel failed\n", procno); - _fd_debug("[%d] waiting for cancellation completion\n", procno); + fd__trace("[%d] waiting for cancellation completion\n", procno); if (MPI_Wait(mpi_request, MPI_STATUS_IGNORE)) - _fd_debug("[%d] MPI_Wait failed\n", procno); + fd__debug("[%d] MPI_Wait failed\n", procno); #else - _fd_debug("[%d] found a not completed request\n", procno); + fd__debug("[%d] found a not completed request\n", procno); #endif } @@ -911,7 +913,7 @@ static void _fd_flush_events(int procno) name = "FD_MSG_SOLUTION"; type = MPI_DOMAIN_TYPE; count = fd_variables_count * DOMAIN_WORDS; - _fd_error("[%d] dropping %s from %d\n", tid, name, source); + fd__error("[%d] dropping %s from %d\n", tid, name, source); break; case FD_MSG_FAIL: name = "FD_MSG_FAIL"; @@ -928,13 +930,13 @@ static void _fd_flush_events(int procno) name = "FD_MSG_COUNT"; type = MPI_LONG_LONG; count = 1; - _fd_error("[%d] dropping %s from %d\n", tid, name, source); + fd__error("[%d] dropping %s from %d\n", tid, name, source); break; case FD_MSG_STORE: name = "FD_MSG_STORE"; type = MPI_DOMAIN_TYPE; count = fd_variables_count * DOMAIN_WORDS; - _fd_error("[%d] *** dropping %s from %d\n", tid, name, source); + fd__error("[%d] *** dropping %s from %d\n", tid, name, source); break; case FD_MSG_FEED_ME: name = "FD_MSG_FEED_ME"; @@ -955,11 +957,11 @@ static void _fd_flush_events(int procno) name = "FD_MSG_READY"; break; default: - _fd_debug("[%d] unknown tag %d\n", tid, mpi_status.MPI_TAG); - _fd_fatal("unknown tag in message"); + fd__debug("[%d] unknown tag %d\n", tid, mpi_status.MPI_TAG); + fd__fatal("unknown tag in message"); } - _fd_debug("[%d] dropping %s from %d\n", tid, name, source); + fd__debug("[%d] dropping %s from %d\n", tid, name, source); // consume message { @@ -967,7 +969,7 @@ static void _fd_flush_events(int procno) if (MPI_Recv(buffer, count, type, source, mpi_status.MPI_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE)) - _fd_error("[%d] MPI_Recv failed (dropping %s)\n", tid, name); + fd__error("[%d] MPI_Recv failed (dropping %s)\n", tid, name); } } #else /* MAD_MPI */ @@ -986,7 +988,7 @@ static void _fd_flush_events(int procno) { _fd_store null = alloca(fd_variables_count * sizeof(*null)); - _fd_debug("[%d] dropping FD_MSG_SOLUTION from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_SOLUTION from %d\n", procno, mpi_status.MPI_SOURCE); _fd_recv_store(mpi_status.MPI_SOURCE, FD_MSG_SOLUTION, null); @@ -997,12 +999,12 @@ static void _fd_flush_events(int procno) if (mpi_flag) { - _fd_debug("[%d] dropping FD_MSG_FEED_ME from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_FEED_ME from %d\n", procno, mpi_status.MPI_SOURCE); // consume message if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, FD_MSG_FEED_ME, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); got_one++; } @@ -1011,12 +1013,12 @@ static void _fd_flush_events(int procno) if (mpi_flag) { - _fd_debug("[%d] dropping FD_MSG_NO_WORK from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_NO_WORK from %d\n", procno, mpi_status.MPI_SOURCE); // consume message if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, FD_MSG_NO_WORK, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); got_one++; } @@ -1027,7 +1029,7 @@ static void _fd_flush_events(int procno) { _fd_store null = alloca(fd_variables_count * sizeof(*null)); - _fd_debug("[%d] dropping FD_MSG_STORE from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_STORE from %d\n", procno, mpi_status.MPI_SOURCE); _fd_recv_store(mpi_status.MPI_SOURCE, FD_MSG_STORE, null); @@ -1038,12 +1040,12 @@ static void _fd_flush_events(int procno) if (mpi_flag) { - _fd_debug("[%d] dropping FD_MSG_FAIL from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_FAIL from %d\n", procno, mpi_status.MPI_SOURCE); // consume message if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, FD_MSG_FAIL, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); got_one++; } @@ -1052,12 +1054,12 @@ static void _fd_flush_events(int procno) if (mpi_flag) { - _fd_debug("[%d] dropping FD_MSG_DONE from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_DONE from %d\n", procno, mpi_status.MPI_SOURCE); // consume message if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, FD_MSG_DONE, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); got_one++; } @@ -1066,12 +1068,12 @@ static void _fd_flush_events(int procno) if (mpi_flag) { - _fd_debug("[%d] dropping FD_MSG_SHARE from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_SHARE from %d\n", procno, mpi_status.MPI_SOURCE); // consume message if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, FD_MSG_SHARE, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); got_one++; } @@ -1080,12 +1082,12 @@ static void _fd_flush_events(int procno) if (mpi_flag) { - _fd_debug("[%d] dropping FD_MSG_NO_SHARE from %d\n", procno, mpi_status.MPI_SOURCE); + fd__trace("[%d] dropping FD_MSG_NO_SHARE from %d\n", procno, mpi_status.MPI_SOURCE); // consume message if (MPI_Recv(NULL, 0, MPI_CHAR, mpi_status.MPI_SOURCE, FD_MSG_NO_SHARE, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); got_one++; } @@ -1102,45 +1104,45 @@ void _fd_cleanup_mpi_state(int process) // a still running process has a chance to see it // XXX: New Madeleine can't cope with messages en route #if 0 //#ifndef MAD_MPI - _fd_debug("[%d] setting up barrier 1\n", process); + fd__trace("[%d] setting up barrier 1\n", process); if (MPI_Barrier(MPI_COMM_WORLD)) - _fd_error("[%d] MPI_Barrier failed\n", process); + fd__error("[%d] MPI_Barrier failed\n", process); else - _fd_debug("[%d] leaving barrier 1\n", process); + fd__trace("[%d] leaving barrier 1\n", process); #endif _fd_flush_events(process); #if 0 - _fd_debug("[%d] setting up barrier 2\n", process); + fd__trace("[%d] setting up barrier 2\n", process); if (MPI_Barrier(MPI_COMM_WORLD)) - _fd_error("[%d] MPI_Barrier failed\n", process); + fd__error("[%d] MPI_Barrier failed\n", process); else - _fd_debug("[%d] leaving barrier 2\n", process); + fd__trace("[%d] leaving barrier 2\n", process); #endif } _fd_statistics_msgs(); - _fd_debug("[%d] calling MPI_Finalize\n", process); + fd__trace("[%d] calling MPI_Finalize\n", process); if (MPI_Finalize()) - _fd_error("[%d] MPI_Finalize failed\n", process); + fd__error("[%d] MPI_Finalize failed\n", process); else - _fd_debug("[%d] returned from MPI_Finalize\n", process); + fd__trace("[%d] returned from MPI_Finalize\n", process); } static void _fd_exit_process(int process) { _fd_cleanup_mpi_state(process); - _fd_debug("[%d] exiting\n", process); + fd__trace("[%d] exiting\n", process); exit(0); } void _fd_search_space_sizes(_fd_store stores[], int n) { -#ifndef FAST +#ifdef TRACE double s; int i, v; @@ -1155,14 +1157,14 @@ void _fd_search_space_sizes(_fd_store stores[], int n) for (v = 0; v < fd__label_vars_count; ++v) s *= _fd_val_size(SVALUE(stores[i][fd__label_vars[v]->index])); - _fd_debug("[%d] search space %d size is %g\n", tid, i, s); + fd__trace("[%d] search space %d size is %g\n", tid, i, s); } -#endif /* FAST */ +#endif /* TRACE */ } static void count_singletons(_fd_store store) { -#ifndef FAST +#ifdef TRACE int i, n; n = 0; @@ -1171,7 +1173,7 @@ static void count_singletons(_fd_store store) if (_fd_val_single(SVALUE(store[i]), NULL)) ++n; - _fd_debug("[%d] store has %d/%d/%d singletons\n", tid, n, + fd__trace("[%d] store has %d/%d/%d singletons\n", tid, n, fd__label_vars_count, fd_variables_count); #endif } @@ -1185,7 +1187,7 @@ static int _fd_restart_agents(int tid, int nagents) parts = fd__split_problem(nagents, _fd_agents_stores, fd__split_team_problem_f); if (parts < nagents) - _fd_debug("[%d] WARNING: store only good for %d agents (out of %d)\n", + fd__debug("[%d] WARNING: store only good for %d agents (out of %d)\n", tid, parts, nagents); agents_to_run = parts; @@ -1200,7 +1202,7 @@ static int _fd_restart_agents(int tid, int nagents) if (pthread_mutex_unlock(&continue_mutex)) perror("pthread_mutex_unlock"); - _fd_debug("[%d] told waiting agents to proceed\n", tid); + fd__trace("[%d] told waiting agents to proceed\n", tid); return parts; } @@ -1222,7 +1224,7 @@ static int _fd_poll_next(int last, int skip) if (poll >= 0) { // send a forceful request for work - _fd_debug("[%d] polling %d\n", tid, poll); + fd__trace("[%d] polling %d\n", tid, poll); _fd_send(poll, FD_MSG_SHARE); } @@ -1261,7 +1263,7 @@ static int _fd_poll_rr(bool starting, int np_or_last, int skip) return -1; // send a forceful request for work - _fd_debug("[%d] polling %d\n", tid, poll); + fd__trace("[%d] polling %d\n", tid, poll); _fd_send(poll, FD_MSG_SHARE); last_polled = poll; @@ -1286,7 +1288,7 @@ static bool _fd_share_work(int peer, MPI_Request *request, fd_list saved_stores, if (!mpi_flag) { // the previous send has not completed - _fd_debug("[%d] there's a store in transit to %d\n", tid, peer); + fd__trace("[%d] there's a store in transit to %d\n", tid, peer); /* despite MPI_Test() having failed, the store may already have been received and processed; since process 0 must receive or @@ -1306,7 +1308,7 @@ static bool _fd_share_work(int peer, MPI_Request *request, fd_list saved_stores, memcpy(_fd_processes_stores[peer], saved, fd_variables_count * sizeof(*saved)); - _fd_debug("[%d] sending store (saved) to %d\n", tid, peer); + fd__trace("[%d] sending store (saved) to %d\n", tid, peer); _fd_send_store(peer, FD_MSG_STORE, _fd_processes_stores[peer], request, true); @@ -1315,13 +1317,9 @@ static bool _fd_share_work(int peer, MPI_Request *request, fd_list saved_stores, return true; } -#ifndef INDEX_IN_POOL - if (_fd_steal_store(_fd_processes_stores[peer], -1, 0)) -#else if (_fd_steal_store(_fd_processes_stores[peer], NULL, -1, 0)) -#endif { - _fd_debug("[%d] sending store to %d\n", tid, peer); + fd__trace("[%d] sending store to %d\n", tid, peer); _fd_send_store(peer, FD_MSG_STORE, _fd_processes_stores[peer], request, true); @@ -1331,12 +1329,12 @@ static bool _fd_share_work(int peer, MPI_Request *request, fd_list saved_stores, // tell the requester that there is no work available if (polled) { - _fd_debug("[%d] no work to share with %d\n", tid, peer); + fd__trace("[%d] no work to share with %d\n", tid, peer); _fd_send(peer, FD_MSG_NO_SHARE); } else { - _fd_debug("[%d] can't find work requested by %d\n", tid, peer); + fd__trace("[%d] can't find work requested by %d\n", tid, peer); _fd_send(peer, FD_MSG_NO_WORK); } @@ -1355,13 +1353,13 @@ static bool _fd_share_work(int peer, MPI_Request *request, fd_list saved_stores, { \ /* record polling process as idle */ \ gettimeofday(&to, NULL); timersub(&to, &ti, &to); \ - _fd_debug("[%d] %d idled after %d.%06ds\n", tid, _p, \ + fd__trace("[%d] %d idled after %d.%06ds\n", tid, _p, \ to.tv_sec, to.tv_usec); \ \ process_idle[_p] = true; \ if (++idle_processes == live_procs - 1) \ { \ - _fd_debug("[%d] sending 2nd quit\n", tid); \ + fd__trace("[%d] sending 2nd quit\n", tid); \ \ _fd_broadcast(FD_MSG_QUIT, processes, tid); \ } \ @@ -1401,21 +1399,21 @@ int _fd_dsolve() gettimeofday(&ti, NULL); if (MPI_Comm_rank(MPI_COMM_WORLD, &tid)) - _fd_fatal("MPI_Comm_rank failed\n"); + fd__fatal("MPI_Comm_rank failed\n"); - _fd_debug("I'm MPI rank %d\n", tid); + fd__trace("I'm MPI rank %d\n", tid); { char host[512]; - gethostname(host, sizeof(host)); - _fd_debug("[%d] process %d at %s\n", tid, getpid(), host); + fd__trace("[%d] process %d at %s\n", tid, getpid(), + (gethostname(host, sizeof(host)), host)); } if (MPI_Comm_size(MPI_COMM_WORLD, &processes)) - _fd_fatal("MPI_Comm_size failed\n"); + fd__fatal("MPI_Comm_size failed\n"); - _fd_debug("[%d] There are %d of us\n", tid, processes); + fd__trace("[%d] There are %d of us\n", tid, processes); pending_requests = fd_list_new(); @@ -1474,7 +1472,7 @@ int _fd_dsolve() parts = fd__split_problem(processes, _fd_processes_stores, fd__split_problem_f); _fd_search_space_sizes(_fd_processes_stores, parts); if (parts < processes) - _fd_error("WARNING: work enough for %d processes only\n", parts); + fd__error("WARNING: work enough for %d processes only\n", parts); // now send the resulting parts to the other processes // XXX: could each have done what this did and now pick its share? @@ -1494,17 +1492,17 @@ int _fd_dsolve() { // code for the remaining processes - _fd_debug("[%d] waiting for initial store\n", tid); + fd__trace("[%d] waiting for initial store\n", tid); // retrieve the domains assigned to the process if (!_fd_recv_store(0, FD_MSG_STORE, store)) { - _fd_debug("[%d] empty initial store\n", tid); + fd__debug("[%d] empty initial store\n", tid); _fd_exit_process(tid); } - _fd_debug("[%d] received initial store\n", tid); + fd__trace("[%d] received initial store\n", tid); } #if FILTER_DOMAINS > 1 @@ -1530,7 +1528,7 @@ int _fd_dsolve() if (parts < nagents) { - _fd_debug("[%d] reducing to %d agents!\n", tid, parts); + fd__trace("[%d] reducing to %d agents!\n", tid, parts); nagents = parts; } @@ -1542,7 +1540,7 @@ int _fd_dsolve() gettimeofday(&to, NULL); timersub(&to, &ti, &to); - _fd_debug("[%d] setup took %d.%06ds\n", tid, to.tv_sec, to.tv_usec); + fd__trace("[%d] setup took %d.%06ds\n", tid, to.tv_sec, to.tv_usec); #if 0 for (i = 0; i < nagents; ++i) @@ -1593,7 +1591,7 @@ int _fd_dsolve() } } - _fd_debug("[%d] main thread waiting\n", tid); + fd__trace("[%d] main thread waiting\n", tid); running = started; live_procs = processes; @@ -1607,7 +1605,7 @@ int _fd_dsolve() { #if STEAL_WORK >= 2 case EV_INT_TIMEOUT: - _fd_debug("[%d] timed out waiting for event\n", tid); + fd__trace("[%d] timed out waiting for event\n", tid); switch (waiting_on) { @@ -1644,7 +1642,7 @@ int _fd_dsolve() else { // resend request for work - _fd_debug("[%d] re-asking for work\n", tid); + fd__trace("[%d] re-asking for work\n", tid); _fd_broadcast(FD_MSG_FEED_ME, processes, tid); timeout = FEED2_TIMEOUT; @@ -1687,8 +1685,8 @@ int _fd_dsolve() break; default: - _fd_debug("[%d] unknown timeout: %d\n", tid, waiting_on); - _fd_fatal("unknown timeout reason"); + fd__debug("[%d] unknown timeout: %d\n", tid, waiting_on); + fd__fatal("unknown timeout reason"); } break; @@ -1697,7 +1695,7 @@ int _fd_dsolve() /* first solution internal events (from the workers) */ case EV_INT_SUCCESS: - _fd_debug("[%d] using agent %d's results\n", tid, peer); + fd__trace("[%d] using agent %d's results\n", tid, peer); assert(!_fd_counting_solutions); @@ -1706,7 +1704,7 @@ int _fd_dsolve() // check and update bound if (!_fd_bound_check_set(_fd_agents_stores[peer])) { - _fd_debug("[%d] invalid solution, releasing %d\n", tid, peer); + fd__trace("[%d] invalid solution, releasing %d\n", tid, peer); if (sem_post(&resume_semaphore)) perror("sem_post (resume)"); @@ -1720,11 +1718,11 @@ int _fd_dsolve() fd_variables_count * sizeof(*solution)); // release agent - _fd_debug("[%d] releasing agent %d\n", tid, peer); + fd__trace("[%d] releasing agent %d\n", tid, peer); if (sem_post(&resume_semaphore)) perror("sem_post (resume)"); - _fd_debug("[%d] bound updated to %d\n", tid, _fd_bound_value()); + fd__trace("[%d] bound updated to %d\n", tid, _fd_bound_value()); // broadcast new bound bound = _fd_bound_value(); @@ -1746,7 +1744,7 @@ int _fd_dsolve() break; case EV_INT_FAIL: - _fd_debug("[%d] agent %d found no solution\n", tid, peer); + fd__trace("[%d] agent %d found no solution\n", tid, peer); assert(!_fd_counting_solutions); @@ -1770,7 +1768,7 @@ int _fd_dsolve() { if (!supplier) { - _fd_debug("[%d] asking for work\n", tid); + fd__trace("[%d] asking for work\n", tid); _fd_broadcast(FD_MSG_FEED_ME, processes, tid); waiting_on = FD_MSG_FEED_ME; @@ -1802,7 +1800,7 @@ int _fd_dsolve() // see if there's some store saved up if (saved = fd_list_remove(saved_stores)) { - _fd_debug("[%d] using saved store\n", tid); + fd__trace("[%d] using saved store\n", tid); memcpy(store, saved, fd_variables_count * sizeof(*saved)); @@ -1840,7 +1838,7 @@ int _fd_dsolve() if (!supplier) { // ask the other processes for more work - _fd_debug("[%d] asking for work\n", tid); + fd__trace("[%d] asking for work\n", tid); _fd_broadcast(FD_MSG_FEED_ME, processes, tid); waiting_on = FD_MSG_FEED_ME; @@ -1873,18 +1871,18 @@ int _fd_dsolve() /* first solution external events (from the other processes) */ case EV_EXT_SUCCESS: - _fd_debug("[%d] received a solution from %d\n", tid, peer); + fd__trace("[%d] received a solution from %d\n", tid, peer); assert(!_fd_counting_solutions); _fd_recv_store(peer, FD_MSG_SOLUTION, store); - _fd_debug("[%d] using process %d's results\n", tid, peer); + fd__trace("[%d] using process %d's results\n", tid, peer); gettimeofday(&to, NULL); timersub(&to, &ti, &to); -#if defined(STATS_PROCS) || !defined(FAST) - fd__info("[%d] process %d took %d.%06ds\n", tid, peer, to.tv_sec, to.tv_usec); +#if defined(STATS_PROCS) || defined(TRACE) + fd__debug("[%d] process %d took %d.%06ds\n", tid, peer, to.tv_sec, to.tv_usec); #endif if (_fd_optimising) @@ -1892,7 +1890,7 @@ int _fd_dsolve() // see if it is the better solution if (!have_solution || _fd_better_solution(store, solution)) { - _fd_debug("[%d] process %d solution is better\n", tid, peer); + fd__trace("[%d] process %d solution is better\n", tid, peer); memcpy(solution, store, fd_variables_count * sizeof(*store)); @@ -1916,14 +1914,14 @@ int _fd_dsolve() break; case EV_EXT_FAIL: - _fd_debug("[%d] process %d found no solution\n", tid, peer); + fd__trace("[%d] process %d found no solution\n", tid, peer); assert(!_fd_counting_solutions); gettimeofday(&to, NULL); timersub(&to, &ti, &to); -#if defined(STATS_PROCS) || !defined(FAST) - fd__info("[%d] process %d took %d.%06ds\n", tid, peer, to.tv_sec, to.tv_usec); +#if defined(STATS_PROCS) || defined(TRACE) + fd__debug("[%d] process %d took %d.%06ds\n", tid, peer, to.tv_sec, to.tv_usec); #endif live_procs--; @@ -1943,7 +1941,7 @@ int _fd_dsolve() break; case EV_EXT_DONE: - _fd_debug("[%d] process %d told me to stop\n", tid, peer); + fd__trace("[%d] process %d told me to stop\n", tid, peer); assert(!_fd_counting_solutions); @@ -1954,7 +1952,7 @@ int _fd_dsolve() /* optimisation external events (from the other processes) */ case EV_EXT_BOUND: - _fd_debug("[%d] received new bound from %d\n", tid, peer); + fd__trace("[%d] received new bound from %d\n", tid, peer); assert(!_fd_counting_solutions && _fd_optimising); @@ -1963,24 +1961,24 @@ int _fd_dsolve() if (MPI_Recv(&bound, 1, MPI_INT, peer, FD_MSG_BOUND, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); // try to set new bound if (_fd_set_bound(bound)) { - _fd_debug("[%d] new bound is %d\n", tid, bound); + fd__trace("[%d] new bound is %d\n", tid, bound); // bound has been reset, invalidate previous solution if (have_solution && !_fd_bound_check(solution)) { - _fd_debug("[%d] invalidating current solution\n", tid); + fd__trace("[%d] invalidating current solution\n", tid); status = FD_NOSOLUTION; have_solution = false; } } else - _fd_debug("[%d] invalid bound %d\n", tid, bound); + fd__trace("[%d] invalid bound %d\n", tid, bound); } break; @@ -1988,7 +1986,7 @@ int _fd_dsolve() /* counting solutions internal events (from the workers) */ case EV_INT_COUNT: - _fd_debug("[%d] agent %d is done\n", tid, peer); + fd__trace("[%d] agent %d is done\n", tid, peer); assert(_fd_counting_solutions); @@ -2012,7 +2010,7 @@ int _fd_dsolve() { if (!supplier) { - _fd_debug("[%d] asking for work\n", tid); + fd__trace("[%d] asking for work\n", tid); _fd_broadcast(FD_MSG_FEED_ME, processes, tid); waiting_on = FD_MSG_FEED_ME; @@ -2044,7 +2042,7 @@ int _fd_dsolve() // see if there's some store saved up if (saved = fd_list_remove(saved_stores)) { - _fd_debug("[%d] using saved store\n", tid); + fd__trace("[%d] using saved store\n", tid); memcpy(store, saved, fd_variables_count * sizeof(*saved)); @@ -2082,7 +2080,7 @@ int _fd_dsolve() if (!supplier) { // ask the other processes for more work - _fd_debug("[%d] asking for work\n", tid); + fd__trace("[%d] asking for work\n", tid); _fd_broadcast(FD_MSG_FEED_ME, processes, tid); waiting_on = FD_MSG_FEED_ME; @@ -2115,7 +2113,7 @@ int _fd_dsolve() /* counting solutions external events (from the other processes) */ case EV_EXT_COUNT: - _fd_debug("[%d] receiving count from %d\n", tid, peer); + fd__trace("[%d] receiving count from %d\n", tid, peer); assert(_fd_counting_solutions); @@ -2124,17 +2122,17 @@ int _fd_dsolve() if (MPI_Recv(&ull, 1, MPI_LONG_LONG, peer, FD_MSG_COUNT, MPI_COMM_WORLD, &mpi_status)) - _fd_fatal("MPI_Recv failed"); + fd__fatal("MPI_Recv failed"); external_solutions += ull; - _fd_debug("[%d] process %d found %llu solutions\n", tid, peer, ull); + fd__trace("[%d] process %d found %llu solutions\n", tid, peer, ull); } gettimeofday(&to, NULL); timersub(&to, &ti, &to); -#if defined(STATS_PROCS) || !defined(FAST) - fd__info("[%d] process %d took %d.%06ds\n", tid, peer, to.tv_sec, to.tv_usec); +#if defined(STATS_PROCS) || defined(TRACE) + fd__debug("[%d] process %d took %d.%06ds\n", tid, peer, to.tv_sec, to.tv_usec); #endif live_procs--; @@ -2158,9 +2156,9 @@ int _fd_dsolve() /* work stealing events (external) */ case EV_EXT_STORE: - _fd_debug("[%d] process %d sent a store\n", tid, peer); + fd__trace("[%d] process %d sent a store\n", tid, peer); -if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); +if (waiting_on == FD_MSG_ANY) fd__trace("[%d] recovered store\n", tid); if (running == 0) { @@ -2198,7 +2196,7 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); break; case EV_EXT_REQ_WORK: - _fd_debug("[%d] process %d wants more work\n", tid, peer); + fd__trace("[%d] process %d wants more work\n", tid, peer); if (supplier) { @@ -2216,7 +2214,7 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); break; case EV_EXT_NO_WORK: - _fd_debug("[%d] process %d can't supply work\n", tid, peer); + fd__trace("[%d] process %d can't supply work\n", tid, peer); // no work sharing after having been told to stop if (quitting || ready) @@ -2268,7 +2266,7 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); break; case EV_EXT_NO_SHARE: - _fd_debug("[%d] process %d can't share work\n", tid, peer); + fd__trace("[%d] process %d can't share work\n", tid, peer); // no work sharing after having been told to stop if (quitting || ready) @@ -2284,7 +2282,7 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); if (peer != polling) { - _fd_debug("[%d] polling %d but got answer from %d\n", + fd__trace("[%d] polling %d but got answer from %d\n", tid, polling, peer); // belated answer, ignore @@ -2331,14 +2329,14 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); break; case EV_EXT_REQ_SHARE: - _fd_debug("[%d] process %d really wants work\n", tid, peer); + fd__trace("[%d] process %d really wants work\n", tid, peer); // if we're idle, there's nothing to share if (running == 0 || quitting || ready) // XXX: could be < nagents { // notify the asking process that there really isn't // work to be shared - _fd_debug("[%d] no work to share with %d\n", tid, peer); + fd__trace("[%d] no work to share with %d\n", tid, peer); _fd_send(peer, FD_MSG_NO_SHARE); break; @@ -2352,14 +2350,14 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); break; case EV_EXT_READY: // peer has no work and no outgoing communications pending - _fd_debug("[%d] %d is done\n", tid, peer); + fd__trace("[%d] %d is done\n", tid, peer); assert(tid == 0); mark_process_idle(peer); // XXX: in mark_process_idle() - //_fd_debug("[%d] sending 2nd quit\n", tid); + //fd__trace("[%d] sending 2nd quit\n", tid); //_fd_broadcast(FD_MSG_QUIT, processes, tid); //done = running == 0 && live_procs == 1; @@ -2371,7 +2369,7 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); break; case EV_EXT_QUIT: // possibilities for finding work have been exhausted - _fd_debug("[%d] %d told me to stop\n", tid, peer); + fd__trace("[%d] %d told me to stop\n", tid, peer); assert(tid != 0); @@ -2385,12 +2383,12 @@ if (waiting_on == FD_MSG_ANY) _fd_debug("[%d] recovered store\n", tid); break; #endif /* STEAL_WORK >= 2 */ default: - _fd_debug("[%d] unknown event in main loop: %d\n", tid, event); - _fd_fatal("unknown event in main loop"); + fd__debug("[%d] unknown event in main loop: %d\n", tid, event); + fd__fatal("unknown event in main loop"); } #if STEAL_WORK >= 2 -if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid, quitting, ready, timeout); +if (done) fd__trace("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid, quitting, ready, timeout); // if it is important that the full search space is explored, // make an extra effort for receiving messages that may have @@ -2400,7 +2398,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid _fd_optimising || status != FD_OK && !stopped)) { - _fd_debug("[%d] checking for any event before leaving\n", tid); + fd__trace("[%d] checking for any event before leaving\n", tid); done = 0; waiting_on = FD_MSG_ANY; @@ -2438,14 +2436,14 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (!mpi_flag) // request hasn't completed { - _fd_debug("[%d] recovering outstanding store to %d\n", + fd__trace("[%d] recovering outstanding store to %d\n", tid, i); // try cancelling the send (or the cancel?) if (MPI_Cancel(stores_pending + i)) perror("MPI_Cancel"); - _fd_debug("[%d] cancelled request\n", tid); + fd__trace("[%d] cancelled request\n", tid); // allow the cancel some time to complete do @@ -2457,7 +2455,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (mpi_flag) break; - _fd_debug("[%d] cancelling store to %d didn't complete\n", + fd__trace("[%d] cancelling store to %d didn't complete\n", tid, i); if (--tries == 0) @@ -2469,7 +2467,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (!mpi_flag) // cancel didn't complete, give up for now { - _fd_debug("[%d] giving up cancelling store to %i for now\n", + fd__trace("[%d] giving up cancelling store to %i for now\n", tid, i); // if no store is cancelled, will have to wait @@ -2482,7 +2480,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid continue; } - _fd_debug("[%d] status = (%d, %d, %d, %d, %d)\n", tid, + fd__trace("[%d] status = (%d, %d, %d, %d, %d)\n", tid, mpi_status.MPI_SOURCE, mpi_status.MPI_TAG, mpi_status.MPI_ERROR, mpi_status._count, mpi_status._cancelled); @@ -2491,12 +2489,12 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (!mpi_flag) { - _fd_debug("[%d] cancel did not succeed\n", tid); + fd__trace("[%d] cancel did not succeed\n", tid); continue; } - _fd_debug("[%d] cancel succeeded\n", tid); + fd__trace("[%d] cancel succeeded\n", tid); } else { @@ -2506,7 +2504,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (!mpi_flag) continue; // the send has completed - _fd_debug("[%d] previously cancelled store to %d\n", + fd__trace("[%d] previously cancelled store to %d\n", tid, i); } @@ -2533,7 +2531,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid { if (tid != 0) { - _fd_debug("[%d] ready to leave\n", tid); + fd__trace("[%d] ready to leave\n", tid); _fd_send(0, FD_MSG_READY); @@ -2566,11 +2564,11 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid // stop the other processes if (live_procs > 1) { - _fd_debug("[%d] stopping all processes\n", tid); + fd__trace("[%d] stopping all processes\n", tid); _fd_broadcast(FD_MSG_DONE, processes, tid); } else - _fd_debug("[%d] all other processes already stopped\n", tid); + fd__trace("[%d] all other processes already stopped\n", tid); if (_fd_optimising && status == FD_OK) { @@ -2581,7 +2579,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (ts.tv_sec) { timersub(&ts, &ti, &ts); - _fd_debug("[%d] time to solution was %d.%06ds\n", tid, + fd__trace("[%d] time to solution was %d.%06ds\n", tid, ts.tv_sec, ts.tv_usec); } } @@ -2594,7 +2592,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid { MPI_Request *mpi_request = malloc(sizeof(MPI_Request)); - _fd_debug("[%d] sending solution\n", tid); + fd__trace("[%d] sending solution\n", tid); if (_fd_optimising) assert(have_solution); @@ -2605,7 +2603,7 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (ts.tv_sec) { timersub(&ts, &ti, &ts); - _fd_debug("[%d] time to solution was %d.%06ds\n", tid, + fd__trace("[%d] time to solution was %d.%06ds\n", tid, ts.tv_sec, ts.tv_usec); } @@ -2613,19 +2611,19 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid } else { - _fd_debug("[%d] sending failure notice\n", tid); + fd__trace("[%d] sending failure notice\n", tid); _fd_send(0, FD_MSG_FAIL); } } // stop all the agents - _fd_debug("[%d] stopping agents\n", tid); + fd__trace("[%d] stopping agents\n", tid); for (i = 0; i < started; ++i) { int s; if ((s = pthread_cancel(threads[i])) && s != ESRCH) - _fd_debug("[%d] error cancelling thread %d = %d\n", tid, i, s); + fd__debug("[%d] error cancelling thread %d = %d\n", tid, i, s); } // make sure all agents have stopped before exiting @@ -2634,9 +2632,9 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid { int s; - _fd_debug("[%d] joining agent %d\n", tid, i); + fd__trace("[%d] joining agent %d\n", tid, i); if ((s = pthread_join(threads[i], NULL)) && s != ESRCH) - _fd_debug("[%d] error joining thread %d = %d\n", tid, i, s); + fd__debug("[%d] error joining thread %d = %d\n", tid, i, s); } #if STEAL_WORK >= 2 @@ -2652,13 +2650,13 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid #if STEAL_WORK >= 2 // stop all the agents, which are waiting for work - _fd_debug("[%d] stopping agents\n", tid); + fd__trace("[%d] stopping agents\n", tid); for (i = 0; i < started; ++i) { int s; if ((s = pthread_cancel(threads[i])) && s != ESRCH) - _fd_debug("[%d] error cancelling thread %d = %d\n", tid, i, s); + fd__debug("[%d] error cancelling thread %d = %d\n", tid, i, s); } // make sure all agents have stopped before exiting @@ -2666,13 +2664,13 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid { int s; - _fd_debug("[%d] joining agent %d\n", tid, i); + fd__trace("[%d] joining agent %d\n", tid, i); if ((s = pthread_join(threads[i], NULL)) && s != ESRCH) - _fd_debug("[%d] error joining thread %d = %d\n", tid, i, s); + fd__debug("[%d] error joining thread %d = %d\n", tid, i, s); } if (!fd_list_empty(saved_stores)) - _fd_fatal("saved_stores not empty on exit"); + fd__fatal("saved_stores not empty on exit"); fd_list_dispose(saved_stores); #endif /* STEAL_WORK >= 2 */ @@ -2699,15 +2697,15 @@ if (done) _fd_debug("[%d] done (quitting = %d, ready = %d, timeout = %d)\n", tid if (_fd_counting_solutions) { - _fd_output("found %llu solutions\n", total_solutions + external_solutions); // XXX + fd__output("found %llu solutions\n", total_solutions + external_solutions); // XXX status = FD_NOSOLUTION; // XXX } gettimeofday(&to, NULL); timersub(&to, &ti, &to); -#if defined(STATS_PROCS) || !defined(FAST) - fd__info("process %d took %d.%06ds\n", tid, to.tv_sec, to.tv_usec); +#if defined(STATS_PROCS) || defined(TRACE) + fd__debug("process %d took %d.%06ds\n", tid, to.tv_sec, to.tv_usec); #endif return status; diff --git a/src/agents-splitgo.c b/src/agents-splitgo.c index 3e97a23..c448c8d 100644 --- a/src/agents-splitgo.c +++ b/src/agents-splitgo.c @@ -13,6 +13,8 @@ #include "splitting.h" #include "bound.h" +#include "util.h" + #ifndef COMPACT_DOMAINS #error "only works with COMPACT_DOMAINS" #endif @@ -81,7 +83,7 @@ int _fd_agent(int n) int result; struct timeval ti, tis, to, tos; - _fd_debug("starting agent %d\n", n); + fd__trace("starting agent %d\n", n); gettimeofday(&ti, NULL); @@ -93,11 +95,11 @@ int _fd_agent(int n) gettimeofday(&to, NULL); timersub(&to, &ti, &to); - _fd_debug("agent %d took %d.%06ds\n", n, to.tv_sec, to.tv_usec); + fd__trace("agent %d took %d.%06ds\n", n, to.tv_sec, to.tv_usec); while (result == FD_OK) { - _fd_debug("agent %d was successful\n", n); + fd__trace("agent %d was successful\n", n); // ensure that only one agent signals its success // XXX: only good (?) if only looking for the 1st solution @@ -106,7 +108,7 @@ int _fd_agent(int n) // in sem_wait() pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &success_mutex); - _fd_debug("agent %d acquired success mutex\n", n); + fd__trace("agent %d acquired success mutex\n", n); // tell the main thread that this agent is done if (sem_wait(&ready_semaphore)) @@ -119,14 +121,14 @@ int _fd_agent(int n) pthread_mutex_unlock(&success_mutex); pthread_cleanup_pop(0); - _fd_debug("agent %d released success mutex\n", n); + fd__trace("agent %d released success mutex\n", n); if (!_fd_optimising) return result; if (sem_wait(&resume_semaphore)) perror("sem_post (resume)"); - _fd_debug("[%d] resuming, new bound is %d\n", n, _fd_bound_value()); + fd__trace("[%d] resuming, new bound is %d\n", n, _fd_bound_value()); // find the next solution gettimeofday(&tis, NULL); @@ -136,12 +138,12 @@ int _fd_agent(int n) gettimeofday(&to, NULL); timersub(&to, &tis, &tos); timersub(&to, &ti, &to); - _fd_debug("agent %d took %d.%06ds (%d.%06ds)\n", n, + fd__trace("agent %d took %d.%06ds (%d.%06ds)\n", n, tos.tv_sec, tos.tv_usec, to.tv_sec, to.tv_usec); } // eventually, the agent will fail to find a solution - _fd_debug("agent %d was unsuccessful\n", n); + fd__trace("agent %d was unsuccessful\n", n); // tell the main thread that this agent is done if (sem_wait(&ready_semaphore)) @@ -159,7 +161,7 @@ int _fd_agent(int n) unsigned long long solutions; struct timeval ti, to; - _fd_debug("starting agent %d\n", n); + fd__trace("starting agent %d\n", n); gettimeofday(&ti, NULL); @@ -171,9 +173,9 @@ int _fd_agent(int n) gettimeofday(&to, NULL); timersub(&to, &ti, &to); - _fd_debug("agent %d took %d.%06ds\n", n, to.tv_sec, to.tv_usec); + fd__trace("agent %d took %d.%06ds\n", n, to.tv_sec, to.tv_usec); - _fd_debug("agent %d found %llu solutions\n", n, solutions); + fd__trace("agent %d found %llu solutions\n", n, solutions); // tell the main thread that this agent is done if (sem_wait(&ready_semaphore)) @@ -193,7 +195,7 @@ int _fd_agent(int n) void _fd_search_space_sizes(_fd_store stores[], int n) { -#ifndef FAST +#ifdef TRACE double s; int i, v; @@ -208,9 +210,9 @@ void _fd_search_space_sizes(_fd_store stores[], int n) for (v = 0; v < fd__label_vars_count; ++v) s *= _fd_val_size(SVALUE(stores[i][fd__label_vars[v]->index])); - _fd_debug("search space %d size is %g\n", i, s); + fd__trace("search space %d size is %g\n", i, s); } -#endif /* FAST */ +#endif /* TRACE */ } int _fd_dsolve() @@ -265,7 +267,7 @@ int _fd_dsolve() if (parts < nagents) { - _fd_debug("reducing to %d agents!\n", parts); + fd__trace("reducing to %d agents!\n", parts); nagents = parts; } @@ -274,7 +276,7 @@ int _fd_dsolve() gettimeofday(&to, NULL); timersub(&to, &ti, &to); - _fd_debug("setup took %d.%06ds\n", to.tv_sec, to.tv_usec); + fd__trace("setup took %d.%06ds\n", to.tv_sec, to.tv_usec); #if 0 for (i = 0; i < nagents; ++i) @@ -316,7 +318,7 @@ int _fd_dsolve() } } - _fd_debug("main thread waiting\n"); + fd__trace("main thread waiting\n"); running = started; do @@ -329,7 +331,7 @@ int _fd_dsolve() if (sem_post(&ready_semaphore)) perror("sem_post"); - _fd_debug("got an answer from %s%d\n", solver == -1 ? "-" : "", + fd__trace("got an answer from %s%d\n", solver == -1 ? "-" : "", solver + (solver < 0)); if (_fd_optimising && solver >= 0) @@ -344,10 +346,10 @@ int _fd_dsolve() memcpy(store, _fd_agents_stores[solver], fd_variables_count * sizeof(*store)); - _fd_debug("releasing %d\n", solver); + fd__trace("releasing %d\n", solver); } else - _fd_debug("invalid solution, releasing %d\n", solver); + fd__trace("invalid solution, releasing %d\n", solver); if (sem_post(&resume_semaphore)) perror("sem_post (resume)"); @@ -359,14 +361,14 @@ int _fd_dsolve() } while ((_fd_optimising || solver < 0) && running > 0); - _fd_debug("%s solution\n", solver < 0 ? "found no" : "got a"); + fd__trace("%s solution\n", solver < 0 ? "found no" : "got a"); for (i = 0; i < started; ++i) { int s; if ((s = pthread_cancel(threads[i])) && s != ESRCH) - _fd_debug("error cancelling thread %d = %d\n", i, s); + fd__debug("error cancelling thread %d = %d\n", i, s); } // make sure all agents have stopped before exiting @@ -376,24 +378,26 @@ int _fd_dsolve() int s; if ((s = pthread_join(threads[i], NULL)) && s != ESRCH) - _fd_debug("error joining thread %d = %d\n", i, s); + fd__debug("error joining thread %d = %d\n", i, s); } if (_fd_optimising) { if (have_solution >= 0) { - _fd_debug("using agent %d's results\n", have_solution); + fd__trace("using agent %d's results\n", have_solution); +#if defined(STATS_TIME_SOLUTION) || defined(TRACE) timersub(&ts, &ti, &ts); - _fd_debug("time to solution was %d.%06ds\n", ts.tv_sec, ts.tv_usec); + fd__debug("time to solution was %d.%06ds\n", ts.tv_sec, ts.tv_usec); +#endif status = FD_OK; } } else if (solver >= 0) { - _fd_debug("using agent %d's results\n", solver); + fd__trace("using agent %d's results\n", solver); status = FD_OK; @@ -404,7 +408,7 @@ int _fd_dsolve() else /* agents == 0 */ { if (_fd_optimising) - _fd_fatal("need at least one agent when optimising"); + fd__fatal("need at least one agent when optimising"); _fd_agents_stores[0] = store; @@ -439,7 +443,7 @@ int _fd_dsolve() started++; } - _fd_debug("main thread waiting\n"); + fd__trace("main thread waiting\n"); running = started; do @@ -465,7 +469,7 @@ int _fd_dsolve() _fd_statistics_steal(); - _fd_output("found %llu solutions\n", total_solutions); // XXX + fd__output("found %llu solutions\n", total_solutions); // XXX return FD_NOSOLUTION; // XXX } diff --git a/src/bound.c b/src/bound.c index db7b757..5fe52c7 100644 --- a/src/bound.c +++ b/src/bound.c @@ -5,8 +5,10 @@ #include "fdc_int.h" #include "store.h" - #include "bound.h" +#include "constraints.h" + +#include "util.h" bool _fd_optimising = false; @@ -32,10 +34,10 @@ _fd_bound_data *_fd_init_bound(int n, C_VAR_T v, fd_constraint c, _fd_bound_data *b; if (_fd_bound) - _fd_fatal("trying to set a 2nd optimisation constraint"); + fd__fatal("trying to set a 2nd optimisation constraint"); if ((b = malloc(sizeof(*_fd_bound))) == NULL) - _fd_fatal("could not allocate memory for the optimisation bound"); + fd__fatal("could not allocate memory for the optimisation bound"); b->value = n; b->variable = v; @@ -121,9 +123,7 @@ int fd__bound_and_revise() if (_fd_revise_wrt_variable(_fd_bound_variable()) == FD_NOSOLUTION) { -#ifdef CONSTRAINT_TEMPS fd__constraint_data_reset(); -#endif return FD_NOSOLUTION; } diff --git a/src/constraints.c b/src/constraints.c index b7a487d..e178455 100644 --- a/src/constraints.c +++ b/src/constraints.c @@ -7,31 +7,46 @@ #include "variables.h" #include "constraints.h" +#include "util.h" + #define MAX_CONSTRAINTS (512 * 512) int _fd_constraint_count = 0; fd_constraint _fd_constraints[MAX_CONSTRAINTS]; -#ifdef CONSTRAINT_TEMPS + +#define CONSTRAINT_INITIALISATION(name, code) \ + static void fd_ ## name ## _init(_fd_constraint_class data[]) \ + { \ + data[code].propagator2 = fd_ ## name ## _propagate2; \ + data[code].filter = fd_ ## name ## _filter; \ + } + +#define initialise_constraint(name) fd_ ## name ## _init(_fd_constraint_data) + + +#ifdef CONSTRAINTS_HAVE_STATE #define CSTR_DATA_VALID 0x01 #define CSTR_ENTAILED 0x02 static __thread uint8_t constraint_state_info[MAX_CONSTRAINTS]; +# ifdef CONSTRAINT_TEMPS static __thread void *constraint_memory[MAX_CONSTRAINTS]; -#endif +# endif +#endif /* CONSTRAINTS_HAVE_STATE */ /* generic functions */ -fd_constraint _fd_constraint_new(int nvariables, int nconstants) +fd_constraint fd__constraint_new(int nvariables, int nconstants) { fd_constraint c; if (_fd_constraint_count == MAX_CONSTRAINTS) - _fd_fatal("too many constraints, increase MAX_CONSTRAINTS"); + fd__fatal("too many constraints, increase MAX_CONSTRAINTS"); if (c = malloc(sizeof(struct fd_constraint))) { -#ifdef CONSTRAINT_TEMPS +#if defined(CONSTRAINT_TEMPS) || !defined(DISABLE_ENTAILED) c->index = _fd_constraint_count; #endif c->variables = calloc(nvariables, sizeof(C_VAR_T)); // XXX: check for NULL @@ -41,12 +56,7 @@ fd_constraint _fd_constraint_new(int nvariables, int nconstants) else c->constants = 0; c->nconstants = nconstants; -#ifdef CONSTRAINT_CLASS c->kind = -1; // XXX -#else /* CONSTRAINT_CLASS */ - c->propagator2 = _fd_undefined; - c->propagator = 0; -#endif /* CONSTRAINT_CLASS */ _fd_constraints[_fd_constraint_count++] = c; } @@ -56,7 +66,7 @@ fd_constraint _fd_constraint_new(int nvariables, int nconstants) int _fd_undefined() { - _fd_fatal("called an undefined function"); + fd__fatal("called an undefined function"); } #ifdef DISTRIBUTED_SOLVER @@ -77,9 +87,17 @@ void _fd_import_constraints(fd_int variables[]) #endif /* DISTRIBUTED_SOLVER */ -#ifdef CONSTRAINT_TEMPS +#ifdef CONSTRAINTS_HAVE_STATE #include <string.h> +void fd__constraint_data_reset(void) +{ + memset(constraint_state_info, 0, + _fd_constraint_count * sizeof(*constraint_state_info)); +} +#endif /* CONSTRAINTS_HAVE_STATE */ + +#ifdef CONSTRAINT_TEMPS int fd__constraint_data_valid(fd_constraint constraint) { return constraint_state_info[constraint->index] & CSTR_DATA_VALID; @@ -90,6 +108,16 @@ void fd__constraint_remember(fd_constraint constraint) constraint_state_info[constraint->index] |= CSTR_DATA_VALID; } +void fd__constraint_free_memory(void) +{ + int i; + + for (i = 0; i < _fd_constraint_count; ++i) + if (constraint_memory[i]) + free(constraint_memory[i]); +} +#endif /* CONSTRAINT_TEMPS */ + #ifndef DISABLE_ENTAILED void fd__constraint_set_entailed(fd_constraint constraint) { @@ -100,27 +128,12 @@ int fd__constraint_entailed(fd_constraint constraint) { return constraint_state_info[constraint->index] & CSTR_ENTAILED; } -#else +#else /* DISABLE_ENTAILED */ #define fd__constraint_set_entailed(_) ((void) 0) -#endif - -void fd__constraint_data_reset() -{ - memset(constraint_state_info, 0, - _fd_constraint_count * sizeof(*constraint_state_info)); -} +#endif /* DISABLE_ENTAILED */ -void fd__constraint_free_memory() -{ - int i; - for (i = 0; i < _fd_constraint_count; ++i) - if (constraint_memory[i]) - free(constraint_memory[i]); -} -#else /* CONSTRAINT_TEMPS */ -#define fd__constraint_set_entailed(_) ((void) 0) -#endif /* CONSTRAINT_TEMPS */ +/* Import the constraints' code. */ #include <constraints/lt.c> #include <constraints/le.c> @@ -152,40 +165,45 @@ void fd__constraint_free_memory() #include <constraints/poly-eq-k.c> #include <constraints/poly-ne.c> #include <constraints/poly-ne-k.c> +#include <constraints/poly-le-k.c> -#ifdef CONSTRAINT_CLASS _fd_constraint_class _fd_constraint_data[FD_CONSTR_KINDS]; -_FD_CONSTRAINT_INITIALISATION(ne, FD_CONSTR_NE) -_FD_CONSTRAINT_INITIALISATION(eq, FD_CONSTR_EQ) -_FD_CONSTRAINT_INITIALISATION(lt, FD_CONSTR_LT) -_FD_CONSTRAINT_INITIALISATION(le, FD_CONSTR_LE) -_FD_CONSTRAINT_INITIALISATION(minus_ne, FD_CONSTR_MINUS_NE) -_FD_CONSTRAINT_INITIALISATION(minus_eq, FD_CONSTR_MINUS_EQ) -// _FD_CONSTRAINT_INITIALISATION(plus_gt, FD_CONSTR_PLUS_GT) -_FD_CONSTRAINT_INITIALISATION(var_eq_minus, FD_CONSTR_VAR_EQ_MINUS) -_FD_CONSTRAINT_INITIALISATION(all_different, FD_CONSTR_ALL_DIFFERENT) -// _FD_CONSTRAINT_INITIALISATION(exactly_one, FD_CONSTR_EXACTLY_ONE) -// _FD_CONSTRAINT_INITIALISATION(nogoods, FD_CONSTR_NOGOODS) -_FD_CONSTRAINT_INITIALISATION(exactly, FD_CONSTR_EXACTLY) -_FD_CONSTRAINT_INITIALISATION(exactly_var, FD_CONSTR_EXACTLY_VAR) -_FD_CONSTRAINT_INITIALISATION(sum, FD_CONSTR_SUM) -_FD_CONSTRAINT_INITIALISATION(var_eq_times, FD_CONSTR_VAR_EQ_TIMES) -_FD_CONSTRAINT_INITIALISATION(sum_prod, FD_CONSTR_SUM_PROD) -_FD_CONSTRAINT_INITIALISATION(element, FD_CONSTR_ELEMENT) -_FD_CONSTRAINT_INITIALISATION(knapsack2, FD_CONSTR_KNAPSACK2) -_FD_CONSTRAINT_INITIALISATION(sum2, FD_CONSTR_SUM2) -_FD_CONSTRAINT_INITIALISATION(min, FD_CONSTR_MIN) -_FD_CONSTRAINT_INITIALISATION(max, FD_CONSTR_MAX) -_FD_CONSTRAINT_INITIALISATION(poly_eq, FD_CONSTR_POLY_EQ) -_FD_CONSTRAINT_INITIALISATION(element_var, FD_CONSTR_ELEMENT_VAR) -_FD_CONSTRAINT_INITIALISATION(exactly_vars, FD_CONSTR_EXACTLY_VARS) -_FD_CONSTRAINT_INITIALISATION(poly_eq_k, FD_CONSTR_POLY_EQ_K) -_FD_CONSTRAINT_INITIALISATION(poly_ne, FD_CONSTR_POLY_NE) -_FD_CONSTRAINT_INITIALISATION(poly_ne_k, FD_CONSTR_POLY_NE_K) - -void _fd_init_constraints() + +/* Define the constraints' initialisation functions. */ + +CONSTRAINT_INITIALISATION(ne, FD_CONSTR_NE) +CONSTRAINT_INITIALISATION(eq, FD_CONSTR_EQ) +CONSTRAINT_INITIALISATION(lt, FD_CONSTR_LT) +CONSTRAINT_INITIALISATION(le, FD_CONSTR_LE) +CONSTRAINT_INITIALISATION(minus_ne, FD_CONSTR_MINUS_NE) +CONSTRAINT_INITIALISATION(minus_eq, FD_CONSTR_MINUS_EQ) +// CONSTRAINT_INITIALISATION(plus_gt, FD_CONSTR_PLUS_GT) +CONSTRAINT_INITIALISATION(var_eq_minus, FD_CONSTR_VAR_EQ_MINUS) +CONSTRAINT_INITIALISATION(all_different, FD_CONSTR_ALL_DIFFERENT) +// CONSTRAINT_INITIALISATION(exactly_one, FD_CONSTR_EXACTLY_ONE) +// CONSTRAINT_INITIALISATION(nogoods, FD_CONSTR_NOGOODS) +CONSTRAINT_INITIALISATION(exactly, FD_CONSTR_EXACTLY) +CONSTRAINT_INITIALISATION(exactly_var, FD_CONSTR_EXACTLY_VAR) +CONSTRAINT_INITIALISATION(sum, FD_CONSTR_SUM) +CONSTRAINT_INITIALISATION(var_eq_times, FD_CONSTR_VAR_EQ_TIMES) +CONSTRAINT_INITIALISATION(sum_prod, FD_CONSTR_SUM_PROD) +CONSTRAINT_INITIALISATION(element, FD_CONSTR_ELEMENT) +CONSTRAINT_INITIALISATION(knapsack2, FD_CONSTR_KNAPSACK2) +CONSTRAINT_INITIALISATION(sum2, FD_CONSTR_SUM2) +CONSTRAINT_INITIALISATION(min, FD_CONSTR_MIN) +CONSTRAINT_INITIALISATION(max, FD_CONSTR_MAX) +CONSTRAINT_INITIALISATION(poly_eq, FD_CONSTR_POLY_EQ) +CONSTRAINT_INITIALISATION(element_var, FD_CONSTR_ELEMENT_VAR) +CONSTRAINT_INITIALISATION(exactly_vars, FD_CONSTR_EXACTLY_VARS) +CONSTRAINT_INITIALISATION(poly_eq_k, FD_CONSTR_POLY_EQ_K) +CONSTRAINT_INITIALISATION(poly_ne, FD_CONSTR_POLY_NE) +CONSTRAINT_INITIALISATION(poly_ne_k, FD_CONSTR_POLY_NE_K) +CONSTRAINT_INITIALISATION(poly_le_k, FD_CONSTR_POLY_LE_K) + +/* Initialises the constraints. */ +void fd__init_constraints() { static int done = 0; @@ -194,35 +212,34 @@ void _fd_init_constraints() memset(_fd_constraint_data, 0, sizeof(_fd_constraint_data)); // XXX? - _fd_init_constraint(ne); - _fd_init_constraint(eq); - _fd_init_constraint(lt); - _fd_init_constraint(le); - _fd_init_constraint(minus_ne); - _fd_init_constraint(minus_eq); -// _fd_init_constraint(plus_gt); - _fd_init_constraint(var_eq_minus); - _fd_init_constraint(all_different); -// _fd_init_constraint(exactly_one); -// _fd_init_constraint(nogoods); - _fd_init_constraint(exactly); - _fd_init_constraint(exactly_var); - _fd_init_constraint(sum); - _fd_init_constraint(var_eq_times); - _fd_init_constraint(sum_prod); - _fd_init_constraint(element); - _fd_init_constraint(knapsack2); - _fd_init_constraint(sum2); - _fd_init_constraint(min); - _fd_init_constraint(max); - _fd_init_constraint(poly_eq); - _fd_init_constraint(element_var); - _fd_init_constraint(exactly_vars); - _fd_init_constraint(poly_eq_k); - _fd_init_constraint(poly_ne); - _fd_init_constraint(poly_ne_k); + initialise_constraint(ne); + initialise_constraint(eq); + initialise_constraint(lt); + initialise_constraint(le); + initialise_constraint(minus_ne); + initialise_constraint(minus_eq); +// initialise_constraint(plus_gt); + initialise_constraint(var_eq_minus); + initialise_constraint(all_different); +// initialise_constraint(exactly_one); +// initialise_constraint(nogoods); + initialise_constraint(exactly); + initialise_constraint(exactly_var); + initialise_constraint(sum); + initialise_constraint(var_eq_times); + initialise_constraint(sum_prod); + initialise_constraint(element); + initialise_constraint(knapsack2); + initialise_constraint(sum2); + initialise_constraint(min); + initialise_constraint(max); + initialise_constraint(poly_eq); + initialise_constraint(element_var); + initialise_constraint(exactly_vars); + initialise_constraint(poly_eq_k); + initialise_constraint(poly_ne); + initialise_constraint(poly_ne_k); + initialise_constraint(poly_le_k); done = 1; } - -#endif /* CONSTRAINT_CLASS */ diff --git a/src/constraints.h b/src/constraints.h index 0061390..5ba059f 100644 --- a/src/constraints.h +++ b/src/constraints.h @@ -4,8 +4,6 @@ extern fd_constraint _fd_constraints[]; #define CONSTRAINT(v,c) _fd_constraints[(v)->constraints[c]] -#ifdef CONSTRAINT_CLASS - typedef enum { FD_CONSTR_NE = 0, FD_CONSTR_EQ, @@ -36,37 +34,42 @@ typedef enum { FD_CONSTR_POLY_EQ_K, FD_CONSTR_POLY_NE, FD_CONSTR_POLY_NE_K, + FD_CONSTR_POLY_LE_K, FD_CONSTR_KINDS // number of kinds of constraints } _fd_constraint_kind; typedef struct _fd_constraint_class { int (*propagator2)(fd_constraint, fd_int); + // propagates changes in a variable's + // domain; 2nd argument is the variable + // against which to revise the domains of + // the other variables in the constraint; + // returns FD_NOSOLUTION if some domain + // becomes empty, and FD_OK otherwise int (*filter)(fd_constraint); + // performs an initial filtering of the + // domains of the constraint variables } _fd_constraint_class; -extern _fd_constraint_class _fd_constraint_data[FD_CONSTR_KINDS]; - - -#define _FD_CONSTRAINT_INITIALISATION(name, code) \ - static void _fd_ ## name ## _init(_fd_constraint_class data[]) \ - { \ - data[code].propagator2 = fd_ ## name ## _propagate2; \ - data[code].filter = fd_ ## name ## _filter; \ - } - -#define _fd_init_constraint(name) _fd_ ## name ## _init(_fd_constraint_data) +extern _fd_constraint_class _fd_constraint_data[]; #define _fd_propagate(c,v) (_fd_constraint_data[(c)->kind].propagator2(c, v)) #define _fd_filter(c) (_fd_constraint_data[(c)->kind].filter(c)) -#else /* CONSTRAINT_CLASS */ +void fd__init_constraints(); -#define _fd_propagate(c,v) ((c)->propagator2(c, v)) -#define _fd_filter(c) ((c)->filter(c)) -#endif /* CONSTRAINT_CLASS */ +#if defined(CONSTRAINT_TEMPS) || !defined(DISABLE_ENTAILED) +#define CONSTRAINTS_HAVE_STATE 1 +#endif + +#ifdef CONSTRAINTS_HAVE_STATE +void fd__constraint_data_reset(void); +#else +#define fd__constraint_data_reset() ((void) 0) +#endif -#if defined(CONSTRAINT_TEMPS) && !defined(DISABLE_ENTAILED) +#ifndef DISABLE_ENTAILED int fd__constraint_entailed(fd_constraint); #else #define fd__constraint_entailed(_) 0 diff --git a/src/constraints/all-different.c b/src/constraints/all-different.c index b2ad0a5..4e95ca9 100644 --- a/src/constraints/all-different.c +++ b/src/constraints/all-different.c @@ -128,7 +128,7 @@ static int fd_all_different_propagate(fd_constraint this, fd_int revise) #if defined(USE_ENTAILED) && 0 // XXX: hampers performance when not optimised if (set == this->nvariables - 1) - _fd_constraint_set_entailed(this); + fd__constraint_set_entailed(this); #endif if (changed) @@ -148,18 +148,14 @@ fd_constraint fd_all_different(fd_int *variables, int nvariables) if (nvariables == 2) return fd_ne(variables[0], variables[1]); - c = _fd_constraint_new(nvariables, 0); + c = fd__constraint_new(nvariables, 0); if (c) { for (i = 0; i < nvariables; ++i) c->variables[i] = FD_INT2C_VAR(variables[i]); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_ALL_DIFFERENT; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_all_different_propagate2; - c->propagator = fd_all_different_propagate; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/element-var.c b/src/constraints/element-var.c index 3f73946..448f3c6 100644 --- a/src/constraints/element-var.c +++ b/src/constraints/element-var.c @@ -143,7 +143,7 @@ static int fd_element_var_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_element_var(fd_int *variables, int nvariables, fd_int index, fd_int value) { - fd_constraint c = _fd_constraint_new(nvariables + 2, 0); + fd_constraint c = fd__constraint_new(nvariables + 2, 0); int i; // XXX: add a constraint 0 <= INDEX < nvariables @@ -154,11 +154,8 @@ fd_constraint fd_element_var(fd_int *variables, int nvariables, fd_int index, c->variables[i] = FD_INT2C_VAR(variables[i]); c->variables[nvariables] = FD_INT2C_VAR(index); c->variables[nvariables + 1] = FD_INT2C_VAR(value); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_ELEMENT_VAR; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_element_var_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/element.c b/src/constraints/element.c index 1318a2f..dff7929 100644 --- a/src/constraints/element.c +++ b/src/constraints/element.c @@ -102,7 +102,7 @@ static int fd_element_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_element(fd_int *variables, int nvariables, fd_int index, int k) { - fd_constraint c = _fd_constraint_new(nvariables + 1, 1); + fd_constraint c = fd__constraint_new(nvariables + 1, 1); int i; // XXX: add a constraint 0 <= INDEX < nvariables @@ -113,11 +113,8 @@ fd_constraint fd_element(fd_int *variables, int nvariables, fd_int index, int k) c->variables[i] = FD_INT2C_VAR(variables[i]); c->variables[nvariables] = FD_INT2C_VAR(index); c->constants[0] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_ELEMENT; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_element_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/eq.c b/src/constraints/eq.c index 300092b..ce01d27 100644 --- a/src/constraints/eq.c +++ b/src/constraints/eq.c @@ -62,17 +62,13 @@ int fd_eq_propagate(fd_constraint this, fd_int revise) fd_constraint fd_eq(fd_int x, fd_int y) { - fd_constraint c = _fd_constraint_new(2, 0); + fd_constraint c = fd__constraint_new(2, 0); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_EQ; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_eq_propagate2; - c->propagator = fd_eq_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/exactly-one.c b/src/constraints/exactly-one.c index 99642e4..e15dbd2 100644 --- a/src/constraints/exactly-one.c +++ b/src/constraints/exactly-one.c @@ -72,7 +72,7 @@ static int fd_exactly_one_propagate(fd_constraint this, fd_int revise) fd_constraint fd_exactly_one(fd_int *variables, int nvariables, int value) { - fd_constraint c = _fd_constraint_new(nvariables, 1); + fd_constraint c = fd__constraint_new(nvariables, 1); int i; if (c) @@ -80,11 +80,8 @@ fd_constraint fd_exactly_one(fd_int *variables, int nvariables, int value) for (i = 0; i < nvariables; ++i) c->variables[i] = FD_INT2C_VAR(variables[i]); c->constants[0] = value; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_EXACTLY_ONE; -#else /* CONSTRAINT_CLASS */ - c->propagator = fd_exactly_one_propagate; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/exactly-var.c b/src/constraints/exactly-var.c index 11e764d..82df8bf 100644 --- a/src/constraints/exactly-var.c +++ b/src/constraints/exactly-var.c @@ -159,7 +159,7 @@ static int fd_exactly_var_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_exactly_var(fd_int *variables, int nvariables, fd_int card, int k) { - fd_constraint c = _fd_constraint_new(nvariables + 1, 1); + fd_constraint c = fd__constraint_new(nvariables + 1, 1); int i; if (c) @@ -168,11 +168,8 @@ fd_constraint fd_exactly_var(fd_int *variables, int nvariables, fd_int card, int c->variables[i] = FD_INT2C_VAR(variables[i]); c->variables[nvariables] = FD_INT2C_VAR(card); c->constants[0] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_EXACTLY_VAR; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_exactly_var_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i <= nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/exactly-vars.c b/src/constraints/exactly-vars.c index 0ba45d1..8f5ee1f 100644 --- a/src/constraints/exactly-vars.c +++ b/src/constraints/exactly-vars.c @@ -166,7 +166,7 @@ static int fd_exactly_vars_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_exactly_vars(fd_int *variables, int nvariables, fd_int card, fd_int k) { - fd_constraint c = _fd_constraint_new(nvariables + 2, 0); + fd_constraint c = fd__constraint_new(nvariables + 2, 0); int i; if (c) @@ -175,11 +175,8 @@ fd_constraint fd_exactly_vars(fd_int *variables, int nvariables, fd_int card, fd c->variables[i] = FD_INT2C_VAR(variables[i]); c->variables[nvariables] = FD_INT2C_VAR(card); c->variables[nvariables + 1] = FD_INT2C_VAR(k); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_EXACTLY_VARS; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_exactly_vars_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < nvariables + 2; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/exactly.c b/src/constraints/exactly.c index eed6304..6e84d17 100644 --- a/src/constraints/exactly.c +++ b/src/constraints/exactly.c @@ -74,7 +74,7 @@ static int fd_exactly_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_exactly(fd_int *variables, int nvariables, int cardinal, int k) { - fd_constraint c = _fd_constraint_new(nvariables, 2); + fd_constraint c = fd__constraint_new(nvariables, 2); int i; if (c) @@ -83,11 +83,8 @@ fd_constraint fd_exactly(fd_int *variables, int nvariables, int cardinal, int k) c->variables[i] = FD_INT2C_VAR(variables[i]); c->constants[0] = k; c->constants[1] = cardinal; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_EXACTLY; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_exactly_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/knapsack.c b/src/constraints/knapsack.c index 07c9edf..217ba43 100644 --- a/src/constraints/knapsack.c +++ b/src/constraints/knapsack.c @@ -105,7 +105,7 @@ static int fd_knapsack_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_knapsack(fd_int variables[], int nvariables, fd_int limits) { - fd_constraint c = _fd_constraint_new(nvariables + 1, 0); + fd_constraint c = fd__constraint_new(nvariables + 1, 0); int i; if (c) @@ -113,11 +113,8 @@ fd_constraint fd_knapsack(fd_int variables[], int nvariables, fd_int limits) for (i = 0; i < nvariables; ++i) c->variables[i] = FD_INT2C_VAR(variables[i]); c->variables[nvariables] = FD_INT2C_VAR(limits); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_KNAPSACK; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_knapsack_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/knapsack2.c b/src/constraints/knapsack2.c index 175eafc..24c8440 100644 --- a/src/constraints/knapsack2.c +++ b/src/constraints/knapsack2.c @@ -4,12 +4,12 @@ static int fd_knapsack2_filter(fd_constraint this) { -#ifdef CONSTRAINT_TEMPS int ub, lb; int min, max; int terms = (this->nvariables - 1) / 2; int *mins, *maxs; // XXX: trouble possible if a variable appears repeated int i; +#ifdef CONSTRAINT_TEMPS int *base; assert(!fd__constraint_data_valid(this)); @@ -21,6 +21,10 @@ static int fd_knapsack2_filter(fd_constraint this) mins = base + 4; maxs = mins + 2 * terms; +#else + mins = alloca(2 * terms * sizeof(*mins)); + maxs = alloca(2 * terms * sizeof(*maxs)); +#endif lb = _fd_var_min(VAR(this, this->nvariables - 1)); // lower bound ub = _fd_var_max(VAR(this, this->nvariables - 1)); // upper bound @@ -115,6 +119,7 @@ static int fd_knapsack2_filter(fd_constraint this) (max < ub && _fd_var_del_gt(max, VAR(this, this->nvariables - 1)))) _fd_revise_connected(this, VAR(this, this->nvariables - 1)); +#ifdef CONSTRAINT_TEMPS // save values *base = lb; *(base + 1) = ub; @@ -122,120 +127,16 @@ static int fd_knapsack2_filter(fd_constraint this) *(base + 3) = max; fd__constraint_remember(this); +#endif return FD_OK; -#else /* CONSTRAINT_TEMPS */ - int ub, lb; - int min, max; - int terms = (this->nvariables - 1) / 2; - int *mins, *maxs; // XXX: trouble possible if a variable appears repeated - int i; - - mins = alloca(2 * terms * sizeof(*mins)); - maxs = alloca(2 * terms * sizeof(*maxs)); - - lb = _fd_var_min(VAR(this, this->nvariables - 1)); // lower bound - ub = _fd_var_max(VAR(this, this->nvariables - 1)); // upper bound - - // sum the minima of the terms - min = 0; - - for (i = 0; i < terms; ++i) - { - mins[i] = _fd_var_min(VAR(this, i)); - mins[terms + i] = _fd_var_min(VAR(this, terms + i)); - - min += mins[i] * mins[terms + i]; - - if (min > ub) - return FD_NOSOLUTION; - } - - // sum the maxima of the terms - max = 0; - - for (i = 0; i < terms; ++i) - { - maxs[i] = _fd_var_max(VAR(this, i)); - maxs[terms + i] = _fd_var_max(VAR(this, terms + i)); - - max += maxs[i] * maxs[terms + i]; - } - - if (max < lb) - return FD_NOSOLUTION; - - // XXX: poor man's propagation - if (min == ub) - for (i = 0; i < terms; ++i) - { - int min_x = mins[i]; - int min_y = mins[terms + i]; - - if (min_x != 0 || min_y != 0) - { - if (min_y != 0 && _fd_var_del_gt(min_x, VAR(this, i))) - _fd_revise_connected(this, VAR(this, i)); - - if (min_x != 0 && _fd_var_del_gt(min_y, VAR(this, terms + i))) - _fd_revise_connected(this, VAR(this, terms + i)); - } - } - else if (max == lb) - for (i = 0; i < terms; ++i) - { - int max_x = maxs[i]; - int max_y = maxs[terms + i]; - - if (max_x != 0 && max_y != 0) - { - if (_fd_var_del_lt(max_x, VAR(this, i))) - _fd_revise_connected(this, VAR(this, i)); - - if (_fd_var_del_lt(max_y, VAR(this, terms + i))) - _fd_revise_connected(this, VAR(this, terms + i)); - } - } - else if (max > ub) - for (i = 0; i < terms; ++i) - { - int min_x = mins[i]; - int max_x = maxs[i]; - int min_y = mins[terms + i]; - int max_y = maxs[terms + i]; - - if (min_x * (max_y - min_y) > ub - min) - { - max_y = (ub - min + min_x * min_y) / min_x; - - _fd_var_del_gt(max_y, VAR(this, terms + i)); - - _fd_revise_connected(this, VAR(this, terms + i)); - } - - if ((max_x - min_x) * min_y > ub - min) - { - max_x = (ub - min + min_x * min_y) / min_y; - - _fd_var_del_gt(max_x, VAR(this, i)); - - _fd_revise_connected(this, VAR(this, i)); - } - } - - if ((min > lb && _fd_var_del_lt(min, VAR(this, this->nvariables - 1))) | - (max < ub && _fd_var_del_gt(max, VAR(this, this->nvariables - 1)))) - _fd_revise_connected(this, VAR(this, this->nvariables - 1)); - - return FD_OK; -#endif /* CONSTRAINT_TEMPS */ } static int fd_knapsack2_propagate2(fd_constraint this, fd_int culprit) { #ifdef CONSTRAINT_TEMPS int ub, lb; - unsigned int min, max; + int min, max; int terms = (this->nvariables - 1) / 2; int *mins, *maxs; // XXX: trouble possible if a variable appears repeated int i; @@ -379,7 +280,7 @@ static int fd_knapsack2_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_knapsack2(fd_int xs[], fd_int ys[], int nvariables, fd_int limits) { - fd_constraint c = _fd_constraint_new(2 * nvariables + 1, 0); + fd_constraint c = fd__constraint_new(2 * nvariables + 1, 0); int i; if (c) @@ -389,11 +290,8 @@ fd_constraint fd_knapsack2(fd_int xs[], fd_int ys[], int nvariables, fd_int limi for (; i < 2 * nvariables; ++i) c->variables[i] = FD_INT2C_VAR(ys[i - nvariables]); c->variables[2 * nvariables] = FD_INT2C_VAR(limits); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_KNAPSACK2; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_knapsack2_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/le.c b/src/constraints/le.c index 91778f1..65edf2b 100644 --- a/src/constraints/le.c +++ b/src/constraints/le.c @@ -1,4 +1,4 @@ -/* X le Y */ +/* x <= y */ static int fd_le_filter(fd_constraint this) { @@ -7,12 +7,21 @@ static int fd_le_filter(fd_constraint this) x = VAR(this, 0); y = VAR(this, 1); +#ifndef DISABLE_ENTAILED + if (_fd_var_max(x) <= _fd_var_min(y)) + { + fd__constraint_set_entailed(this); + + return FD_OK; + } +#endif + if (_fd_var_del_lt(_fd_var_min(x), y)) { if (fd_domain_empty(y)) return FD_NOSOLUTION; - _fd_revise_connected(NULL, y); + _fd_revise_connected(this, y); } if (_fd_var_del_gt(_fd_var_max(y), x)) @@ -20,10 +29,10 @@ static int fd_le_filter(fd_constraint this) if (fd_domain_empty(x)) return FD_NOSOLUTION; - _fd_revise_connected(NULL, x); + _fd_revise_connected(this, x); } -#if CONSTRAINT_TEMPS > 3 +#ifndef DISABLE_ENTAILED if (_fd_var_max(x) <= _fd_var_min(y)) fd__constraint_set_entailed(this); #endif @@ -31,39 +40,63 @@ static int fd_le_filter(fd_constraint this) return FD_OK; } -int fd_le_propagate2(fd_constraint this, fd_int culprit) +static int fd_le_propagate2(fd_constraint this, fd_int culprit) { + fd_int x, y; + int vmax, vmin; fd_int revise; int changed = 0; - if (culprit == VAR(this, 0)) + x = VAR(this, 0); + y = VAR(this, 1); + +#ifndef DISABLE_ENTAILED + vmax = _fd_var_max(x); + vmin = _fd_var_min(y); + + if (vmax <= vmin) { - revise = VAR(this, 1); + fd__constraint_set_entailed(this); - changed = _fd_var_del_lt(_fd_var_min(culprit), revise); + return FD_OK; } - else +#endif + + if (culprit == x) { - revise = VAR(this, 0); + revise = y; - changed = _fd_var_del_gt(_fd_var_max(culprit), revise); + vmin = _fd_var_min(x); + + changed = _fd_var_del_lt(vmin, y); } + else + { + revise = x; - if (changed && fd_domain_empty(revise)) - return FD_NOSOLUTION; + vmax = _fd_var_max(y); -#if CONSTRAINT_TEMPS > 3 - if (_fd_var_max(VAR(this, 0)) <= _fd_var_min(VAR(this, 1))) - fd__constraint_set_entailed(this); -#endif + changed = _fd_var_del_gt(vmax, x); + } if (changed) - _fd_revise_connected(0, revise); + { + if (fd_domain_empty(revise)) + return FD_NOSOLUTION; + + _fd_revise_connected(this, revise); + +#ifndef DISABLE_ENTAILED + // see if the culprit's domain is a singleton + if (vmin == vmax) + fd__constraint_set_entailed(this); +#endif + } return FD_OK; } -int fd_le_propagate(fd_constraint this, fd_int revise) +static int fd_le_propagate(fd_constraint this, fd_int revise) { int changed = 0; @@ -77,7 +110,7 @@ int fd_le_propagate(fd_constraint this, fd_int revise) #ifdef USE_ENTAILED if (_fd_var_max(VAR(this, 0)) <= _fd_var_min(VAR(this, 1))) - _fd_constraint_set_entailed(this); + fd__constraint_set_entailed(this); #endif // XXX: enqueue further updates here? @@ -89,17 +122,13 @@ int fd_le_propagate(fd_constraint this, fd_int revise) fd_constraint fd_le(fd_int x, fd_int y) { - fd_constraint c = _fd_constraint_new(2, 0); + fd_constraint c = fd__constraint_new(2, 0); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_LE; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_le_propagate2; - c->propagator = fd_le_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/lt.c b/src/constraints/lt.c index 95675bb..7de09fe 100644 --- a/src/constraints/lt.c +++ b/src/constraints/lt.c @@ -1,6 +1,6 @@ -/* X lt Y */ +/* x < y */ -int fd_lt_filter(fd_constraint this) +static int fd_lt_filter(fd_constraint this) { fd_int x, y; @@ -9,7 +9,11 @@ int fd_lt_filter(fd_constraint this) #ifndef DISABLE_ENTAILED if (_fd_var_max(x) < _fd_var_min(y)) - fd__constraint_set_entailed(this); + { + fd__constraint_set_entailed(this); + + return FD_OK; + } #endif if (_fd_var_del_le(_fd_var_min(x), y)) @@ -17,7 +21,7 @@ int fd_lt_filter(fd_constraint this) if (fd_domain_empty(y)) return FD_NOSOLUTION; - _fd_revise_connected(NULL, y); + _fd_revise_connected(this, y); } if (_fd_var_del_ge(_fd_var_max(y), x)) @@ -25,19 +29,32 @@ int fd_lt_filter(fd_constraint this) if (fd_domain_empty(x)) return FD_NOSOLUTION; - _fd_revise_connected(NULL, x); + _fd_revise_connected(this, x); } +#ifndef DISABLE_ENTAILED + if (_fd_var_max(x) < _fd_var_min(y)) + fd__constraint_set_entailed(this); +#endif + return FD_OK; } -int fd_lt_propagate2(fd_constraint this, fd_int culprit) +static int fd_lt_propagate2(fd_constraint this, fd_int culprit) { + fd_int x, y; + int vmax, vmin; fd_int revise; int changed = 0; -#if !defined(DISABLE_ENTAILED) && CONSTRAINT_TEMPS > 2 - if (_fd_var_max(VAR(this, 0)) < _fd_var_min(VAR(this, 1))) + x = VAR(this, 0); + y = VAR(this, 1); + +#ifndef DISABLE_ENTAILED + vmax = _fd_var_max(x); + vmin = _fd_var_min(y); + + if (vmax < vmin) { fd__constraint_set_entailed(this); @@ -45,29 +62,41 @@ int fd_lt_propagate2(fd_constraint this, fd_int culprit) } #endif - if (culprit == VAR(this, 0)) + if (culprit == x) { - revise = VAR(this, 1); + revise = y; - changed = _fd_var_del_le(_fd_var_min(culprit), revise); + vmin = _fd_var_min(x); + + changed = _fd_var_del_le(vmin, y); } else { - revise = VAR(this, 0); + revise = x; - changed = _fd_var_del_ge(_fd_var_max(culprit), revise); - } + vmax = _fd_var_max(y); - if (changed && fd_domain_empty(revise)) - return FD_NOSOLUTION; + changed = _fd_var_del_ge(vmax, x); + } if (changed) - _fd_revise_connected(0, revise); + { + if (fd_domain_empty(revise)) + return FD_NOSOLUTION; + + _fd_revise_connected(this, revise); + +#ifndef DISABLE_ENTAILED + // see if the culprit's domain is a singleton + if (vmin == vmax) + fd__constraint_set_entailed(this); +#endif + } return FD_OK; } -int fd_lt_propagate(fd_constraint this, fd_int revise) +static int fd_lt_propagate(fd_constraint this, fd_int revise) { int changed = 0; @@ -81,7 +110,7 @@ int fd_lt_propagate(fd_constraint this, fd_int revise) #ifdef USE_ENTAILED if (_fd_var_max(VAR(this, 0)) < _fd_var_min(VAR(this, 1))) - _fd_constraint_set_entailed(this); + fd__constraint_set_entailed(this); #endif // XXX: enqueue further updates here? @@ -93,17 +122,13 @@ int fd_lt_propagate(fd_constraint this, fd_int revise) fd_constraint fd_lt(fd_int x, fd_int y) { - fd_constraint c = _fd_constraint_new(2, 0); + fd_constraint c = fd__constraint_new(2, 0); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_LT; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_lt_propagate2; - c->propagator = fd_lt_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/max.c b/src/constraints/max.c index 6878345..31e2d05 100644 --- a/src/constraints/max.c +++ b/src/constraints/max.c @@ -84,16 +84,13 @@ bool fd_max_bound_variable(fd_constraint this, int bound) fd_constraint fd_max(fd_int variable) { - fd_constraint c = _fd_constraint_new(1, 0); + fd_constraint c = fd__constraint_new(1, 0); if (c) { c->variables[0] = FD_INT2C_VAR(variable); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_MAX; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_max_propagate2; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(variable, c); diff --git a/src/constraints/min.c b/src/constraints/min.c index a77f813..72d6fdf 100644 --- a/src/constraints/min.c +++ b/src/constraints/min.c @@ -84,16 +84,13 @@ bool fd_min_bound_variable(fd_constraint this, int bound) fd_constraint fd_min(fd_int variable) { - fd_constraint c = _fd_constraint_new(1, 0); + fd_constraint c = fd__constraint_new(1, 0); if (c) { c->variables[0] = FD_INT2C_VAR(variable); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_MIN; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_min_propagate2; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(variable, c); diff --git a/src/constraints/minus-eq.c b/src/constraints/minus-eq.c index 3ae7ed9..572ad78 100644 --- a/src/constraints/minus-eq.c +++ b/src/constraints/minus-eq.c @@ -105,18 +105,14 @@ int fd_minus_eq_propagate(fd_constraint this, fd_int revise) fd_constraint fd_minus_eq(fd_int x, fd_int y, int k) { - fd_constraint c = _fd_constraint_new(2, 1); + fd_constraint c = fd__constraint_new(2, 1); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); c->constants[0] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_MINUS_EQ; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_minus_eq_propagate2; - c->propagator = fd_minus_eq_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/minus-ne.c b/src/constraints/minus-ne.c index 3164877..8f799e4 100644 --- a/src/constraints/minus-ne.c +++ b/src/constraints/minus-ne.c @@ -99,18 +99,14 @@ int fd_minus_ne_propagate(fd_constraint this, fd_int revise) fd_constraint fd_minus_ne(fd_int x, fd_int y, int k) { - fd_constraint c = _fd_constraint_new(2, 1); + fd_constraint c = fd__constraint_new(2, 1); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); c->constants[0] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_MINUS_NE; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_minus_ne_propagate2; - c->propagator = fd_minus_ne_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/ne.c b/src/constraints/ne.c index ebbc0bd..9cb9406 100644 --- a/src/constraints/ne.c +++ b/src/constraints/ne.c @@ -86,17 +86,13 @@ int fd_ne_propagate(fd_constraint this, fd_int revise) fd_constraint fd_ne(fd_int x, fd_int y) { - fd_constraint c = _fd_constraint_new(2, 0); + fd_constraint c = fd__constraint_new(2, 0); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_NE; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_ne_propagate2; - c->propagator = fd_ne_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/nogoods.c b/src/constraints/nogoods.c index c77929d..503d58d 100644 --- a/src/constraints/nogoods.c +++ b/src/constraints/nogoods.c @@ -35,16 +35,13 @@ int fd_nogoods_propagate(fd_constraint this, fd_int revise) fd_constraint fd_nogoods(fd_int x, fd_int y, int *nogoods, int nnogoods) { - fd_constraint c = _fd_constraint_new(2, 2 * nnogoods); + fd_constraint c = fd__constraint_new(2, 2 * nnogoods); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_NOGOODS; -#else /* CONSTRAINT_CLASS */ - c->propagator = fd_nogoods_propagate; -#endif /* CONSTRAINT_CLASS */ memcpy(c->constants, nogoods, 2 * nnogoods * sizeof(int)); diff --git a/src/constraints/plus-gt.c b/src/constraints/plus-gt.c index 990c1a3..da49e96 100644 --- a/src/constraints/plus-gt.c +++ b/src/constraints/plus-gt.c @@ -23,17 +23,14 @@ int fd_plus_gt_propagate(fd_constraint this, fd_int revise) fd_constraint fd_plus_gt(fd_int x, fd_int y, int k) { - fd_constraint c = _fd_constraint_new(2, 1); + fd_constraint c = fd__constraint_new(2, 1); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); c->constants[0] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_PLUS_GT; -#else /* CONSTRAINT_CLASS */ - c->propagator = fd_plus_gt_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/poly-eq-k.c b/src/constraints/poly-eq-k.c index 81e22af..c140093 100644 --- a/src/constraints/poly-eq-k.c +++ b/src/constraints/poly-eq-k.c @@ -1,5 +1,8 @@ /* poly-eq-k(C, X, k) == sum(C . X) = k */ +// caveat: may not work correctly when there are more than one +// occurrences of some variable + static int fd_poly_eq_k_filter(fd_constraint this) { int k; @@ -52,142 +55,99 @@ static int fd_poly_eq_k_filter(fd_constraint this) return FD_NOSOLUTION; if (min == max) - return FD_OK; - - // XXX: poor man's propagation - if (min == k) { - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - - if (c && mins[i] != maxs[i]) - { - if (c > 0) - _fd_var_del_gt(mins[i], VAR(this, i)); - else - _fd_var_del_lt(maxs[i], VAR(this, i)); - - // check needed for when variables occur more than once - // and with opposite signs - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; - - _fd_revise_connected(this, VAR(this, i)); - } - } - fd__constraint_set_entailed(this); } - else if (max == k) + else { - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; + // bounds domain filtering + // XXX: number of iterations depends on the size of the domains - if (c && mins[i] != maxs[i]) - { - if (c > 0) - _fd_var_del_lt(maxs[i], VAR(this, i)); - else - _fd_var_del_gt(mins[i], VAR(this, i)); + int omin, omax; - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; - - _fd_revise_connected(this, VAR(this, i)); - } - } + do { + omin = min; + omax = max; - fd__constraint_set_entailed(this); - } - else - { - if (max > k) for (i = 0; i < terms; ++i) { int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; + int imin = mins[i]; + int imax = maxs[i]; + + if (c == 0 || imin == imax) continue; if (c > 0) { - // enforce sum{j!=i}(c[j] * min[j]) + c[i] * max[i] <= k + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] >= k - if ((xmax - xmin) * c > k - min) + if (max + (imin - imax) * c < k) { - // xmax = floor((k - min) / c) + xmin - xmax = (k - min) / c + xmin; + // imin = ceil((k - max) / c) + imax + imin = (k - max) / c + imax; - _fd_var_del_gt(xmax, VAR(this, i)); + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); - if (fd_domain_empty(VAR(this, i))) + min += (imin - mins[i]) * c; + + if (min > k) return FD_NOSOLUTION; - _fd_revise_connected(this, VAR(this, i)); + mins[i] = imin; } - } - else if (c < 0) - { - // enforce sum{j!=i}(c[j] * min[j]) + c[i] * min[i] <= k - if ((xmin - xmax) * c > k - min) + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] <= k + + if (min + (imax - imin) * c > k) { - // xmin = ceil((k - min) / c) + xmax - xmin = (k - min) / c + xmax; + // imax = floor((k - min) / c) + imin + imax = (k - min) / c + imin; - _fd_var_del_lt(xmin, VAR(this, i)); + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + max -= (maxs[i] - imax) * c; // max >= k! - _fd_revise_connected(this, VAR(this, i)); + maxs[i] = imax; } } - } - - if (min < k) - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; - - if (c > 0) + else { - // enforce sum{j!=i}(c[j] * max[j]) + c[i] * min[i] >= k + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] >= k - if ((xmax - xmin) * c > max - k) + if (max + (imax - imin) * c < k) { - // xmin = ceil((k - max) / c) + xmax - xmin = (k - max) / c + xmax; + // imax = floor((k - max) / c) + imin + imax = (k - max) / c + imin; + + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); - _fd_var_del_lt(xmin, VAR(this, i)); + min += (imax - maxs[i]) * c; - if (fd_domain_empty(VAR(this, i))) // domains may have holes + if (min > k) return FD_NOSOLUTION; - _fd_revise_connected(this, VAR(this, i)); + maxs[i] = imax; } - } - else if (c < 0) - { - // enforce sum{j!=i}(c[j] * max[j]) + c[i] * max[i] >= k - if ((xmax - xmin) * c < k - max) + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] <= k + + if (min + (imin - imax) * c > k) { - // xmax = floor((k - max) / c) + xmin - xmax = (k - max) / c + xmin; + // imin = ceil((k - min) / c) + imax + imin = (k - min) / c + imax; - _fd_var_del_gt(xmax, VAR(this, i)); + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); - if (fd_domain_empty(VAR(this, i))) // domains may have holes - return FD_NOSOLUTION; + max -= (mins[i] - imin) * c; // max >= k! - _fd_revise_connected(this, VAR(this, i)); + mins[i] = imin; } } } + } while (min != max && (min != omin || max != omax)); + + if (min == max) + fd__constraint_set_entailed(this); } #ifdef CONSTRAINT_TEMPS @@ -267,170 +227,104 @@ static int fd_poly_eq_k_propagate2(fd_constraint this, fd_int culprit) } while (x < terms); - // XXX: poor man's propagation - if (nmin == k) - { - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - - if (c && mins[i] != maxs[i]) - { - if (c > 0) - { - _fd_var_del_gt(mins[i], VAR(this, i)); - - maxs[i] = mins[i]; - } - else - { - _fd_var_del_lt(maxs[i], VAR(this, i)); - - mins[i] = maxs[i]; - } - - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; - - _fd_revise_connected(this, VAR(this, i)); - } - } + if (nmin == min && nmax == max) + return FD_OK; + if (nmin == nmax) + { fd__constraint_set_entailed(this); } - else if (nmax == k) + else { - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - - if (c && mins[i] != maxs[i]) - { - if (c > 0) - { - _fd_var_del_lt(maxs[i], VAR(this, i)); + // bounds domain propagation + // XXX: number of iterations depends on the size of the domains - mins[i] = maxs[i]; - } - else - { - _fd_var_del_gt(mins[i], VAR(this, i)); + int onmin, onmax; - maxs[i] = mins[i]; - } + do { + onmin = nmin; + onmax = nmax; - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; - - _fd_revise_connected(this, VAR(this, i)); - } - } - - fd__constraint_set_entailed(this); - } - -#if 0 // this is too expensive - { - if (nmax < max && nmax > k) for (i = 0; i < terms; ++i) { int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; + int imin = mins[i]; + int imax = maxs[i]; + + if (c == 0 || imin == imax) continue; if (c > 0) { - // enforce sum{j!=i}(c[j] * min[j]) + c[i] * max[i] <= k + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] >= k - if ((xmax - xmin) * c > k - nmin) + if (nmax + (imin - imax) * c < k) { - // xmax = floor((k - nmin) / c) + xmin - xmax = (k - nmin) / c + xmin; + // imin = ceil((k - nmax) / c) + imax + imin = (k - nmax) / c + imax; + + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); - if (_fd_var_del_gt(xmax, VAR(this, i))) - { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + nmin += (imin - mins[i]) * c; - _fd_revise_connected(this, VAR(this, i)); - } + if (nmin > k) + return FD_NOSOLUTION; - maxs[i] = xmax; + mins[i] = imin; } - } - else if (c < 0) - { - // enforce sum{j!=i}(c[j] * min[j]) + c[i] * min[i] <= k - if ((xmin - xmax) * c > k - nmin) + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] <= k + + if (nmin + (imax - imin) * c > k) { - // xmin = ceil((k - nmin) / c) + xmax - xmin = (k - nmin) / c + xmax; + // imax = floor((k - nmin) / c) + imin + imax = (k - nmin) / c + imin; - if (_fd_var_del_lt(xmin, VAR(this, i))) - { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); - _fd_revise_connected(this, VAR(this, i)); - } + nmax -= (maxs[i] - imax) * c; // nmax >= k! - mins[i] = xmin; + maxs[i] = imax; } } - } - - if (nmin > min && nmin < k) - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; - - if (c > 0) + else { - // enforce sum{j!=i}(c[j] * max[j]) + c[i] * min[i] >= k + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] >= k - if ((xmax - xmin) * c > nmax - k) + if (nmax + (imax - imin) * c < k) { - // xmin = ceil((k - nmax) / c) + xmax - xmin = (k - nmax) / c + xmax; + // imax = floor((k - nmax) / c) + imin + imax = (k - nmax) / c + imin; - if (_fd_var_del_lt(xmin, VAR(this, i))) - { + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); - if (fd_domain_empty(VAR(this, i))) // domains may have holes - return FD_NOSOLUTION; + nmin += (imax - maxs[i]) * c; - _fd_revise_connected(this, VAR(this, i)); - } + if (nmin > k) + return FD_NOSOLUTION; - mins[i] = xmin; + maxs[i] = imax; } - } - else if (c < 0) - { - // enforce sum{j!=i}(c[j] * max[j]) + c[i] * max[i] >= k - if ((xmax - xmin) * c < k - nmax) + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] <= k + + if (nmin + (imin - imax) * c > k) { - // xmax = floor((k - nmax) / c) + xmin - xmax = (k - nmax) / c + xmin; + // imin = ceil((k - nmin) / c) + imax + imin = (k - nmin) / c + imax; - if (_fd_var_del_gt(xmax, VAR(this, i))) - { - if (fd_domain_empty(VAR(this, i))) // domains may have holes - return FD_NOSOLUTION; + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); - _fd_revise_connected(this, VAR(this, i)); - } + nmax -= (mins[i] - imin) * c; // nmax >= k! - maxs[i] = xmax; + mins[i] = imin; } } } + } while (nmin != nmax && (nmin != onmin || nmax != onmax)); + + if (nmin == nmax) + fd__constraint_set_entailed(this); } -#endif *base = nmin; *(base + 1) = nmax; @@ -443,7 +337,7 @@ static int fd_poly_eq_k_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_poly_eq_k(int cs[], fd_int xs[], int nterms, int k) { - fd_constraint c = _fd_constraint_new(nterms, nterms + 1); + fd_constraint c = fd__constraint_new(nterms, nterms + 1); int i; if (c) @@ -453,11 +347,8 @@ fd_constraint fd_poly_eq_k(int cs[], fd_int xs[], int nterms, int k) for (i = 0; i < nterms; ++i) c->constants[i] = cs[i]; c->constants[nterms] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_POLY_EQ_K; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_poly_eq_k_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/poly-eq.c b/src/constraints/poly-eq.c index 0bbb135..b9bf60f 100644 --- a/src/constraints/poly-eq.c +++ b/src/constraints/poly-eq.c @@ -1,4 +1,7 @@ -/* poly-eq(C, X, y) == min(y) <= sum(C . X) <= max(y) */ +/* poly-eq(C, X, y) == sum(C . X) = y */ + +// caveat: may not work correctly when there are more than one +// occurrences of some variable static int fd_poly_eq_filter(fd_constraint this) { @@ -52,154 +55,155 @@ static int fd_poly_eq_filter(fd_constraint this) if (min > ub || max < lb) return FD_NOSOLUTION; - if ((min > lb && _fd_var_del_lt(min, VAR(this, this->nvariables - 1))) | - (max < ub && _fd_var_del_gt(max, VAR(this, this->nvariables - 1)))) + if (min > lb) { - if (fd_domain_empty(VAR(this, this->nvariables - 1))) - return FD_NOSOLUTION; + fd_update_domain_and_check(del_lt, min, VAR(this, this->nvariables - 1)); + + lb = min; + } + + if (max < ub) + { + fd_update_domain_and_check(del_gt, max, VAR(this, this->nvariables - 1)); - _fd_revise_connected(this, VAR(this, this->nvariables - 1)); + ub = max; } if (min == max) - return FD_OK; + { + fd__constraint_set_entailed(this); + } + else + { + // bounds domain filtering + // XXX: number of iterations depends on the size of the domains - // XXX: poor man's propagation - if (min == ub) - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; + int omin, omax; - if (c && mins[i] != maxs[i]) + do { + omin = min; + omax = max; + + if (max > ub) { - if (c > 0) + for (i = 0; i < terms; ++i) { - _fd_var_del_gt(mins[i], VAR(this, i)); + int c = this->constants[i]; + int imin = mins[i]; + int imax = maxs[i]; - // check needed for when variables occur twice and - // with opposite signs - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + if (c == 0 || imin == imax) continue; - _fd_revise_connected(this, VAR(this, i)); - } - else - { - _fd_var_del_lt(maxs[i], VAR(this, i)); + if (c > 0) + { + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] <= max[y] - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + if (min + (imax - imin) * c > ub) + { + // imax = floor((ub - min) / c) + imin + imax = (ub - min) / c + imin; - _fd_revise_connected(this, VAR(this, i)); - } - } - } - else if (max == lb) - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); - if (c && mins[i] != maxs[i]) - { - if (c > 0) - { - _fd_var_del_lt(maxs[i], VAR(this, i)); + max -= (maxs[i] - imax) * c; - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + maxs[i] = imax; + } + } + else + { + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] <= max[y] - _fd_revise_connected(this, VAR(this, i)); - } - else - { - _fd_var_del_gt(mins[i], VAR(this, i)); + if (min + (imin - imax) * c > ub) + { + // imin = ceil((ub - min) / c) + imax + imin = (ub - min) / c + imax; + + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + max -= (mins[i] - imin) * c; - _fd_revise_connected(this, VAR(this, i)); + mins[i] = imin; + } + } } + + if (max < lb) + return FD_NOSOLUTION; } - } - else - { - if (max > ub) - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; - if (c > 0) + if (min < lb) + { + for (i = 0; i < terms; ++i) { - if ((xmax - xmin) * c > ub - min) + int c = this->constants[i]; + int imin = mins[i]; + int imax = maxs[i]; + + if (c == 0 || imin == imax) continue; + + if (c > 0) { - // xmax = floor((ub - min) / c) + xmin - xmax = (ub - min) / c + xmin; + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] >= min[y] + + if (max + (imin - imax) * c < lb) + { + // imin = ceil((lb - max) / c) + imax + imin = (lb - max) / c + imax; - _fd_var_del_gt(xmax, VAR(this, i)); + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + min += (imin - mins[i]) * c; - _fd_revise_connected(this, VAR(this, i)); + mins[i] = imin; + } } - } - else if (c < 0) - { - if ((xmin - xmax) * c > ub - min) + else { - // xmin = ceil((ub - min) / c) + xmax - xmin = (ub - min) / c + xmax; + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] >= min[y] + + if (max + (imax - imin) * c < lb) + { + // imax = floor((lb - max) / c) + imin + imax = (lb - max) / c + imin; - _fd_var_del_lt(xmin, VAR(this, i)); + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + min += (imax - maxs[i]) * c; - _fd_revise_connected(this, VAR(this, i)); + maxs[i] = imax; + } } } + + if (min > ub) + return FD_NOSOLUTION; } - if (min < lb) - for (i = 0; i < terms; ++i) + if (min > lb && _fd_var_del_lt(min, VAR(this, this->nvariables - 1))) { - int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; + if (fd_domain_empty(VAR(this, this->nvariables - 1))) + return FD_NOSOLUTION; - if (c > 0) - { - if ((xmax - xmin) * c > max - lb) - { - // xmin = ceil((lb - max) / c) + xmax - xmin = (lb - max) / c + xmax; + _fd_revise_connected(this, VAR(this, this->nvariables - 1)); - _fd_var_del_lt(xmin, VAR(this, i)); + lb = min; + } - if (fd_domain_empty(VAR(this, i))) // domains may have holes - return FD_NOSOLUTION; + if (max < ub && _fd_var_del_gt(max, VAR(this, this->nvariables - 1))) + { + if (fd_domain_empty(VAR(this, this->nvariables - 1))) + return FD_NOSOLUTION; - _fd_revise_connected(this, VAR(this, i)); - } - } - else if (c < 0) - { - if ((xmax - xmin) * c < lb - max) - { - // xmax = floor((lb - max) / c) + xmin - xmax = (lb - max) / c + xmin; + _fd_revise_connected(this, VAR(this, this->nvariables - 1)); - _fd_var_del_gt(xmax, VAR(this, i)); + ub = max; + } - if (fd_domain_empty(VAR(this, i))) // domains may have holes - return FD_NOSOLUTION; + } while (min != max && (min != omin || max != omax)); - _fd_revise_connected(this, VAR(this, i)); - } - } - } + if (min == max) + fd__constraint_set_entailed(this); } #ifdef CONSTRAINT_TEMPS @@ -226,6 +230,7 @@ static int fd_poly_eq_propagate2(fd_constraint this, fd_int culprit) int *base; int x, c; int nmin, nmin_x, nmax, nmax_x; + int nlb, nub; if (!fd__constraint_data_valid(this)) return fd_poly_eq_filter(this); // ignores culprit @@ -237,16 +242,15 @@ static int fd_poly_eq_propagate2(fd_constraint this, fd_int culprit) mins = base + 4; maxs = mins + terms; - lb = *base; - ub = *(base + 1); + nlb = lb = *base; + nub = ub = *(base + 1); - min = *(base + 2); - max = *(base + 3); + nmin = min = *(base + 2); + nmax = max = *(base + 3); if (culprit == VAR(this, this->nvariables - 1)) { // the culprit is the sum variable - int nlb, nub; nlb = _fd_var_min(culprit); nub = _fd_var_max(culprit); @@ -254,203 +258,205 @@ static int fd_poly_eq_propagate2(fd_constraint this, fd_int culprit) if (nlb == lb && nub == ub) return FD_OK; - if (nlb != lb) - { - if (max < nlb) - return FD_NOSOLUTION; + if (min > nub || max < nlb) + return FD_NOSOLUTION; + } + else + { + // the culprit appears in one of the terms, find out which one(s) + for (x = 0; culprit != VAR(this, x); ++x) + ; - if (max == nlb) - for (i = 0; i < terms; ++i) - { - if (this->constants[i] > 0) - { - if (_fd_var_del_lt(maxs[i], VAR(this, i))) - { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + nmin_x = _fd_var_min(VAR(this, x)); + nmax_x = _fd_var_max(VAR(this, x)); - _fd_revise_connected(this, VAR(this, i)); - } - } - else if (this->constants[i] < 0) - { - if (_fd_var_del_gt(mins[i], VAR(this, i))) - { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + if (nmin_x == mins[x] && nmax_x == maxs[x]) + return FD_OK; - _fd_revise_connected(this, VAR(this, i)); - } - } - } + do + { + c = this->constants[x]; + + if (c > 0) + { + nmin = nmin + (nmin_x - mins[x]) * c; + nmax = nmax - (maxs[x] - nmax_x) * c; + } + else if (c < 0) + { + nmin = nmin - (maxs[x] - nmax_x) * c; + nmax = nmax + (nmin_x - mins[x]) * c; + } + + if (nmin > ub || nmax < lb) + return FD_NOSOLUTION; - if (min < nlb) - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; + mins[x] = nmin_x; + maxs[x] = nmax_x; - if (c > 0) - { - if ((xmax - xmin) * c > max - nlb) - { - // xmin = ceil((nlb - max) / c) + xmax - xmin = (nlb - max) / c + xmax; + while (++x < terms && culprit != VAR(this, x)) + ; + } + while (x < terms); - _fd_var_del_lt(xmin, VAR(this, i)); + if (nmin == min && nmax == max) + return FD_OK; - if (fd_domain_empty(VAR(this, i))) // domains may have holes - return FD_NOSOLUTION; + if (nmin > lb) + { + fd_update_domain_and_check(del_lt, nmin, VAR(this, this->nvariables - 1)); - _fd_revise_connected(this, VAR(this, i)); - } - } - else if (c < 0) - { - if ((xmax - xmin) * c < nlb - max) - { - // xmax = floor((nlb - max) / c) + xmin - xmax = (nlb - max) / c + xmin; + nlb = nmin; + } - _fd_var_del_gt(xmax, VAR(this, i)); + if (nmax < ub) + { + fd_update_domain_and_check(del_gt, nmax, VAR(this, this->nvariables - 1)); - if (fd_domain_empty(VAR(this, i))) // domains may have holes - return FD_NOSOLUTION; + nub = nmax; + } + } - _fd_revise_connected(this, VAR(this, i)); - } - } - } + // (nmin, nlb, nub, nmax) != (min, lb, ub, max) - *base = nlb; - } + if (nmin == nmax) + { + fd__constraint_set_entailed(this); + } + else + { + // bounds domain propagation + // XXX: number of iterations depends on the size of the domains - if (nub != ub) - { - if (min > nub) - return FD_NOSOLUTION; + int onmin, onmax; - if (min == nub) + do { + onmin = nmin; + onmax = nmax; + + if (nmin < nlb) + { for (i = 0; i < terms; ++i) { - if (this->constants[i] > 0) + int c = this->constants[i]; + int imin = mins[i]; + int imax = maxs[i]; + + if (c == 0 || imin == imax) continue; + + if (c > 0) { - if (_fd_var_del_gt(mins[i], VAR(this, i))) + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] >= min[y] + + if (nmax + (imin - imax) * c < nlb) { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + // imin = ceil((nlb - nmax) / c) + imax + imin = (nlb - nmax) / c + imax; + + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); + + nmin += (imin - mins[i]) * c; - _fd_revise_connected(this, VAR(this, i)); + mins[i] = imin; } } - else if (this->constants[i] < 0) + else { - if (_fd_var_del_lt(maxs[i], VAR(this, i))) + // enforce max(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] >= min[y] + + if (nmax + (imax - imin) * c < nlb) { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + // imax = floor((nlb - nmax) / c) + imin + imax = (nlb - nmax) / c + imin; + + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); - _fd_revise_connected(this, VAR(this, i)); + nmin += (imax - maxs[i]) * c; + + maxs[i] = imax; } } } - if (max > nub) - for (i = 0; i < terms; ++i) - { - int c = this->constants[i]; - int xmin = mins[i]; - int xmax = maxs[i]; + if (nmin > nub) + return FD_NOSOLUTION; + } - if (c > 0) + if (nmax > nub) + { + for (i = 0; i < terms; ++i) { - if ((xmax - xmin) * c > nub - min) + int c = this->constants[i]; + int imin = mins[i]; + int imax = maxs[i]; + + if (c == 0 || imin == imax) continue; + + if (c > 0) { - // xmax = floor((nub - min) / c) + xmin - xmax = (nub - min) / c + xmin; + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] <= max[y] - if (_fd_var_del_gt(xmax, VAR(this, i))) + if (nmin + (imax - imin) * c > nub) { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + // imax = floor((nub - nmin) / c) + imin + imax = (nub - nmin) / c + imin; - _fd_revise_connected(this, VAR(this, i)); + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); + + nmax -= (maxs[i] - imax) * c; + + maxs[i] = imax; } } - } - else if (c < 0) - { - if ((xmin - xmax) * c > nub - min) + else { - // xmin = ceil((nub - min) / c) + xmax - xmin = (nub - min) / c + xmax; + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] <= max[y] - if (_fd_var_del_lt(xmin, VAR(this, i))) + if (nmin + (imin - imax) * c > nub) { - if (fd_domain_empty(VAR(this, i))) - return FD_NOSOLUTION; + // imin = ceil((nub - nmin) / c) + imax + imin = (nub - nmin) / c + imax; + + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); - _fd_revise_connected(this, VAR(this, i)); + nmax -= (mins[i] - imin) * c; + + mins[i] = imin; } } } - } - - *(base + 1) = nub; - } - - return FD_OK; - } - - // the culprit appears in one of the terms, find out which one(s) - for (x = 0; culprit != VAR(this, x); ++x) - ; - - nmin_x = _fd_var_min(VAR(this, x)); - nmax_x = _fd_var_max(VAR(this, x)); - - if (nmin_x == mins[x] && nmax_x == maxs[x]) - return FD_OK; - nmin = min; - nmax = max; + if (nmax < nlb) + return FD_NOSOLUTION; + } - do - { - c = this->constants[x]; + if (nmin > nlb && _fd_var_del_lt(nmin, VAR(this, this->nvariables - 1))) + { + if (fd_domain_empty(VAR(this, this->nvariables - 1))) + return FD_NOSOLUTION; - if (c > 0) - { - nmin = nmin + (nmin_x - mins[x]) * c; - nmax = nmax - (maxs[x] - nmax_x) * c; - } - else if (c < 0) - { - nmin = nmin - (maxs[x] - nmax_x) * c; - nmax = nmax + (nmin_x - mins[x]) * c; - } + _fd_revise_connected(this, VAR(this, this->nvariables - 1)); - if (nmin > ub || nmax < lb) - return FD_NOSOLUTION; + nlb = nmin; + } - mins[x] = nmin_x; - maxs[x] = nmax_x; + if (nmax < nub && _fd_var_del_gt(nmax, VAR(this, this->nvariables - 1))) + { + if (fd_domain_empty(VAR(this, this->nvariables - 1))) + return FD_NOSOLUTION; - while (++x < terms && culprit != VAR(this, x)) - ; - } - while (x < terms); + _fd_revise_connected(this, VAR(this, this->nvariables - 1)); - if ((nmin > lb && _fd_var_del_lt(nmin, VAR(this, this->nvariables - 1))) | - (nmax < ub && _fd_var_del_gt(nmax, VAR(this, this->nvariables - 1)))) - { - if (fd_domain_empty(VAR(this, this->nvariables - 1))) - return FD_NOSOLUTION; + nub = nmax; + } + } while (nmin != nmax && (nmin != onmin || nmax != onmax)); - _fd_revise_connected(this, VAR(this, this->nvariables - 1)); + if (nmin == nmax) + fd__constraint_set_entailed(this); } + *(base + 0) = nlb; + *(base + 1) = nub; *(base + 2) = nmin; *(base + 3) = nmax; @@ -462,8 +468,15 @@ static int fd_poly_eq_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_poly_eq(int cs[], fd_int xs[], int nterms, fd_int y) { - fd_constraint c = _fd_constraint_new(nterms + 1, nterms); - int i; + fd_constraint fd_poly_eq_k(int[], fd_int[], int, int); + fd_constraint c; + int i, k; + + // specialise when y is a singleton + if (fd_var_single(y, &k)) + return fd_poly_eq_k(cs, xs, nterms, k); + + c = fd__constraint_new(nterms + 1, nterms); if (c) { @@ -472,11 +485,8 @@ fd_constraint fd_poly_eq(int cs[], fd_int xs[], int nterms, fd_int y) c->variables[nterms] = FD_INT2C_VAR(y); for (i = 0; i < nterms; ++i) c->constants[i] = cs[i]; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_POLY_EQ; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_poly_eq_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/poly-le-k.c b/src/constraints/poly-le-k.c new file mode 100644 index 0000000..fb77d39 --- /dev/null +++ b/src/constraints/poly-le-k.c @@ -0,0 +1,346 @@ +/* poly-le-k(C, X, k) == sum(C . X) <= k */ + +static int fd_poly_le_k_filter(fd_constraint this) +{ + int k; + int min, max; + int terms = this->nvariables; + int *mins, *maxs; + int i; +#ifdef CONSTRAINT_TEMPS + int *base; + + assert(!fd__constraint_data_valid(this)); + + if (!constraint_memory[this->index]) + constraint_memory[this->index] = malloc((2 * terms + 2) * sizeof(int)); + + base = constraint_memory[this->index]; + + mins = base + 2; + maxs = mins + terms; +#else + mins = alloca(terms * sizeof(*mins)); + maxs = alloca(terms * sizeof(*maxs)); +#endif + + k = this->constants[terms]; + + // sum the minima and the maxima of the terms + min = max = 0; + + for (i = 0; i < terms; ++i) + { + int vl, vh; + + if (this->constants[i] > 0) + { + vl = mins[i] = _fd_var_min(VAR(this, i)); + vh = maxs[i] = _fd_var_max(VAR(this, i)); + } + else + { + vl = maxs[i] = _fd_var_max(VAR(this, i)); + vh = mins[i] = _fd_var_min(VAR(this, i)); + } + + min += this->constants[i] * vl; + max += this->constants[i] * vh; + } + + if (min > k) + return FD_NOSOLUTION; + + if (max <= k) + { + fd__constraint_set_entailed(this); + } + else if (min == k) + { + for (i = 0; i < terms; ++i) + { + int c = this->constants[i]; + + if (c == 0 || mins[i] == maxs[i]) continue; + + if (c > 0) + { + _fd_var_del_gt(mins[i], VAR(this, i)); + + // check needed for when variables occur more than once + // and with opposite signs + if (fd_domain_empty(VAR(this, i))) + return FD_NOSOLUTION; + + _fd_revise_connected(this, VAR(this, i)); + + maxs[i] = mins[i]; + } + else + { + _fd_var_del_lt(maxs[i], VAR(this, i)); + + // check needed for when variables occur more than once + // and with opposite signs + if (fd_domain_empty(VAR(this, i))) + return FD_NOSOLUTION; + + _fd_revise_connected(this, VAR(this, i)); + + mins[i] = maxs[i]; + } + } + + max = min; + + fd__constraint_set_entailed(this); + } + else // max > k + { + // bounds domain filtering + + for (i = 0; i < terms; ++i) + { + int c = this->constants[i]; + int imin = mins[i]; + int imax = maxs[i]; + + if (c > 0) + { + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] <= k + + if (min + (imax - imin) * c > k) + { + // max[i] = floor((k - min) / c[i]) + min[i] + imax = (k - min) / c + imin; + + _fd_var_del_gt(imax, VAR(this, i)); + + if (fd_domain_empty(VAR(this, i))) + return FD_NOSOLUTION; + + _fd_revise_connected(this, VAR(this, i)); + + max -= (maxs[i] - imax) * c; + + maxs[i] = imax; + } + } + else // c < 0 (does nothing if c is 0) + { + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] <= k + + if (min + (imin - imax) * c > k) + { + // min[i] = ceil((k - min) / c[i]) + max[i] + imin = (k - min) / c + imax; + + _fd_var_del_lt(imin, VAR(this, i)); + + if (fd_domain_empty(VAR(this, i))) + return FD_NOSOLUTION; + + _fd_revise_connected(this, VAR(this, i)); + + max -= (mins[i] - imin) * c; + + mins[i] = imin; + } + } + } + + if (max <= k) + fd__constraint_set_entailed(this); + } + +#ifdef CONSTRAINT_TEMPS + // save values + *base = min; + *(base + 1) = max; + + fd__constraint_remember(this); +#endif + + return FD_OK; +} + +static int fd_poly_le_k_propagate2(fd_constraint this, fd_int culprit) +{ +#ifdef CONSTRAINT_TEMPS + int k; + int min, max; + int terms = this->nvariables; + int *mins, *maxs; + int i; + int *base; + int x, c; + int nmin, nmin_x, nmax, nmax_x; + + if (!fd__constraint_data_valid(this)) + return fd_poly_le_k_filter(this); // ignores culprit + + // bounds filtering + + base = constraint_memory[this->index]; + + mins = base + 2; + maxs = mins + terms; + + min = *base; + max = *(base + 1); + + k = this->constants[terms]; + + // find the (first) term where the culprit appears + for (x = 0; culprit != VAR(this, x); ++x) + ; + + nmin_x = _fd_var_min(VAR(this, x)); + nmax_x = _fd_var_max(VAR(this, x)); + + if (nmin_x == mins[x] && nmax_x == maxs[x]) + return FD_OK; + + nmin = min; + nmax = max; + + do + { + c = this->constants[x]; + + if (c > 0) + { + nmin = nmin + (nmin_x - mins[x]) * c; + nmax = nmax - (maxs[x] - nmax_x) * c; + } + else if (c < 0) + { + nmin = nmin - (maxs[x] - nmax_x) * c; + nmax = nmax + (nmin_x - mins[x]) * c; + } + + if (nmin > k) + return FD_NOSOLUTION; + + mins[x] = nmin_x; + maxs[x] = nmax_x; + + // search for the next term where the culprit appears + while (++x < terms && culprit != VAR(this, x)) + ; + } + while (x < terms); + + if (nmin == min && nmax == max) + return FD_OK; + + if (nmax <= k) + { + fd__constraint_set_entailed(this); + } + else if (nmin == k) + { + for (i = 0; i < terms; ++i) + { + int c = this->constants[i]; + + if (c == 0 || mins[i] == maxs[i]) continue; + + if (c > 0) + { + fd_update_domain_and_check(del_gt, mins[i], VAR(this, i)); + + maxs[i] = mins[i]; + } + else + { + fd_update_domain_and_check(del_lt, maxs[i], VAR(this, i)); + + mins[i] = maxs[i]; + } + } + + nmax = nmin; + + fd__constraint_set_entailed(this); + } + else if (nmin > min) // nmax > k + { + // bounds domain propagation + + for (i = 0; i < terms; ++i) + { + int c = this->constants[i]; + int imin = mins[i]; + int imax = maxs[i]; + + if (c > 0) + { + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * max[i] <= k + + if (nmin + (imax - imin) * c > k) + { + // max[i] = floor((k - nmin) / c[i]) + min[i] + imax = (k - nmin) / c + imin; + + fd_update_domain_and_check(del_gt, imax, VAR(this, i)); + + nmax -= (maxs[i] - imax) * c; + + maxs[i] = imax; + } + } + else // c < 0 (does nothing if c is 0) + { + // enforce min(sum{j!=i}(c[j] * x[j])) + c[i] * min[i] <= k + + if (nmin + (imin - imax) * c > k) + { + // min[i] = ceil((k - nmin) / c[i]) + max[i] + imin = (k - nmin) / c + imax; + + fd_update_domain_and_check(del_lt, imin, VAR(this, i)); + + nmax -= (mins[i] - imin) * c; + + mins[i] = imin; + } + } + } + + if (nmax <= k) + fd__constraint_set_entailed(this); + } + + *base = nmin; + *(base + 1) = nmax; + + return FD_OK; +#else /* CONSTRAINT_TEMPS */ + return fd_poly_le_k_filter(this); // ignores culprit +#endif /* CONSTRAINT_TEMPS */ +} + +fd_constraint fd_poly_le_k(int cs[], fd_int xs[], int nterms, int k) +{ + fd_constraint c = fd__constraint_new(nterms, nterms + 1); + int i; + + if (c) + { + for (i = 0; i < nterms; ++i) + c->variables[i] = FD_INT2C_VAR(xs[i]); + for (i = 0; i < nterms; ++i) + c->constants[i] = cs[i]; + c->constants[nterms] = k; + + c->kind = FD_CONSTR_POLY_LE_K; + + for (i = 0; i < c->nvariables; ++i) + _fd_var_add_constraint(VAR(c, i), c); + + _fd_add_constraint(c); + } + + return c; +} diff --git a/src/constraints/poly-ne-k.c b/src/constraints/poly-ne-k.c index 6fefc55..5b7eebd 100644 --- a/src/constraints/poly-ne-k.c +++ b/src/constraints/poly-ne-k.c @@ -199,11 +199,13 @@ static int fd_poly_ne_k_propagate2(fd_constraint this, fd_int culprit) if (this->constants[i] && mins[i] != maxs[i]) break; + // m = sum{j != i} c[j] * x[j] if (this->constants[i] > 0) - m = min - this->constants[i] * mins[i]; + m = nmin - this->constants[i] * mins[i]; else - m = min - this->constants[i] * maxs[i]; + m = nmin - this->constants[i] * maxs[i]; + // v * c[i] + m = k (if v were a real value) v = (k - m) / this->constants[i]; if (v * this->constants[i] + m == k) @@ -224,7 +226,7 @@ static int fd_poly_ne_k_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_poly_ne_k(int cs[], fd_int xs[], int nterms, int k) { - fd_constraint c = _fd_constraint_new(nterms, nterms + 1); + fd_constraint c = fd__constraint_new(nterms, nterms + 1); int i; if (c) @@ -234,11 +236,8 @@ fd_constraint fd_poly_ne_k(int cs[], fd_int xs[], int nterms, int k) for (i = 0; i < nterms; ++i) c->constants[i] = cs[i]; c->constants[nterms] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_POLY_NE_K; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_poly_ne_k_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/poly-ne.c b/src/constraints/poly-ne.c index 70b3a39..eb2ad18 100644 --- a/src/constraints/poly-ne.c +++ b/src/constraints/poly-ne.c @@ -237,11 +237,13 @@ static int fd_poly_ne_propagate2(fd_constraint this, fd_int culprit) if (this->constants[i] && mins[i] != maxs[i]) break; + // m = sum{j != i} c[j] * x[j] if (this->constants[i] > 0) - m = min - this->constants[i] * mins[i]; + m = nmin - this->constants[i] * mins[i]; else - m = min - this->constants[i] * maxs[i]; + m = nmin - this->constants[i] * maxs[i]; + // v * c[i] + m = y (if v were a real value) v = (lb - m) / this->constants[i]; if (v * this->constants[i] + m == lb) @@ -262,7 +264,7 @@ static int fd_poly_ne_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_poly_ne(int cs[], fd_int xs[], int nterms, fd_int y) { - fd_constraint c = _fd_constraint_new(nterms + 1, nterms); + fd_constraint c = fd__constraint_new(nterms + 1, nterms); int i; if (c) @@ -272,11 +274,8 @@ fd_constraint fd_poly_ne(int cs[], fd_int xs[], int nterms, fd_int y) c->variables[nterms] = FD_INT2C_VAR(y); for (i = 0; i < nterms; ++i) c->constants[i] = cs[i]; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_POLY_NE; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_poly_ne_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/sum-prod.c b/src/constraints/sum-prod.c index 6bad8ee..cd30c6b 100644 --- a/src/constraints/sum-prod.c +++ b/src/constraints/sum-prod.c @@ -393,7 +393,7 @@ static int fd_sum_prod_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_sum_prod(fd_int *xs, fd_int *ys, int nvariables, int k) { - fd_constraint c = _fd_constraint_new(2 * nvariables, 1); + fd_constraint c = fd__constraint_new(2 * nvariables, 1); int i; if (c) @@ -403,11 +403,8 @@ fd_constraint fd_sum_prod(fd_int *xs, fd_int *ys, int nvariables, int k) for (; i < 2 * nvariables; ++i) c->variables[i] = FD_INT2C_VAR(ys[i - nvariables]); c->constants[0] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_SUM_PROD; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_sum_prod_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < 2 * nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/sum.c b/src/constraints/sum.c index add543a..8225477 100644 --- a/src/constraints/sum.c +++ b/src/constraints/sum.c @@ -177,7 +177,7 @@ static int fd_sum_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_sum(fd_int *variables, int nvariables, int k) { - fd_constraint c = _fd_constraint_new(nvariables, 1); + fd_constraint c = fd__constraint_new(nvariables, 1); int i; if (c) @@ -185,11 +185,8 @@ fd_constraint fd_sum(fd_int *variables, int nvariables, int k) for (i = 0; i < nvariables; ++i) c->variables[i] = FD_INT2C_VAR(variables[i]); c->constants[0] = k; -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_SUM; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_sum_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/sum2.c b/src/constraints/sum2.c index ddf5541..0dd7c8f 100644 --- a/src/constraints/sum2.c +++ b/src/constraints/sum2.c @@ -94,7 +94,7 @@ static int fd_sum2_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_sum2(fd_int *variables, int nvariables, fd_int x) { - fd_constraint c = _fd_constraint_new(nvariables + 1, 0); + fd_constraint c = fd__constraint_new(nvariables + 1, 0); int i; if (c) @@ -102,11 +102,8 @@ fd_constraint fd_sum2(fd_int *variables, int nvariables, fd_int x) for (i = 0; i < nvariables; ++i) c->variables[i] = FD_INT2C_VAR(variables[i]); c->variables[nvariables] = FD_INT2C_VAR(x); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_SUM2; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_sum2_propagate2; -#endif /* CONSTRAINT_CLASS */ for (i = 0; i < nvariables + 1; ++i) _fd_var_add_constraint(VAR(c, i), c); diff --git a/src/constraints/var-eq-minus.c b/src/constraints/var-eq-minus.c index 0fd59da..d403b5d 100644 --- a/src/constraints/var-eq-minus.c +++ b/src/constraints/var-eq-minus.c @@ -1,4 +1,4 @@ -/* X = Y - Z */ +/* x = y - z */ static int fd_var_eq_minus_filter(fd_constraint this) { @@ -10,7 +10,7 @@ static int fd_var_eq_minus_filter(fd_constraint this) y = VAR(this, 1); z = VAR(this, 2); - // XXX: just do bounds consistency, for now + // bounds consistency xmin = _fd_var_min(x); xmax = _fd_var_max(x); @@ -28,6 +28,15 @@ static int fd_var_eq_minus_filter(fd_constraint this) _fd_revise_connected(NULL, y); } +#ifndef DISABLE_ENTAILED + if ((xmin == xmax) + (zmin == zmax) == 2) + { + fd__constraint_set_entailed(this); + + return FD_OK; + } +#endif + ymin = _fd_var_min(y); ymax = _fd_var_max(y); @@ -54,98 +63,129 @@ static int fd_var_eq_minus_filter(fd_constraint this) _fd_revise_connected(NULL, x); } -#if CONSTRAINT_TEMPS > 3 - if (fd_var_single(x, 0) && fd_var_single(y, 0) && fd_var_single(z, 0)) +#ifndef DISABLE_ENTAILED + if ((ymin == ymax) + (zmin == zmax) == 2) fd__constraint_set_entailed(this); #endif return FD_OK; } -int fd_var_eq_minus_propagate2(fd_constraint this, fd_int culprit) +static int fd_var_eq_minus_propagate2(fd_constraint this, fd_int culprit) { fd_int x, y, z; + int xmin, xmax, ymin, ymax, zmin, zmax; int changed_x = 0, changed_y = 0, changed_z = 0; x = VAR(this, 0); y = VAR(this, 1); z = VAR(this, 2); - // XXX: just do bounds consistency, for now + // bounds consistency if (culprit == x) { - changed_y = - _fd_var_del_lt(_fd_var_min(x) + _fd_var_min(z), y); - changed_y |= - _fd_var_del_gt(_fd_var_max(x) + _fd_var_max(z), y); + xmin = _fd_var_min(x); + xmax = _fd_var_max(x); - if (changed_y && fd_domain_empty(y)) - return FD_NOSOLUTION; + changed_y = _fd_var_del_lt(xmin + _fd_var_min(z), y) | + _fd_var_del_gt(xmax + _fd_var_max(z), y); + + if (changed_y) + { + if (fd_domain_empty(y)) + return FD_NOSOLUTION; + + _fd_revise_connected(NULL, y); // XXX: NULL or this? + } + + ymin = _fd_var_min(y); + ymax = _fd_var_max(y); changed_z = - _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(x), z); - changed_z |= - _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(x), z); + _fd_var_del_lt(ymin - xmax, z) | _fd_var_del_gt(ymax - xmin, z); - if (changed_z && fd_domain_empty(z)) - return FD_NOSOLUTION; + if (changed_z) + { + if (fd_domain_empty(z)) + return FD_NOSOLUTION; + + _fd_revise_connected(NULL, z); // XXX: NULL or this? + } } else if (culprit == y) { - changed_x = - _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(z), x); - changed_x |= - _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(z), x); + ymin = _fd_var_min(y); + ymax = _fd_var_max(y); - if (changed_x && fd_domain_empty(x)) - return FD_NOSOLUTION; + changed_x = _fd_var_del_lt(ymin - _fd_var_max(z), x) | + _fd_var_del_gt(ymax - _fd_var_min(z), x); + + if (changed_x) + { + if (fd_domain_empty(x)) + return FD_NOSOLUTION; + + _fd_revise_connected(NULL, x); // XXX: NULL or this? + } + + xmin = _fd_var_min(x); + xmax = _fd_var_max(x); changed_z = - _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(x), z); - changed_z |= - _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(x), z); + _fd_var_del_lt(ymin - xmax, z) | _fd_var_del_gt(ymax - xmin, z); - if (changed_z && fd_domain_empty(z)) - return FD_NOSOLUTION; + if (changed_z) + { + if (fd_domain_empty(z)) + return FD_NOSOLUTION; + + _fd_revise_connected(NULL, z); // XXX: NULL or this? + } } else // culprit == z { - changed_x = - _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(z), x); - changed_x |= - _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(z), x); + zmin = _fd_var_min(z); + zmax = _fd_var_max(z); - if (changed_x && fd_domain_empty(x)) - return FD_NOSOLUTION; + changed_x = _fd_var_del_lt(_fd_var_min(y) - zmax, x) | + _fd_var_del_gt(_fd_var_max(y) - zmin, x); - changed_y = - _fd_var_del_lt(_fd_var_min(x) + _fd_var_min(z), y); - changed_y |= - _fd_var_del_gt(_fd_var_max(x) + _fd_var_max(z), y); + if (changed_x) + { + if (fd_domain_empty(x)) + return FD_NOSOLUTION; - if (changed_y && fd_domain_empty(y)) - return FD_NOSOLUTION; - } + _fd_revise_connected(NULL, x); // XXX: NULL or this? + } - if (changed_x) - _fd_revise_connected(NULL, x); // XXX: NULL or this? + xmin = _fd_var_min(x); + xmax = _fd_var_max(x); - if (changed_y) - _fd_revise_connected(NULL, y); // XXX: NULL or this? + changed_y = + _fd_var_del_lt(xmin + zmin, y) | _fd_var_del_gt(xmax + zmax, y); - if (changed_z) - _fd_revise_connected(NULL, z); // XXX: NULL or this? + if (changed_y) + { + if (fd_domain_empty(y)) + return FD_NOSOLUTION; -#if CONSTRAINT_TEMPS > 3 - if (fd_var_single(x, 0) && fd_var_single(y, 0) && fd_var_single(z, 0)) + _fd_revise_connected(NULL, y); // XXX: NULL or this? + } + + ymin = zmin + xmin; + ymax = zmax + xmax; + } + +#ifndef DISABLE_ENTAILED + if ((xmin == xmax) + (ymin == ymax) == 2) fd__constraint_set_entailed(this); #endif return FD_OK; } -int fd_var_eq_minus_propagate(fd_constraint this, fd_int revise) +static int fd_var_eq_minus_propagate(fd_constraint this, fd_int revise) { fd_int x, y, z; int changed; @@ -190,19 +230,15 @@ int fd_var_eq_minus_propagate(fd_constraint this, fd_int revise) fd_constraint fd_var_eq_minus(fd_int x, fd_int y, fd_int z) { - fd_constraint c = _fd_constraint_new(3, 0); + fd_constraint c = fd__constraint_new(3, 0); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); c->variables[2] = FD_INT2C_VAR(z); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_VAR_EQ_MINUS; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_var_eq_minus_propagate2; - c->propagator = fd_var_eq_minus_propagate; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/constraints/var-eq-times.c b/src/constraints/var-eq-times.c index 17438f3..eedfd36 100644 --- a/src/constraints/var-eq-times.c +++ b/src/constraints/var-eq-times.c @@ -177,18 +177,15 @@ int fd_var_eq_times_propagate2(fd_constraint this, fd_int culprit) fd_constraint fd_var_eq_times(fd_int x, fd_int y, fd_int z) { - fd_constraint c = _fd_constraint_new(3, 0); + fd_constraint c = fd__constraint_new(3, 0); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); c->variables[2] = FD_INT2C_VAR(z); -#ifdef CONSTRAINT_CLASS + c->kind = FD_CONSTR_VAR_EQ_TIMES; -#else /* CONSTRAINT_CLASS */ - c->propagator2 = fd_var_eq_times_propagate2; -#endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); diff --git a/src/dsearch-sg.c b/src/dsearch-sg.c index 55b1886..1a7f761 100644 --- a/src/dsearch-sg.c +++ b/src/dsearch-sg.c @@ -15,6 +15,9 @@ #include "variables.h" #include "values.h" #include "bound.h" +#include "constraints.h" + +#include "util.h" #if STEAL_WORK > 0 #include <time.h> @@ -52,9 +55,7 @@ void _fd_epoch_forward() void _fd_epoch_rewind() { -#ifdef CONSTRAINT_TEMPS fd__constraint_data_reset(); -#endif } int _fd_dsearch(fd_int variables[], int agent_no) @@ -69,20 +70,20 @@ int _fd_dsearch(fd_int variables[], int agent_no) agent = agent_no; #if defined(NEW_ENTRANCE) && defined(DEBUG_SPLITGO) - _fd_debug("[%d.%d] agents_searching = %d, agents_failed = %d\n", tid, agent, agents_searching, agents_failed); + fd__debug("[%d.%d] agents_searching = %d, agents_failed = %d\n", tid, agent, agents_searching, agents_failed); #endif _fd_init_local_depository(); #if DEBUG_SPLITGO > 1 - _fd_output("[%d.%d] ", tid, agent); _fd_cprint2(variables); + fd__output("[%d.%d] ", tid, agent); _fd_cprint2(variables); #endif if (_fd_filter_domains() == FD_NOSOLUTION) { fd_int variable = NULL; - _fd_debug("[%d.%d] failed before beginning\n", tid, agent); + fd__trace("[%d.%d] failed before beginning\n", tid, agent); #if STEAL_WORK > 0 #ifdef NEW_ENTRANCE @@ -106,20 +107,14 @@ int _fd_dsearch(fd_int variables[], int agent_no) do { -#ifndef INDEX_IN_POOL - if (!_fd_steal_store(store, agent_no, 7)) -#else if (!_fd_steal_store(store, &variable, agent_no, 7)) -#endif { - _fd_debug("[%d.%d] giving up\n", tid, agent); + fd__trace("[%d.%d] giving up\n", tid, agent); return FD_NOSOLUTION; } -#ifdef CONSTRAINT_TEMPS fd__constraint_data_reset(); // XXX: this doesn't belong here! -#endif } while (_fd_revise_wrt_variable(variable) == FD_NOSOLUTION); #else /* STEAL_WORK > 0 */ @@ -128,7 +123,7 @@ int _fd_dsearch(fd_int variables[], int agent_no) } #if DEBUG_SPLITGO > 1 - _fd_output("[%d.%d] ", tid, agent); _fd_cprint2(variables); + fd__output("[%d.%d] ", tid, agent); _fd_cprint2(variables); #endif #ifdef NEW_ENTRANCE @@ -139,7 +134,7 @@ int _fd_dsearch(fd_int variables[], int agent_no) pthread_spin_unlock(&entrance_lock); #endif - _fd_debug("[%d.%d] about to start searching\n", tid, agent); + fd__trace("[%d.%d] about to start searching\n", tid, agent); return _fd_dsearch_(variables); } @@ -170,7 +165,7 @@ static int _fd_dsearch_(fd_int _fd_variables[]) instantiations++; #ifdef DEBUG_PROGRESS if (instantiations % 100000 == 0) - _fd_debug("[%d.%d] still alive (%d stores)\n", tid, agent, + fd__debug("[%d.%d] still alive (%d stores)\n", tid, agent, next_split_index - base_split_index); #endif @@ -202,7 +197,7 @@ static int _fd_dsearch_(fd_int _fd_variables[]) { if (!_fd_counting_solutions) { - _fd_debug("[%d.%d] performed %d instantiations and %d backtracks\n", + fd__trace("[%d.%d] performed %d instantiations and %d backtracks\n", tid, agent, instantiations, backtrack); _fd_statistics_pool(); @@ -229,10 +224,10 @@ static int _fd_dsearch_(fd_int _fd_variables[]) if (!_fd_counting_solutions) { - _fd_debug("[%d.%d] performed %d instantiations and %d backtracks\n", tid, + fd__trace("[%d.%d] performed %d instantiations and %d backtracks\n", tid, agent, instantiations, backtrack); - _fd_debug("[%d.%d] %d stores in store\n", tid, agent, next_split_index - base_split_index); + fd__trace("[%d.%d] %d stores in store\n", tid, agent, next_split_index - base_split_index); _fd_statistics_pool(); } diff --git a/src/fdc_int.h b/src/fdc_int.h index 57246b9..d12eda2 100644 --- a/src/fdc_int.h +++ b/src/fdc_int.h @@ -152,33 +152,15 @@ struct fd_value { #define FD_INT2C_VAR(v) ((v)->index) struct fd_constraint { -#ifdef CONSTRAINT_TEMPS +#if defined(CONSTRAINT_TEMPS) || !defined(DISABLE_ENTAILED) int index; #endif C_VAR_T *variables; // variables involved in the constraint int nvariables; // number of variables int *constants; // constraint's constants (where applicable) int nconstants; // number of constants -#ifdef CONSTRAINT_CLASS // _fd_constraint_kind kind; // what kind of constraint is this? int kind; // what kind of constraint is this? // XXX -#else /* CONSTRAINT_CLASS */ - int (*propagator2)(fd_constraint, fd_int); - // how to propagate changes in a variable's - // domain; 2nd argument is the variable - // against which to revise the domains of - // the other variables in the constraint; - // returns 1 if some domain becomes empty - int (*filter)(fd_constraint); - // performs an initial filtering of the - // domains of the constraint variables - int (*propagator)(fd_constraint, fd_int); - // how to propagate changes in a variable's - // domain; 2nd argument is the variable to - // revise (against the domains of every - // other variable in the constraint); - // returns 1 if some domain became empty -#endif /* CONSTRAINT_CLASS */ }; #define fd_cvariable(c,v) ((c)->variables[v]) // XXX: not being used @@ -197,6 +179,7 @@ extern int fd_variables_count; extern __thread fd_int _fd_variables[]; fd_int fd_new(int, int); +fd_int fd_const(int); // type for the variable's constraints #define VAR_C_T int @@ -266,6 +249,8 @@ typedef enum { #endif /* DISTRIBUTED_SOLVER */ -#ifdef FAST -# define _fd_debug(...) ((void) 0) -#endif /* FAST */ +#ifdef TRACE +# define fd__trace fd__debug +#else +# define fd__trace(...) ((void) 0) +#endif diff --git a/src/matching.c b/src/matching.c index 9fbf099..13a8933 100644 --- a/src/matching.c +++ b/src/matching.c @@ -9,6 +9,10 @@ #include "values.h" #include "matching.h" +#ifdef DEBUG_MATCH +# include "util.h" +#endif + #define UNSEEN (-2) // value not seen in any domain #define WHITE (-1) @@ -297,7 +301,7 @@ static void _fd_mark_cycles(fd_constraint c, int8_t *vgraph, int r_verts, if (vgraph[var * r_verts + val] == 1) { -// _fd_debug("marking %d in %d's domain\n", val + min, VAR(c, var)->index); +// fd__debug("marking %d in %d's domain\n", val + min, VAR(c, var)->index); vgraph[var * r_verts + val] = 3; } @@ -604,7 +608,7 @@ static void _fd_remark_cycles(fd_constraint c, int culprit, int8_t *vgraph, if (vgraph[var * r_verts + val] == 1) { -// _fd_debug("marking %d in %d's domain\n", val + min, VAR(c, var)->index); +// fd__debug("marking %d in %d's domain\n", val + min, VAR(c, var)->index); vgraph[var * r_verts + val] = 3; } @@ -620,7 +624,7 @@ static void _fd_remark_cycles(fd_constraint c, int culprit, int8_t *vgraph, for (i = 0; i < nvariables; ++i) if (l_scc[i] == r_scc[v] && vgraph[i * r_verts + v] == 1) { -// _fd_debug("marking %d in %d's domain\n", v + min, VAR(c, i)->index); +// fd__debug("marking %d in %d's domain\n", v + min, VAR(c, i)->index); vgraph[i * r_verts + v] = 3; } @@ -694,7 +698,7 @@ static void _fd_mark_paths(fd_constraint c, int8_t *vgraph, int r_verts, continue; #if DEBUG_MATCH > 1 - _fd_debug("marking %d in %d's domain\n", + fd__debug("marking %d in %d's domain\n", queue[head] + min, VAR(c, v)->index); #endif // this edge is in an M-alternating path @@ -772,7 +776,7 @@ int _fd_find_matching(fd_constraint c, int **memory) if (*memory == NULL) { #ifdef DEBUG_MATCH - _fd_debug("all-different memory size is %d\n", size); + fd__debug("all-different memory size is %d\n", size); #endif *memory = malloc(size); // XXX: NULL @@ -784,7 +788,7 @@ int _fd_find_matching(fd_constraint c, int **memory) { // the allocated memory is not enough #ifdef DEBUG_MATCH - _fd_debug("all-different new memory size is %d\n", size); + fd__debug("all-different new memory size is %d\n", size); #endif *memory = realloc(*memory, size); // XXX: NULL @@ -808,13 +812,13 @@ int _fd_find_matching(fd_constraint c, int **memory) l_scc = r_edge + r_verts; r_scc = l_scc + nvariables; vgraph = (int8_t *) (r_scc + r_verts); -#else +#else /* CONSTRAINT_TEMPS */ l_edge = alloca(nvariables * sizeof(*l_edge)); r_edge = alloca(r_verts * sizeof(*r_edge)); l_scc = alloca(nvariables * sizeof(*l_scc)); r_scc = alloca(r_verts * sizeof(*r_scc)); vgraph = alloca(nvariables * r_verts * sizeof(*vgraph)); -#endif +#endif /* CONSTRAINT_TEMPS */ l_parent = alloca(nvariables * sizeof(*l_parent)); l_colour = alloca(nvariables * sizeof(*l_colour)); @@ -967,7 +971,7 @@ int _fd_find_matching(fd_constraint c, int **memory) if (vgraph[i * r_verts + v] == 1) { #ifdef DEBUG_MATCH - _fd_debug("removing %d from %d's domain\n", v + min, + fd__debug("removing %d from %d's domain\n", v + min, VAR(c, i)->index); #endif changed |= _fd_var_del_val(v + min, VAR(c, i)); @@ -1198,7 +1202,7 @@ int _fd_update_matching(fd_constraint c, fd_int culprit, int *memory) if (vgraph[i * r_verts + v] == 1 && /* {XXX */ r_scc[v] == -1 /* XXX} */) { #ifdef DEBUG_MATCH - _fd_debug("removing %d from %d's domain\n", v + min, + fd__debug("removing %d from %d's domain\n", v + min, VAR(c, i)->index); #endif changed |= _fd_var_del_val(v + min, VAR(c, i)); diff --git a/src/options.c b/src/options.c index 713f929..5b74778 100644 --- a/src/options.c +++ b/src/options.c @@ -117,7 +117,7 @@ static char *_fd_options = "@(#) $Options: " #endif #ifdef CONSTRAINT_CLASS - "CONSTRAINT_CLASS" " " +#warning "CONSTRAINT_CLASS committed (16JUN16)" #endif #ifdef CONSTRAINT_TEMPS "CONSTRAINT_TEMPS" " " @@ -143,7 +143,7 @@ static char *_fd_options = "@(#) $Options: " "GROWABLE_POOL" " " #endif #ifdef INDEX_IN_POOL - "INDEX_IN_POOL" " " +#warning "INDEX_IN_POOL committed (24APR16)" #endif #ifdef STORE_IN_POOL "STORE_IN_POOL" " " diff --git a/src/paccs.h b/src/paccs.h index 88cd5ad..b1312bf 100644 --- a/src/paccs.h +++ b/src/paccs.h @@ -14,6 +14,7 @@ void fd_init(int *argc, char **argv[]); void fd_end(void); int fd_solve(void); +fd_int fd_const(int value); fd_int fd_new(int min, int max); void fd_label(fd_int vars[], int nvars); @@ -40,6 +41,7 @@ fd_constraint fd_var_eq_times(fd_int x, fd_int y, fd_int z); /* Global constraints */ fd_constraint fd_all_different(fd_int X[], int n); +fd_constraint fd_fake_all_different(fd_int X[], int n); fd_constraint fd_element(fd_int X[], int n, fd_int y, int k); fd_constraint fd_element_var(fd_int X[], int n, fd_int y, fd_int z); @@ -51,6 +53,7 @@ fd_constraint fd_sum_prod(fd_int X[], fd_int Y[], int n, int k); fd_constraint fd_poly_eq(int C[], fd_int Y[], int n, fd_int z); fd_constraint fd_poly_eq_k(int C[], fd_int Y[], int n, int k); +fd_constraint fd_poly_le_k(int C[], fd_int Y[], int n, int k); fd_constraint fd_poly_ne(int C[], fd_int Y[], int n, fd_int y); fd_constraint fd_poly_ne_k(int C[], fd_int Y[], int n, int k); fd_constraint fd_knapsack2(fd_int X[], fd_int Y[], int n, fd_int z); diff --git a/src/packed.c b/src/packed.c index 43d858b..cfb7f81 100644 --- a/src/packed.c +++ b/src/packed.c @@ -11,6 +11,8 @@ #include "constraints.h" #include "packed.h" +#include "util.h" + static struct _fd_packed_problem *packed_memory; // XXX: so it can be freed #ifdef USE_MMAP static size_t packed_memory_size; @@ -42,7 +44,7 @@ static struct _fd_packed_problem *_fd_allocate_memory() tconsts += _fd_constraints[i]->nconstants; } - _fd_debug("packed size is %d + %d + %d + %d\n", + fd__trace("packed size is %d + %d + %d + %d\n", sizeof(*p), p->nvariables * sizeof(*p->variables), p->nconstraints * sizeof(*p->constraints), @@ -86,7 +88,7 @@ static struct _fd_packed_problem *_fd_allocate_memory() { perror("mmap"); - _fd_fatal("mmap() failed"); + fd__fatal("mmap() failed"); } p = m; @@ -141,10 +143,6 @@ void _fd_pack_problem() int offset; int i, j; -#ifndef CONSTRAINT_CLASS - _fd_fatal("packed problems require CONSTRAINT_CLASS"); -#endif - packed = _fd_allocate_memory(); assert(packed != NULL); // XXX diff --git a/src/packed.h b/src/packed.h index 8c1654c..bc65f82 100644 --- a/src/packed.h +++ b/src/packed.h @@ -36,7 +36,7 @@ struct _fd_packed_int { /* fields must correspond to an initial segment of fd_constraint */ struct _fd_packed_constraint { -#ifdef CONSTRAINT_TEMPS +#if defined(CONSTRAINT_TEMPS) || !defined(DISABLE_ENTAILED) int index; #endif C_VAR_T *variables; diff --git a/src/pool.c b/src/pool.c index 18e05f3..fae7b59 100644 --- a/src/pool.c +++ b/src/pool.c @@ -10,12 +10,9 @@ static __thread _fd_store alt_store; // the other side of the split static _fd_store *split_stores_; #define split_stores split_stores_[agent] -#ifndef INDEX_IN_POOL -static __thread fd_int *split_variable; -#else static int **split_variable_; -static __thread int *split_variable; -#endif +static __thread int *split_variable; // (index of the) variable whose domain + // was split to obtain the store #ifdef GROWABLE_POOL // number of stores in the pool @@ -100,9 +97,7 @@ void _fd_init_store_depository(int agents) for (i = 0; i < agents; ++i) split_indexes[i] = EMPTY_POOL; -#ifdef INDEX_IN_POOL split_variable_ = calloc(agents, sizeof(*split_variable_)); -#endif stores_mutexes = calloc(agents, sizeof(*stores_mutexes)); for (i = 0; i < agents; ++i) @@ -130,18 +125,15 @@ void _fd_init_store_depository(int agents) static void _fd_init_local_depository() { - if (split_stores) + if (split_stores) // see if it has already been initialised { #ifdef STORE_IN_POOL // copy the new store to the pool store = split_stores; memcpy(store, main_store, STORE_SIZE); -#ifdef INDEX_IN_POOL - split_variable[next_split_index] = -1; -#else - split_variable[next_split_index] = NULL; -#endif - ++next_split_index; + + split_variable[next_split_index] = -1; // starting anew + next_split_index++; #endif /* STORE_IN_POOL */ return; @@ -149,24 +141,24 @@ static void _fd_init_local_depository() #ifndef GROWABLE_POOL #ifndef STORE_IN_POOL - _fd_debug("[%d.%d] stores size %d + %d\n", tid, agent, + fd__trace("[%d.%d] stores size %d + %d\n", tid, agent, fd_variables_count * STORE_SIZE, fd_variables_count * sizeof(*split_variable)); if (posix_memalign((void **) &split_stores, sysconf(_SC_PAGESIZE), fd_variables_count * STORE_SIZE + fd_variables_count * sizeof(*split_variable))) - _fd_fatal("unable to allocate pool memory"); + fd__fatal("unable to allocate pool memory"); // XXX: alignment problems possible split_variable = ((void *) split_stores) + fd_variables_count * STORE_SIZE; #else - _fd_debug("[%d.%d] stores size %d + %d\n", tid, agent, + fd__trace("[%d.%d] stores size %d + %d\n", tid, agent, (fd_variables_count + 1) * STORE_SIZE, fd_variables_count * sizeof(*split_variable)); if (posix_memalign((void **) &split_stores, sysconf(_SC_PAGESIZE), (fd_variables_count + 1) * STORE_SIZE + fd_variables_count * sizeof(*split_variable))) - _fd_fatal("unable to allocate pool memory"); + fd__fatal("unable to allocate pool memory"); // XXX: alignment problems possible split_variable = ((void *) split_stores) + (fd_variables_count + 1) * STORE_SIZE; @@ -180,21 +172,19 @@ static void _fd_init_local_depository() fd__label_vars_count + 1 : POOL_DEFAULT_SIZE; #endif - _fd_debug("[%d.%d] stores size %d + %d\n", tid, agent, pool_size * STORE_SIZE, + fd__trace("[%d.%d] stores size %d + %d\n", tid, agent, pool_size * STORE_SIZE, fd_variables_count * sizeof(*split_variable)); - + if (posix_memalign((void **) &split_stores, sysconf(_SC_PAGESIZE), pool_size * STORE_SIZE)) - _fd_fatal("unable to allocate pool memory"); + fd__fatal("unable to allocate pool memory"); if (posix_memalign((void **) &split_variable, sysconf(_SC_PAGESIZE), fd_variables_count * sizeof(*split_variable))) - _fd_fatal("unable to allocate pool variable memory"); + fd__fatal("unable to allocate pool variable memory"); #endif /* GROWABLE_POOL */ -#if defined(INDEX_IN_POOL) && !defined(split_variable) split_variable_[agent] = split_variable; -#endif local_split_indexes = calloc(POOL_INDEXES, sizeof(*local_split_indexes)); split_indexes[agent] = local_split_indexes; @@ -204,12 +194,8 @@ static void _fd_init_local_depository() main_store = store; store = split_stores; memcpy(store, main_store, STORE_SIZE); -#ifdef INDEX_IN_POOL split_variable[next_split_index] = -1; -#else - split_variable[next_split_index] = NULL; -#endif - ++next_split_index; + next_split_index++; #endif /* STORE_IN_POOL */ } @@ -225,11 +211,11 @@ static void _fd_grow_pool(void) #else nsize = (fd_variables_count + 1 < nsize) ? fd_variables_count + 1 : nsize; #endif - _fd_debug("[%d.%d] new pool size is %d\n", tid, agent, nsize * STORE_SIZE); - + fd__trace("[%d.%d] new pool size is %d\n", tid, agent, nsize * STORE_SIZE); + if (posix_memalign((void **) &npool, sysconf(_SC_PAGESIZE), nsize * STORE_SIZE)) - _fd_fatal("unable to allocate pool memory"); + fd__fatal("unable to allocate pool memory"); memcpy(npool, split_stores, pool_size * STORE_SIZE); @@ -251,7 +237,7 @@ static void _fd_grow_pool(void) } #endif /* GROWABLE_POOL */ -/* +/* saving a store to the pool is done in two steps: 1. a copy of the store which is about to be split is saved (to have @@ -280,30 +266,18 @@ static void _fd_start_saving_store(_fd_store *dst) static void _fd_end_saving_store(fd_int variable) { #ifndef STORE_IN_POOL -#ifndef INDEX_IN_POOL - split_variable[next_split_index] = variable; -#else split_variable[next_split_index] = variable->index; -#endif #else /* STORE_IN_POOL */ // here, the split also affects the store which is below the // (about to be) current one -#ifndef INDEX_IN_POOL - split_variable[next_split_index - 1] = variable; -#else split_variable[next_split_index - 1] = variable->index; -#endif #endif /* STORE_IN_POOL */ - ++next_split_index; + next_split_index++; } // try to steal a store from another agent -#ifndef INDEX_IN_POOL -bool _fd_steal_store(_fd_store store_, int agent, int retries) -#else bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) -#endif { #ifndef RANDOM_VICTIM int v; // the victim @@ -317,7 +291,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) #if defined(STORE_IN_POOL) && defined(DECREMENT_EARLY) if (agent != -1) - --next_split_index; + next_split_index--; #endif // only let one agent in at a time @@ -381,7 +355,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) v = candidate; if (retrying) - _fd_debug("[%d.%d] %d tries left\n", tid, agent, retries); + fd__trace("[%d.%d] %d tries left\n", tid, agent, retries); break; } @@ -392,10 +366,10 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) if (active == 0 || retries == 0) { - _fd_debug("[%d.%d] no agent can supply work\n", tid, agent); + fd__trace("[%d.%d] no agent can supply work\n", tid, agent); if (retrying) - _fd_debug("[%d.%d] %d tries left\n", tid, agent, retries); + fd__trace("[%d.%d] %d tries left\n", tid, agent, retries); return false; } @@ -429,13 +403,13 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) // lock access to victim's stores pthread_mutex_lock(&stores_mutexes[v]); #if DEBUG_STEALING > 1 - _fd_debug("[%d.%d] locked %d stores' mutex\n", tid, agent, v); + fd__debug("[%d.%d] locked %d stores' mutex\n", tid, agent, v); #endif stores = split_indexes[v][1] - split_indexes[v][0]; #if DEBUG_STEALING > 1 - _fd_debug("[%d.%d] %d stores left at %d\n", tid, agent, stores, v); + fd__debug("[%d.%d] %d stores left at %d\n", tid, agent, stores, v); #endif // don't steal the last few stores from an agent @@ -445,7 +419,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) pthread_mutex_unlock(&thieves_mutex); #ifdef DEBUG_STEALING - _fd_debug("[%d.%d] not enough stores (%d) at %d\n", tid, agent, stores, v); + fd__debug("[%d.%d] not enough stores (%d) at %d\n", tid, agent, stores, v); #endif return false; @@ -463,14 +437,12 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) memcpy(store_, &split_stores_[v][s * fd_variables_count], STORE_SIZE); -#ifdef INDEX_IN_POOL #ifndef STORE_IN_POOL if (variable) #else if (variable && split_variable_[v][s] != -1) #endif *variable = _fd_variables[split_variable_[v][s]]; -#endif // this agent will likely become the one with the largest search space // (if work is being stolen by the controller, most_work will be set @@ -490,14 +462,10 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) } #ifdef DEBUG_STEALING -#ifdef INDEX_IN_POOL - _fd_debug("[%d.%d] stole work (%d/%d) from %d (var %d)\n", tid, agent, s, + fd__debug("[%d.%d] stole work (%d/%d) from %d (var %d)\n", tid, agent, s, stores, v, split_variable_[v][s]); -#else - _fd_debug("[%d.%d] stole work (%d/%d) from %d\n", tid, agent, s, stores, v); -#endif #if DEBUG_STEALING > 2 - _fd_output("[%d.%d] ", tid, agent); _fd_cprint3(store_); + fd__output("[%d.%d] ", tid, agent); _fd_cprint3(store_); #endif #endif @@ -523,7 +491,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) #if defined(STORE_IN_POOL) && defined(DECREMENT_EARLY) if (agent != -1) - --next_split_index; + next_split_index--; #endif pthread_spin_lock(&starving_lock); @@ -535,7 +503,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) if (as == nagents) { #ifdef DEBUG_STEALING - _fd_debug("[%d.%d] all agents starving...\n", tid, agent); + fd__debug("[%d.%d] all agents starving...\n", tid, agent); #endif return false; @@ -565,14 +533,14 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) // lock access to victim's stores ... pthread_mutex_lock(&stores_mutexes[v]); #if DEBUG_STEALING > 1 - _fd_debug("[%d.%d] locked %d stores' mutex\n", tid, agent, v); + fd__debug("[%d.%d] locked %d stores' mutex\n", tid, agent, v); #endif // ... and make sure that the victim has enough stores stores = split_indexes[v][1] - split_indexes[v][0]; #if DEBUG_STEALING > 1 - _fd_debug("[%d.%d] %d stores left at %d\n", tid, agent, stores, v); + fd__debug("[%d.%d] %d stores left at %d\n", tid, agent, stores, v); #endif // don't steal the last few stores from an agent @@ -583,7 +551,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) pthread_mutex_unlock(&stores_mutexes[v]); #ifdef DEBUG_STEALING - _fd_debug("[%d.%d] not enough stores (%d) at %d\n", tid, agent, + fd__debug("[%d.%d] not enough stores (%d) at %d\n", tid, agent, stores, v); #endif } @@ -596,7 +564,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) // the main thread won't keep trying if (agent == -1) { - _fd_debug("[%d] giving up stealing\n", tid); + fd__trace("[%d] giving up stealing\n", tid); return false; } @@ -608,7 +576,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) if (as == nagents) { #ifdef DEBUG_STEALING - _fd_debug("[%d.%d] all agents starving...\n", tid, agent); + fd__debug("[%d.%d] all agents starving...\n", tid, agent); #endif return false; @@ -619,7 +587,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) #endif #ifdef DEBUG_STEALING - _fd_debug("[%d.%d] pausing...\n", tid, agent); + fd__debug("[%d.%d] pausing...\n", tid, agent); #endif nanosleep(&delay, NULL); @@ -631,7 +599,7 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) if (as == nagents) { #ifdef DEBUG_STEALING - _fd_debug("[%d.%d] all agents starving...\n", tid, agent); + fd__debug("[%d.%d] all agents starving...\n", tid, agent); #endif return false; @@ -667,14 +635,12 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) memcpy(store_, &split_stores_[v][s * fd_variables_count], STORE_SIZE); -#ifdef INDEX_IN_POOL #ifndef STORE_IN_POOL if (variable) #else if (variable && split_variable_[v][s] != -1) #endif *variable = _fd_variables[split_variable_[v][s]]; -#endif // this agent will likely become the one with the largest search space // (if work is being stolen by the controller, most_work will be set @@ -697,14 +663,10 @@ bool _fd_steal_store(_fd_store store_, fd_int *variable, int agent, int retries) } #if DEBUG_STEALING > 0 -#ifdef INDEX_IN_POOL - _fd_debug("[%d.%d] stole work (%d/%d) from %d (var %d)\n", tid, agent, s, + fd__debug("[%d.%d] stole work (%d/%d) from %d (var %d)\n", tid, agent, s, stores, v, split_variable_[v][s]); -#else - _fd_debug("[%d.%d] stole work (%d/%d) from %d\n", tid, agent, s, stores, v); -#endif #if DEBUG_STEALING > 2 - _fd_output("[%d.%d] ", tid, agent); _fd_cprint3(store_); + fd__output("[%d.%d] ", tid, agent); _fd_cprint3(store_); #endif #endif @@ -733,24 +695,20 @@ static bool _fd_restore_store(fd_int *variable) #if STEAL_WORK < 1 return false; #else /* STEAL_WORK < 1 */ -#ifndef INDEX_IN_POOL - return _fd_steal_store(store, agent, 0); -#else return _fd_steal_store(store, variable, agent, 0); -#endif #endif /* STEAL_WORK < 1 */ #if STEAL_WORK > 0 if (next_split_index - base_split_index < INDEX_SAFE) { - //_fd_debug("[%d.%d] have %d stores\n", tid, agent, next_split_index - base_split_index); -#ifndef FAST + //fd__trace("[%d.%d] have %d stores\n", tid, agent, next_split_index - base_split_index); +#ifdef TRACE if (pthread_mutex_trylock(&stores_mutexes[agent])) - _fd_debug("[%d.%d] *** found stores locked [%d,%d[\n", tid, agent, + fd__trace("[%d.%d] *** found stores locked [%d,%d[\n", tid, agent, base_split_index, next_split_index), #endif pthread_mutex_lock(&stores_mutexes[agent]); - //_fd_debug("[%d.%d] locked stores\n", tid, agent); + //fd__trace("[%d.%d] locked stores\n", tid, agent); locked = true; } @@ -763,7 +721,7 @@ static bool _fd_restore_store(fd_int *variable) ++pool_gets; #endif - --next_split_index; + next_split_index--; #ifndef STORE_IN_POOL memcpy(store, &split_stores[next_split_index * fd_variables_count], @@ -774,18 +732,10 @@ static bool _fd_restore_store(fd_int *variable) #endif #ifndef STORE_IN_POOL -# ifndef INDEX_IN_POOL - *variable = split_variable[next_split_index]; -# else *variable = _fd_variables[split_variable[next_split_index]]; -# endif /* INDEX_IN_POOL */ #else -# ifndef INDEX_IN_POOL - *variable = split_variable[next_split_index - 1]; -# else assert(split_variable[next_split_index - 1] != -1); *variable = _fd_variables[split_variable[next_split_index - 1]]; -# endif /* INDEX_IN_POOL */ #endif /* STORE_IN_POOL */ #if STEAL_WORK > 0 diff --git a/src/problem.c b/src/problem.c index 4b51163..30d0330 100644 --- a/src/problem.c +++ b/src/problem.c @@ -10,6 +10,8 @@ #include "values.h" #include "constraints.h" +#include "util.h" + extern int fd__workers; static void _fd_cleanup(void); @@ -114,7 +116,7 @@ void fd_init(int *argc, char **argv[]) { #ifdef SPLITGO_MPI if (MPI_Init(argc, argv)) - _fd_fatal("MPI_Init failed"); + fd__fatal("MPI_Init failed"); #endif _fd_parse_general_options(argc, *argv); @@ -123,9 +125,7 @@ void fd_init(int *argc, char **argv[]) fd__init_splitgo(argc, *argv); #endif -#ifdef CONSTRAINT_CLASS - _fd_init_constraints(); -#endif + fd__init_constraints(); #ifdef USE_STORE _fd_init_main_store(); diff --git a/src/revisions.c b/src/revisions.c index 0f396ed..1243d90 100644 --- a/src/revisions.c +++ b/src/revisions.c @@ -7,6 +7,8 @@ #include "fdc_int.h" #include "constraints.h" +#include "util.h" + #ifdef REVISION_IS_VAR typedef fd_int revision; #else /* REVISION_IS_VAR */ @@ -181,7 +183,7 @@ int _fd_perform_revisions() if (_fd_propagate(c, v) == FD_NOSOLUTION) { #ifdef COUNT_REVISIONS - _fd_debug("failed after %d revisions\n", nr + 1); + fd__debug("failed after %d revisions\n", nr + 1); #endif return FD_NOSOLUTION; @@ -212,7 +214,7 @@ int _fd_perform_revisions() free(r); #ifdef COUNT_REVISIONS - _fd_debug("failed after %d revisions\n", nr + 1); + fd__debug("failed after %d revisions\n", nr + 1); #endif return FD_NOSOLUTION; @@ -228,7 +230,7 @@ int _fd_perform_revisions() #endif /* ORDER_REVISIONS */ #ifdef COUNT_REVISIONS - _fd_debug("performed %d revisions\n", nr); + fd__debug("performed %d revisions\n", nr); #endif return FD_OK; @@ -251,7 +253,7 @@ static int filter_domains() if (_fd_filter(c) == FD_NOSOLUTION) { #ifdef COUNT_REVISIONS - _fd_debug("failed after %d filtering steps\n", nr + 1); + fd__debug("failed after %d filtering steps\n", nr + 1); #endif return FD_NOSOLUTION; @@ -263,7 +265,7 @@ static int filter_domains() } #ifdef COUNT_REVISIONS - _fd_debug("performed %d filtering steps\n", nr); + fd__debug("performed %d filtering steps\n", nr); #endif // revise domains wrt the variables whose domains changed @@ -272,9 +274,7 @@ static int filter_domains() int _fd_filter_domains() { -#ifdef CONSTRAINT_TEMPS fd__constraint_data_reset(); -#endif return filter_domains(); } diff --git a/src/splitting.c b/src/splitting.c index 0b5ff2e..c807cbb 100644 --- a/src/splitting.c +++ b/src/splitting.c @@ -5,6 +5,8 @@ #include "values.h" #include "store.h" +#include "util.h" + #ifndef COMPACT_DOMAINS #error "only works with COMPACT_DOMAINS" #endif @@ -210,7 +212,7 @@ static int fd__split_even_one(int n, _fd_store stores[]) if (v == fd__label_vars_count) { - _fd_debug("[%d] cannot split %d-ways evenly, resorting to even " + fd__debug("[%d] cannot split %d-ways evenly, resorting to even " "splitting\n", tid, n); return fd__split_even(n, stores); @@ -258,7 +260,7 @@ int fd__split_problem(int n, _fd_store stores[], int v, p; #ifdef DEBUG_SPLITTING - _fd_output("before splitting: "); _fd_cprint3(store); + fd__output("before splitting: "); _fd_cprint3(store); #endif parts = splitter(n, stores); @@ -272,9 +274,9 @@ int fd__split_problem(int n, _fd_store stores[], _fd_copy_value(SVALUE(stores[p][v]), DOMAIN(_fd_variables[v])); #ifdef DEBUG_SPLITTING - _fd_output("split into %d out of %d stores\n", np, n); + fd__output("split into %d out of %d stores\n", np, n); for (p = 0; p < n; ++p) - _fd_output("store %d: ", p), _fd_cprint3(stores[p]); + fd__output("store %d: ", p), _fd_cprint3(stores[p]); #endif return parts; diff --git a/src/util.c b/src/util.c index a328d31..e204e51 100644 --- a/src/util.c +++ b/src/util.c @@ -2,13 +2,15 @@ #include <stdlib.h> #include <stdarg.h> -void _fd_fatal(char *msg) +#include "util.h" + +void fd__fatal(char *msg) { fprintf(stderr, "%s\n", msg); abort(); // XXX } -void _fd_error(char *format, ...) +void fd__error(char *format, ...) { va_list args; @@ -17,7 +19,7 @@ void _fd_error(char *format, ...) va_end (args); } -void _fd_output(char *format, ...) +void fd__output(char *format, ...) { va_list args; @@ -35,9 +37,9 @@ void fd__info(char *format, ...) va_end (args); } -#ifndef _fd_debug +#ifndef fd__debug -void _fd_debug(char *format, ...) +void fd__debug(char *format, ...) { va_list args; diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..ee09e98 --- /dev/null +++ b/src/util.h @@ -0,0 +1,8 @@ +void fd__fatal(char *msg); +void fd__error(char *format, ...); +void fd__output(char *format, ...); +void fd__info(char *format, ...); + +#ifndef fd__debug +void fd__debug(char *format, ...); +#endif diff --git a/src/values-bitmap.c b/src/values-bitmap.c index c3fcc17..b76d70f 100644 --- a/src/values-bitmap.c +++ b/src/values-bitmap.c @@ -58,10 +58,10 @@ fd_value fd_new_value(int min, int max) fd_value v; if (min < MIN_VALUE) - _fd_fatal("value less than MIN_VALUE"); + fd__fatal("value less than MIN_VALUE"); if (max > MAX_VALUE) - _fd_fatal("value greater than MAX_VALUE"); + fd__fatal("value greater than MAX_VALUE"); #ifdef INLINE_DOMAINS return (ALL_ONES >> min) & (ALL_ONES << DOMAIN_BITS - max - 1); @@ -95,10 +95,10 @@ fd_value fd_new_value(int min, int max) void _fd_init_domain(DOMAIN_REF_T(domain), int min, int max) { if (min < MIN_VALUE) - _fd_fatal("value less than MIN_VALUE"); + fd__fatal("value less than MIN_VALUE"); if (max > MAX_VALUE) - _fd_fatal("value greater than MAX_VALUE"); + fd__fatal("value greater than MAX_VALUE"); #if WORDS == 1 (*domain)[0] = (ALL_ONES >> min) & (ALL_ONES << DOMAIN_BITS - max - 1); @@ -1278,10 +1278,10 @@ fd_value fd_new_value(int min, int max) fd_value v; if (min < MIN_VALUE) - _fd_fatal("value less than MIN_VALUE"); + fd__fatal("value less than MIN_VALUE"); if (max > MAX_VALUE) - _fd_fatal("value greater than MAX_VALUE"); + fd__fatal("value greater than MAX_VALUE"); #if WORDS == 1 if (v = malloc(sizeof(*v))) @@ -1320,10 +1320,10 @@ fd_value fd_new_value(int min, int max) void _fd_init_domain(DOMAIN_REF_T(domain), int min, int max) { if (min < MIN_VALUE) - _fd_fatal("value less than MIN_VALUE"); + fd__fatal("value less than MIN_VALUE"); if (max > MAX_VALUE) - _fd_fatal("value greater than MAX_VALUE"); + fd__fatal("value greater than MAX_VALUE"); #if WORDS == 1 *domain->map = (ALL_ONES >> min) & (ALL_ONES << DOMAIN_BITS - max - 1); diff --git a/src/values-intervals.c b/src/values-intervals.c index a29f557..cdc888a 100644 --- a/src/values-intervals.c +++ b/src/values-intervals.c @@ -90,10 +90,10 @@ int _fd_val_max(fd_value domain) case FD_MULTIPLE: return v->value.interval.upper; case FD_EMPTY: - _fd_fatal("empty domain in _fd_val_max"); + fd__fatal("empty domain in _fd_val_max"); /* NOTREACHED */ default: - _fd_fatal("corrupt domain in _fd_val_max?"); + fd__fatal("corrupt domain in _fd_val_max?"); /* NOTREACHED */ } } @@ -108,10 +108,10 @@ int _fd_val_min(fd_value domain) case FD_MULTIPLE: return domain->value.interval.lower; case FD_EMPTY: - _fd_fatal("empty domain in _fd_val_min"); + fd__fatal("empty domain in _fd_val_min"); /* NOTREACHED */ default: - _fd_fatal("corrupt domain in _fd_val_min?"); + fd__fatal("corrupt domain in _fd_val_min?"); /* NOTREACHED */ } } @@ -151,10 +151,10 @@ int _fd_val_del_min(fd_value domain) break; case FD_EMPTY: - _fd_fatal("empty domain in _fd_val_del_min"); + fd__fatal("empty domain in _fd_val_del_min"); /* NOTREACHED */ default: - _fd_fatal("corrupt domain in _fd_val_del_min?"); + fd__fatal("corrupt domain in _fd_val_del_min?"); /* NOTREACHED */ } @@ -198,10 +198,10 @@ int _fd_val_del_max(fd_value domain) break; case FD_EMPTY: - _fd_fatal("empty domain in _fd_val_del_max"); + fd__fatal("empty domain in _fd_val_del_max"); /* NOTREACHED */ default: - _fd_fatal("corrupt domain in _fd_val_del_max?"); + fd__fatal("corrupt domain in _fd_val_del_max?"); /* NOTREACHED */ } @@ -230,10 +230,10 @@ int _fd_val_contains_val(fd_value domain, int value) break; case FD_EMPTY: - _fd_fatal("empty domain in _fd_val_contains_val"); + fd__fatal("empty domain in _fd_val_contains_val"); /* NOTREACHED */ default: - _fd_fatal("corrupt domain in _fd_val_contains_val?"); + fd__fatal("corrupt domain in _fd_val_contains_val?"); /* NOTREACHED */ } @@ -249,7 +249,7 @@ void _fd_val_set_value(fd_value domain, int value) switch (domain->kind) { case FD_EMPTY: - _fd_fatal("_fd_val_set_val called on a variable with empty domain"); + fd__fatal("_fd_val_set_val called on a variable with empty domain"); /* NOTREACHED */ case FD_MULTIPLE: domain->kind = FD_SINGLETON; @@ -262,7 +262,7 @@ void _fd_val_set_value(fd_value domain, int value) } break; default: - _fd_fatal("corrupt domain in _fd_val_set_value?"); + fd__fatal("corrupt domain in _fd_val_set_value?"); /* NOTREACHED */ } } @@ -702,7 +702,7 @@ fd_value _fd_val_clone(fd_value value) *next = fd_new_value(1, 0); break; default: - _fd_fatal("corrupt domain in _fd_val_clone?"); + fd__fatal("corrupt domain in _fd_val_clone?"); /* NOTREACHED */ } @@ -744,7 +744,7 @@ void _fd_val_copy(fd_value to, fd_value from) break; #endif default: - _fd_fatal("corrupt domain in _fd_val_copy?"); + fd__fatal("corrupt domain in _fd_val_copy?"); /* NOTREACHED */ } @@ -769,7 +769,7 @@ int _fd_val_size(fd_value domain) s += v->value.interval.upper - v->value.interval.lower + 1; break; default: - _fd_fatal("corrupt domain in _fd_val_size?"); + fd__fatal("corrupt domain in _fd_val_size?"); /* NOTREACHED */ } diff --git a/src/values.c b/src/values.c index 7a2987c..f738a75 100644 --- a/src/values.c +++ b/src/values.c @@ -7,6 +7,8 @@ #include "fdc_int.h" #include "values.h" +#include "util.h" + #ifdef COMPACT_DOMAINS # include "values-bitmap.c" diff --git a/src/variables.c b/src/variables.c index 1f10edc..f72a0b1 100644 --- a/src/variables.c +++ b/src/variables.c @@ -9,18 +9,31 @@ #include "store.h" #include "constraints.h" +#include "util.h" + int fd_variables_count = 0; __thread fd_int _fd_variables[MAX_VARIABLES]; +// variables with singleton domains (ie, constants) +static fd_int fd__constants[MAX_VALUE + 1]; + fd_int *fd__label_vars = 0; // variables subject to labelling int fd__label_vars_count = 0; bool *fd__var_labelled; // identifies the variables subject to labelling -fd_int fd_new(int min, int max) + +/* + Create and return a new variable with domain { MIN, ..., MAX }. + Also store it in the global variable table. +*/ +static fd_int create_variable(int min, int max) { - fd_int v = malloc(sizeof(struct fd_int)); + fd_int v; - assert(fd_variables_count < MAX_VARIABLES); + if (fd_variables_count == MAX_VARIABLES) + fd__fatal("too many variables, increase MAX_VARIABLES"); + + v = malloc(sizeof(struct fd_int)); if (v) { @@ -39,6 +52,31 @@ fd_int fd_new(int min, int max) return v; } +/* Return a variable with singleton domain { VALUE }. */ +fd_int fd_const(int value) +{ + if (value < MIN_VALUE) + fd__fatal("value less than MIN_VALUE"); + + if (value > MAX_VALUE) + fd__fatal("value greater than MAX_VALUE"); + + // only create the variable if it has not yet been created + if (fd__constants[value] == NULL) + fd__constants[value] = create_variable(value, value); + + return fd__constants[value]; +} + +/* Return a variable with domain { MIN, ..., MAX }. */ +fd_int fd_new(int min, int max) +{ + if (min == max) + return fd_const(min); + else + return create_variable(min, max); +} + #ifdef SPLITGO /* create a skeletal copy of VARIABLE */ // XXX: description fd_int _fd_var_copy(fd_int variable) @@ -302,7 +340,7 @@ void _fd_var_set_value(fd_int variable, int value) void fd_label(fd_int variables[], int n) { if (fd__label_vars) - _fd_fatal("fd_label() can only be called once"); + fd__fatal("fd_label() can only be called once"); fd__label_vars = malloc(n * sizeof(*fd__label_vars)); // XXX: NULL fd__label_vars_count = n; diff --git a/src/variables.h b/src/variables.h index 2ca1d01..7e76215 100644 --- a/src/variables.h +++ b/src/variables.h @@ -7,6 +7,7 @@ extern fd_int *fd__label_vars; extern int fd__label_vars_count; extern bool *fd__var_labelled; +fd_int fd_const(int value); fd_int fd_new(int min, int max); fd_int _fd_var_copy(fd_int variable); void _fd_var_copy_domain(fd_int to, fd_int from); @@ -36,15 +37,15 @@ int _fd_var_intersect(fd_int variable1, fd_int variable2); int _fd_var_contains_val(fd_int variable, int value); void _fd_var_set_value(fd_int variable, int value); -#define fd_update_domain(op,var,value) \ - { \ - _fd_var_ ## op(var, value); \ - \ - _fd_revise_connected(var); \ - } +#define fd_update_domain(op, val, var) \ + do { \ + _fd_var_ ## op(val, var); \ + \ + _fd_revise_connected(this, var); \ + } while (0) #define fd_update_domain_and_check(op, val, var) \ - { \ + do { \ if (_fd_var_ ## op(val, var)) \ { \ if (fd_domain_empty(var)) \ @@ -52,7 +53,7 @@ void _fd_var_set_value(fd_int variable, int value); \ _fd_revise_connected(this, var); \ } \ - } + } while (0) // SEARCH extern int (*fd__cmp_variables)(fd_int, fd_int); -- libgit2 0.21.2