diff options
| -rw-r--r-- | TODO/2.1.md | 96 | ||||
| -rw-r--r-- | TODO/new-feature-ideas.md | 2 | ||||
| -rw-r--r-- | TODO/refactoring.md | 2 | ||||
| -rw-r--r-- | old/solve_old.c | 447 | ||||
| -rw-r--r-- | old/solve_old.h | 9 | ||||
| -rw-r--r-- | src/alg.c | 127 | ||||
| -rw-r--r-- | src/alg.h | 76 | ||||
| -rw-r--r-- | src/commands.c | 18 | ||||
| -rw-r--r-- | src/commands.h | 9 | ||||
| -rw-r--r-- | src/cubetypes.h | 36 | ||||
| -rw-r--r-- | src/movesets.c | 194 | ||||
| -rw-r--r-- | src/movesets.h | 15 | ||||
| -rw-r--r-- | src/pruning.h | 1 | ||||
| -rw-r--r-- | src/solve.c | 513 | ||||
| -rw-r--r-- | src/solve.h | 50 | ||||
| -rw-r--r-- | src/solver_step.c | 296 | ||||
| -rw-r--r-- | src/solver_step.h | 12 | ||||
| -rw-r--r-- | src/steps.c | 14 | ||||
| -rw-r--r-- | src/steps.h | 5 | ||||
| -rw-r--r-- | src/threader_eager.c | 162 | ||||
| -rw-r--r-- | src/threader_eager.h | 8 | ||||
| -rw-r--r-- | src/threader_single.c | 35 | ||||
| -rw-r--r-- | src/threader_single.h | 8 | ||||
| -rw-r--r-- | tests/alg_tests.h | 1 |
24 files changed, 1436 insertions, 700 deletions
diff --git a/TODO/2.1.md b/TODO/2.1.md index d65eb93..7448094 100644 --- a/TODO/2.1.md +++ b/TODO/2.1.md | |||
| @@ -1,89 +1,33 @@ | |||
| 1 | # TODO-list for version 2.1 (or is it 3.0 at this point?) | 1 | # TODO-list for version 2.1 (or is it 3.0 at this point?) |
| 2 | 2 | ||
| 3 | ## Alg and moveset changes (prerequisite for solve.h) | ||
| 4 | |||
| 5 | ### moveset.h | ||
| 6 | * split off from alg.h | ||
| 7 | |||
| 8 | ### alg.h | ||
| 9 | * There is a (future) bug in the way the solver checks if a move can | ||
| 10 | be appended (allowed_next and similar): the last two moves are not enough. | ||
| 11 | * Example: using QTM we have last 3 moves U U D. Considering only last 2, | ||
| 12 | U could be appended, but it cannot (cancel to U'). | ||
| 13 | * Solution: the per-moveset bool allowed_next() should take an alg as | ||
| 14 | parameter. There are going to be basically two versions, one for QTM and | ||
| 15 | one for HTM (but more may be added). | ||
| 16 | * Alg should be extended to remember the list of moves on inverse / normal | ||
| 17 | separately (without looping over moves). | ||
| 18 | * Maybe another parameter to know if it can assume there has not been | ||
| 19 | any double switching, i.e. if the last moves are the only ones to | ||
| 20 | be checked and there is no need to go back further (e.g. if alg is | ||
| 21 | U (... stuff on inverse ...) D I don't want to have to check back | ||
| 22 | to the U, but in practice we can often assume this does not happen). | ||
| 23 | * Then we can remove last and lastinv from dfsdata. | ||
| 24 | * move also can_niss to alg.h | ||
| 25 | * the check for the order of the moves (to avoid counting L R and R L as | ||
| 26 | different) can be made separately. Maybe add a "compare" function for moves, | ||
| 27 | such that non-commuting moves are not comparable (return -1 0 1). | ||
| 28 | |||
| 29 | ## Rework solver | 3 | ## Rework solver |
| 30 | 4 | ||
| 31 | * The architecture is the following: solve.h contains a solve() public | 5 | ### 1. Implement minimum viable |
| 32 | function that takes as parameters a set of solver methods (see below) | 6 | |
| 33 | and a thread manager (basically, multithreaded or single threaded). | 7 | * Implement nxopt31 with fst_cube. Remember that the function |
| 34 | It also has a dfs() public function with the same parameters. | 8 | move_check_solved() should do one axis at the time, so that we don't move |
| 35 | * The solve() function, looping over the allowed depths, calls | 9 | everything before checking. |
| 36 | the dispatcher provided by the thread manager, which takes care of | 10 | * test? |
| 37 | instantiating the threads. Each thread calls back to dfs(). The | ||
| 38 | thread manager then takes case of re-assembling the solutions, and | ||
| 39 | finally returns a list of solutions for the given depth. | ||
| 40 | * The specifics of how dfs() works are implemented in a specific solver | ||
| 41 | module. | ||
| 42 | 11 | ||
| 43 | ### solve.h | 12 | ### 2. Rework achitecture and file dependencies |
| 44 | 13 | ||
| 45 | * Interface: define solve(), dfs() and the types dfsdata, solvermethods and | 14 | * solve.h depends only on moves(alg?) (dependency on step and trans is removed). |
| 46 | threadmanager. solve.h is included by specific thread managers and solvers. | 15 | * Other modules have changed dependencies, might as well rework all. |
| 47 | * DfsData: remove Cube *, Movable, Step and extra. Add Void * (containing | 16 | * Make files smaller, do not include definition in .h, separate |
| 48 | either cube, indexes or whatnot) and a moveset (extracted from step, | 17 | data from abstract operations. |
| 49 | necessary). Maybe cleanup solveoptions too (e.g. threads not necessary). | 18 | * remove cubetypes.h |
| 50 | * solve.h depends only on moves (dependency on step and trans is removed). | 19 | * Create a module for multi-step (maybe wait?) |
| 51 | * preparation step should be reworked, maybe removed or delegated to the | 20 | * Possible changes: in step solver, copy cube only if niss; add cleanup function |
| 52 | specific implementations. | 21 | in solver (called by solve()) to free cube and perhaps pruning tables. |
| 53 | * All dfs stuff in the same function. Maybe remove also solvestop. | 22 | * see various TODO's in files |
| 54 | * Move two-step solve to a different module | ||
| 55 | 23 | ||
| 56 | ### Specific thread managers | 24 | ### 4. More threading options |
| 57 | 25 | ||
| 58 | * Single thread. Useful in low-resources environments or when solving multiple | ||
| 59 | scrambles at the same time, or simply when asked to solve with one thread. | ||
| 60 | * Lazy multithread: threads are as independent as possible and only | 26 | * Lazy multithread: threads are as independent as possible and only |
| 61 | merged at the end. Ideal when all solutions of a certain length are requested. | 27 | merged at the end. Ideal when all solutions of a certain length are requested. |
| 62 | * Eager multithread: current implementation, branches communicate the number | 28 | * (Done) Eager multithread: current implementation, branches communicate the |
| 63 | and list of solutions to stop as soon as possible. Good when only one solution | 29 | number and list of solutions to stop as soon as possible. Good when only one |
| 64 | of a certain depth is required. | 30 | solution of a certain depth is required. |
| 65 | |||
| 66 | ### Solver methods | ||
| 67 | |||
| 68 | * bool move_check_stop(DfsArg *, Move): applies the given move (possibly | ||
| 69 | recovered from DfsData, but we avoid checking for niss by passing it | ||
| 70 | directly) and at the same time checks if the branch should be pruned. Not | ||
| 71 | elegant, but it is much more efficient to do the two things at the same time | ||
| 72 | (e.g. when moving a fst_cube we can move one "orientation" at the time, check | ||
| 73 | the pruning table and stop if possible). | ||
| 74 | * void add_solution(DfsArg *, ThreadManager): add the solution to the list. | ||
| 75 | Also checks if the solution is valid / acceptable (e.g. EO does not finish | ||
| 76 | with F' instead of F and such) and cleans it up (rotation, cleanup, unniss). | ||
| 77 | * void copy(void * src, void * dst): copy the cube-part of dfs_data. To be | ||
| 78 | called by copy_dfsdata, which remains in solve.h (but merged into dfs). | ||
| 79 | * void * invert_cube(void *): in preparation for niss. | ||
| 80 | * bool niss_makes_sense(DfsArg *): maybe can be done generically in solve.h? | ||
| 81 | |||
| 82 | ## New optimal solver (use fst) | ||
| 83 | |||
| 84 | * Implement nxopt31 with fst_cube. Remember that the function | ||
| 85 | move_check_solved() should do one axis at the time, so that we don't move | ||
| 86 | everything before checking. | ||
| 87 | 31 | ||
| 88 | ## Simplify steps | 32 | ## Simplify steps |
| 89 | 33 | ||
diff --git a/TODO/new-feature-ideas.md b/TODO/new-feature-ideas.md index b619e36..067d440 100644 --- a/TODO/new-feature-ideas.md +++ b/TODO/new-feature-ideas.md | |||
| @@ -22,9 +22,11 @@ get its own file and more details. | |||
| 22 | * Optimal solver: when asking only for one solution, scan for upper bound in | 22 | * Optimal solver: when asking only for one solution, scan for upper bound in |
| 23 | parallel using a non-optimal (but fast) solver (e.g. twophase). | 23 | parallel using a non-optimal (but fast) solver (e.g. twophase). |
| 24 | * Optimal solver: up to a small bound, try with a small pruning table. | 24 | * Optimal solver: up to a small bound, try with a small pruning table. |
| 25 | * Optimal solver: start at different depths in parallel | ||
| 25 | * Multi-step solver: make more general | 26 | * Multi-step solver: make more general |
| 26 | 27 | ||
| 27 | ## New features | 28 | ## New features |
| 28 | 29 | ||
| 30 | * Allow user to specify moveset manually (see issue \#5 on github) | ||
| 29 | * EO analysis (and also DR and HTR analysis): group similar EOs (Jay) | 31 | * EO analysis (and also DR and HTR analysis): group similar EOs (Jay) |
| 30 | * HTR "maze" analysis? | 32 | * HTR "maze" analysis? |
diff --git a/TODO/refactoring.md b/TODO/refactoring.md index 206b402..eedbd20 100644 --- a/TODO/refactoring.md +++ b/TODO/refactoring.md | |||
| @@ -25,6 +25,4 @@ | |||
| 25 | * Sort function implementations alphabetically, ignore static vs non static. | 25 | * Sort function implementations alphabetically, ignore static vs non static. |
| 26 | * Rename functions and variable to have a consistent naming scheme. | 26 | * Rename functions and variable to have a consistent naming scheme. |
| 27 | * Functions that copy data: swap src and dest, follow memcpy standard. | 27 | * Functions that copy data: swap src and dest, follow memcpy standard. |
| 28 | * The way coord uses define guards to organize the .h file is good, apply it | ||
| 29 | to other modules too - including tests. | ||
| 30 | * Read style(9) and decide what to implement. | 28 | * Read style(9) and decide what to implement. |
diff --git a/old/solve_old.c b/old/solve_old.c new file mode 100644 index 0000000..8662c9e --- /dev/null +++ b/old/solve_old.c | |||
| @@ -0,0 +1,447 @@ | |||
| 1 | #define SOLVE_C | ||
| 2 | |||
| 3 | #include "solve.h" | ||
| 4 | |||
| 5 | /* Local functions ***********************************************************/ | ||
| 6 | |||
| 7 | static void copy_dfsarg(DfsArg *src, DfsArg *dst); | ||
| 8 | static void dfs(DfsArg *arg); | ||
| 9 | static void dfs_add_sol(DfsArg *arg); | ||
| 10 | static void dfs_niss(DfsArg *arg); | ||
| 11 | static bool dfs_move_checkstop(DfsArg *arg); | ||
| 12 | static void * instance_thread(void *arg); | ||
| 13 | static void multidfs(DfsArg *arg); | ||
| 14 | static bool niss_makes_sense(DfsArg *arg); | ||
| 15 | static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols); | ||
| 16 | |||
| 17 | /* Local functions ***********************************************************/ | ||
| 18 | |||
| 19 | static void | ||
| 20 | copy_dfsarg(DfsArg *src, DfsArg *dst) | ||
| 21 | { | ||
| 22 | int i; | ||
| 23 | |||
| 24 | dst->cube = src->cube; | ||
| 25 | dst->t = src->t; | ||
| 26 | dst->s = src->s; | ||
| 27 | dst->opts = src->opts; | ||
| 28 | dst->d = src->d; | ||
| 29 | dst->bound = src->bound; /* In theory not needed */ | ||
| 30 | dst->niss = src->niss; | ||
| 31 | dst->sols = src->sols; | ||
| 32 | dst->sols_mutex = src->sols_mutex; | ||
| 33 | dst->current_alg = src->current_alg; | ||
| 34 | |||
| 35 | for (i = 0; i < src->s->n_coord; i++) { | ||
| 36 | dst->ind[i].val = src->ind[i].val; | ||
| 37 | dst->ind[i].t = src->ind[i].t; | ||
| 38 | } | ||
| 39 | |||
| 40 | src->s->copy_extra(src, dst); | ||
| 41 | } | ||
| 42 | |||
| 43 | static void | ||
| 44 | dfs(DfsArg *arg) | ||
| 45 | { | ||
| 46 | int i; | ||
| 47 | Move m, l0, l1; | ||
| 48 | DfsArg newarg; | ||
| 49 | |||
| 50 | if (dfs_move_checkstop(arg)) | ||
| 51 | return; | ||
| 52 | |||
| 53 | if (arg->bound == 0) { | ||
| 54 | if (arg->current_alg->len == arg->d) | ||
| 55 | dfs_add_sol(arg); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 60 | m = arg->s->moveset->sorted_moves[i]; | ||
| 61 | if (arg->s->moveset->can_append(arg->current_alg, m, arg->niss) | ||
| 62 | && compare_last(arg->current_alg, m, arg->niss) >= 0) { | ||
| 63 | copy_dfsarg(arg, &newarg); | ||
| 64 | append_move(arg->current_alg, m, newarg.niss); | ||
| 65 | dfs(&newarg); | ||
| 66 | remove_last_move(arg->current_alg); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | if (niss_makes_sense(arg)) | ||
| 71 | dfs_niss(arg); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void | ||
| 75 | dfs_add_sol(DfsArg *arg) | ||
| 76 | { | ||
| 77 | bool valid, accepted, nisscanc; | ||
| 78 | |||
| 79 | valid = arg->s->is_valid==NULL || arg->s->is_valid(arg->current_alg); | ||
| 80 | accepted = valid || arg->opts->all; | ||
| 81 | nisscanc = arg->s->final && | ||
| 82 | arg->s->moveset->cancel_niss(arg->current_alg); | ||
| 83 | |||
| 84 | if (accepted && !nisscanc) { | ||
| 85 | pthread_mutex_lock(arg->sols_mutex); | ||
| 86 | |||
| 87 | if (arg->sols->len < arg->opts->max_solutions) { | ||
| 88 | append_alg(arg->sols, arg->current_alg); | ||
| 89 | transform_alg( | ||
| 90 | inverse_trans(arg->t), arg->sols->last->alg); | ||
| 91 | if (arg->opts->verbose) | ||
| 92 | print_alg(arg->sols->last->alg, false); | ||
| 93 | } | ||
| 94 | |||
| 95 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | static void | ||
| 100 | dfs_niss(DfsArg *arg) | ||
| 101 | { | ||
| 102 | DfsArg newarg; | ||
| 103 | Alg *inv; | ||
| 104 | Cube *c; | ||
| 105 | |||
| 106 | copy_dfsarg(arg, &newarg); | ||
| 107 | |||
| 108 | /* Invert current alg and scramble */ | ||
| 109 | newarg.cube = malloc(sizeof(Cube)); | ||
| 110 | inv = inverse_alg(arg->current_alg); | ||
| 111 | c = malloc(sizeof(Cube)); | ||
| 112 | make_solved(newarg.cube); | ||
| 113 | apply_alg(inv, newarg.cube); | ||
| 114 | copy_cube(arg->cube, c); | ||
| 115 | invert_cube(c); | ||
| 116 | compose(c, newarg.cube); | ||
| 117 | |||
| 118 | /* New indexes */ | ||
| 119 | compute_ind(newarg.s, newarg.cube, newarg.ind); | ||
| 120 | |||
| 121 | newarg.niss = !(arg->niss); | ||
| 122 | |||
| 123 | dfs(&newarg); | ||
| 124 | |||
| 125 | free_alg(inv); | ||
| 126 | free(c); | ||
| 127 | free(newarg.cube); | ||
| 128 | } | ||
| 129 | |||
| 130 | static bool | ||
| 131 | dfs_move_checkstop(DfsArg *arg) | ||
| 132 | { | ||
| 133 | int i, goal, nsols; | ||
| 134 | Move mm; | ||
| 135 | Trans tt = uf; /* Avoid uninitialized warning */ | ||
| 136 | |||
| 137 | /* Moving and computing bound */ | ||
| 138 | arg->bound = 0; | ||
| 139 | goal = arg->d - arg->current_alg->len; | ||
| 140 | for (i = 0; i < arg->s->n_coord; i++) { | ||
| 141 | if (arg->last[0] != NULLMOVE) { | ||
| 142 | mm = transform_move(arg->ind[i].t, arg->last[0]); | ||
| 143 | arg->ind[i].val = move_coord(arg->s->coord[i], | ||
| 144 | mm, arg->ind[i].val, &tt); | ||
| 145 | arg->ind[i].t = transform_trans(tt, arg->ind[i].t); | ||
| 146 | } | ||
| 147 | |||
| 148 | arg->bound = | ||
| 149 | MAX(arg->bound, ptableval(arg->s->pd[i], arg->ind[i].val)); | ||
| 150 | if (arg->opts->can_niss && !arg->niss) | ||
| 151 | arg->bound = MIN(1, arg->bound); | ||
| 152 | |||
| 153 | if (arg->bound > goal) | ||
| 154 | return true; | ||
| 155 | } | ||
| 156 | |||
| 157 | pthread_mutex_lock(arg->sols_mutex); | ||
| 158 | nsols = arg->sols->len; | ||
| 159 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 160 | |||
| 161 | return nsols >= arg->opts->max_solutions; | ||
| 162 | } | ||
| 163 | |||
| 164 | static void * | ||
| 165 | instance_thread(void *arg) | ||
| 166 | { | ||
| 167 | bool b, inv; | ||
| 168 | Cube c; | ||
| 169 | Move m; | ||
| 170 | ThreadDataSolve *td; | ||
| 171 | AlgListNode *node; | ||
| 172 | DfsArg darg; | ||
| 173 | |||
| 174 | td = (ThreadDataSolve *)arg; | ||
| 175 | |||
| 176 | while (1) { | ||
| 177 | b = false; | ||
| 178 | |||
| 179 | pthread_mutex_lock(td->start_mutex); | ||
| 180 | if ((node = *(td->node)) == NULL) | ||
| 181 | b = true; | ||
| 182 | else | ||
| 183 | *(td->node) = (*(td->node))->next; | ||
| 184 | pthread_mutex_unlock(td->start_mutex); | ||
| 185 | |||
| 186 | if (b) | ||
| 187 | break; | ||
| 188 | |||
| 189 | inv = node->alg->inv[0]; | ||
| 190 | m = node->alg->move[0]; | ||
| 191 | |||
| 192 | copy_cube(td->arg.cube, &c); | ||
| 193 | if (inv) | ||
| 194 | invert_cube(&c); | ||
| 195 | |||
| 196 | copy_dfsarg(&td->arg, &darg); | ||
| 197 | compute_ind(td->arg.s, &c, darg.ind); | ||
| 198 | darg.cube = &c; | ||
| 199 | |||
| 200 | darg.niss = inv; | ||
| 201 | darg.current_alg = new_alg(""); | ||
| 202 | append_move(darg.current_alg, m, inv); | ||
| 203 | |||
| 204 | dfs(&darg); | ||
| 205 | |||
| 206 | free_alg(darg.current_alg); | ||
| 207 | } | ||
| 208 | |||
| 209 | return NULL; | ||
| 210 | } | ||
| 211 | |||
| 212 | static void | ||
| 213 | multidfs(DfsArg *arg) | ||
| 214 | { | ||
| 215 | int i; | ||
| 216 | Cube local_cube; | ||
| 217 | Alg *alg; | ||
| 218 | AlgList *start; | ||
| 219 | AlgListNode **node; | ||
| 220 | pthread_t t[arg->opts->nthreads]; | ||
| 221 | ThreadDataSolve td[arg->opts->nthreads]; | ||
| 222 | pthread_mutex_t *start_mutex, *sols_mutex; | ||
| 223 | |||
| 224 | node = malloc(sizeof(AlgListNode *)); | ||
| 225 | start_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 226 | sols_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 227 | |||
| 228 | start = new_alglist(); | ||
| 229 | pthread_mutex_init(start_mutex, NULL); | ||
| 230 | pthread_mutex_init(sols_mutex, NULL); | ||
| 231 | |||
| 232 | for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 233 | alg = new_alg(""); | ||
| 234 | append_move(alg, arg->s->moveset->sorted_moves[i], false); | ||
| 235 | append_alg(start, alg); | ||
| 236 | if (arg->opts->can_niss && !arg->s->final) { | ||
| 237 | alg->inv[0] = true; | ||
| 238 | append_alg(start, alg); | ||
| 239 | } | ||
| 240 | free_alg(alg); | ||
| 241 | } | ||
| 242 | *node = start->first; | ||
| 243 | |||
| 244 | copy_cube(arg->cube, &local_cube); | ||
| 245 | |||
| 246 | for (i = 0; i < arg->opts->nthreads; i++) { | ||
| 247 | copy_dfsarg(arg, &(td[i].arg)); | ||
| 248 | td[i].arg.cube = &local_cube; | ||
| 249 | td[i].arg.sols_mutex = sols_mutex; | ||
| 250 | |||
| 251 | td[i].thid = i; | ||
| 252 | td[i].start = start; | ||
| 253 | td[i].node = node; | ||
| 254 | td[i].start_mutex = start_mutex; | ||
| 255 | |||
| 256 | pthread_create(&t[i], NULL, instance_thread, &td[i]); | ||
| 257 | } | ||
| 258 | |||
| 259 | for (i = 0; i < arg->opts->nthreads; i++) | ||
| 260 | pthread_join(t[i], NULL); | ||
| 261 | |||
| 262 | free_alglist(start); | ||
| 263 | free(node); | ||
| 264 | free(start_mutex); | ||
| 265 | free(sols_mutex); | ||
| 266 | } | ||
| 267 | |||
| 268 | static bool | ||
| 269 | niss_makes_sense(DfsArg *arg) | ||
| 270 | { | ||
| 271 | Move m, mm; | ||
| 272 | uint64_t u; | ||
| 273 | int i; | ||
| 274 | |||
| 275 | if (arg->s->final || arg->niss || !arg->opts->can_niss) | ||
| 276 | return false; | ||
| 277 | |||
| 278 | if (arg->current_alg->len_normal == 0) | ||
| 279 | return true; | ||
| 280 | |||
| 281 | m = inverse_move(arg->last[0]); | ||
| 282 | for (i = 0; i < arg->s->n_coord; i++) { | ||
| 283 | mm = transform_move(arg->ind[i].t, m); | ||
| 284 | u = move_coord(arg->s->coord[i], mm, 0, NULL); | ||
| 285 | if (ptableval(arg->s->pd[i], u) > 0) | ||
| 286 | return true; | ||
| 287 | } | ||
| 288 | |||
| 289 | return false; | ||
| 290 | } | ||
| 291 | |||
| 292 | static bool | ||
| 293 | solvestop(int d, int op, SolveOptions *opts, AlgList *sols) | ||
| 294 | { | ||
| 295 | bool opt_done, max_moves_exceeded, max_sols_exceeded; | ||
| 296 | |||
| 297 | opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op; | ||
| 298 | max_moves_exceeded = d > opts->max_moves; | ||
| 299 | max_sols_exceeded = sols->len >= opts->max_solutions; | ||
| 300 | |||
| 301 | return opt_done || max_moves_exceeded || max_sols_exceeded; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* Public functions **********************************************************/ | ||
| 305 | |||
| 306 | AlgList * | ||
| 307 | solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts) | ||
| 308 | { | ||
| 309 | int i, j, d, op, est; | ||
| 310 | bool ready[99], one_ready, zerosol; | ||
| 311 | Movable ind[99][10]; | ||
| 312 | AlgList *s; | ||
| 313 | Cube *c[99]; | ||
| 314 | DfsArg arg[99]; | ||
| 315 | |||
| 316 | prepare_cs(cs, opts); | ||
| 317 | s = new_alglist(); | ||
| 318 | |||
| 319 | for (i = 0, one_ready = false; cs->step[i] != NULL; i++) { | ||
| 320 | c[i] = malloc(sizeof(Cube)); | ||
| 321 | copy_cube(cube, c[i]); | ||
| 322 | apply_trans(cs->t[i], c[i]); | ||
| 323 | |||
| 324 | arg[i].cube = c[i]; | ||
| 325 | arg[i].t = cs->t[i]; | ||
| 326 | arg[i].s = cs->step[i]; | ||
| 327 | arg[i].opts = opts; | ||
| 328 | arg[i].sols = s; | ||
| 329 | |||
| 330 | if ((ready[i] = cs->step[i]->ready(c[i]))) { | ||
| 331 | one_ready = true; | ||
| 332 | /* Only for local use for 0 moves solutions */ | ||
| 333 | compute_ind(cs->step[i], c[i], ind[i]); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | if (!one_ready) { | ||
| 337 | fprintf(stderr, "Cube not ready for solving step: "); | ||
| 338 | fprintf(stderr, "%s\n", cs->ready_msg); | ||
| 339 | return s; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* If the empty moves sequence is a solution for one of the | ||
| 343 | * alternatives, all longer solutions will be discarded, so we may | ||
| 344 | * just set its ready[] value to false. If the solution is accepted | ||
| 345 | * we append it and start searching from d = 1. */ | ||
| 346 | for (i = 0, zerosol = false; cs->step[i] != NULL; i++) { | ||
| 347 | if (ready[i]) { | ||
| 348 | est = 0; | ||
| 349 | for (j = 0; j < cs->step[i]->n_coord; j++) | ||
| 350 | est = MAX(est, ptableval(cs->step[i]->pd[j], | ||
| 351 | ind[i][j].val)); | ||
| 352 | if (est == 0) { | ||
| 353 | ready[i] = false; | ||
| 354 | zerosol = true; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | } | ||
| 358 | if (zerosol && opts->min_moves == 0) { | ||
| 359 | append_alg(s, new_alg("")); | ||
| 360 | opts->min_moves = 1; | ||
| 361 | if (opts->verbose) | ||
| 362 | printf("Step is already solved" | ||
| 363 | "(empty alg is a solution)\n"); | ||
| 364 | } | ||
| 365 | |||
| 366 | for (d = opts->min_moves, op = -1; !solvestop(d, op, opts, s); d++) { | ||
| 367 | if (opts->verbose) | ||
| 368 | fprintf(stderr, "Searching depth %d\n", d); | ||
| 369 | |||
| 370 | for (i=0; cs->step[i]!=NULL && !solvestop(d,op,opts,s); i++) { | ||
| 371 | if (!ready[i]) | ||
| 372 | continue; | ||
| 373 | |||
| 374 | arg[i].d = d; | ||
| 375 | multidfs(&arg[i]); | ||
| 376 | |||
| 377 | if (s->len > 0 && op == -1) | ||
| 378 | op = d; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | for (i = 0; cs->step[i] != NULL; i++) | ||
| 383 | free(c[i]); | ||
| 384 | |||
| 385 | return s; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* TODO: make more general! */ | ||
| 389 | Alg * | ||
| 390 | solve_2phase(Cube *cube, int nthreads) | ||
| 391 | { | ||
| 392 | int bestlen, newb; | ||
| 393 | Alg *bestalg, *ret; | ||
| 394 | AlgList *sols1, *sols2; | ||
| 395 | AlgListNode *i; | ||
| 396 | Cube c; | ||
| 397 | SolveOptions opts1, opts2; | ||
| 398 | |||
| 399 | opts1.min_moves = 0; | ||
| 400 | opts1.max_moves = 13; | ||
| 401 | opts1.max_solutions = 20; | ||
| 402 | opts1.nthreads = nthreads; | ||
| 403 | opts1.optimal = 3; | ||
| 404 | opts1.can_niss = false; | ||
| 405 | opts1.verbose = false; | ||
| 406 | opts1.all = true; | ||
| 407 | |||
| 408 | opts2.min_moves = 0; | ||
| 409 | opts2.max_moves = 19; | ||
| 410 | opts2.max_solutions = 1; | ||
| 411 | opts2.nthreads = nthreads; | ||
| 412 | opts2.can_niss = false; | ||
| 413 | opts2.verbose = false; | ||
| 414 | |||
| 415 | /* We skip step1 if it is solved on U/D */ | ||
| 416 | if (check_drud(cube)) { | ||
| 417 | sols1 = new_alglist(); | ||
| 418 | append_alg(sols1, new_alg("")); | ||
| 419 | } else { | ||
| 420 | sols1 = solve(cube, &drud_HTM, &opts1); | ||
| 421 | } | ||
| 422 | bestalg = new_alg(""); | ||
| 423 | bestlen = 999; | ||
| 424 | for (i = sols1->first; i != NULL; i = i->next) { | ||
| 425 | copy_cube(cube, &c); | ||
| 426 | apply_alg(i->alg, &c); | ||
| 427 | sols2 = solve(&c, &dranyfin_DR, &opts2); | ||
| 428 | |||
| 429 | if (sols2->len > 0) { | ||
| 430 | newb = i->alg->len + sols2->first->alg->len; | ||
| 431 | if (newb < bestlen) { | ||
| 432 | bestlen = newb; | ||
| 433 | copy_alg(i->alg, bestalg); | ||
| 434 | compose_alg(bestalg, sols2->first->alg); | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | free_alglist(sols2); | ||
| 439 | } | ||
| 440 | |||
| 441 | free_alglist(sols1); | ||
| 442 | |||
| 443 | ret = cleanup(bestalg); | ||
| 444 | free_alg(bestalg); | ||
| 445 | |||
| 446 | return ret; | ||
| 447 | } | ||
diff --git a/old/solve_old.h b/old/solve_old.h new file mode 100644 index 0000000..010389e --- /dev/null +++ b/old/solve_old.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #ifndef SOLVE_H | ||
| 2 | #define SOLVE_H | ||
| 3 | |||
| 4 | #include "movesets.h" | ||
| 5 | |||
| 6 | AlgList * solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts); | ||
| 7 | Alg * solve_2phase(Cube *cube, int nthreads); | ||
| 8 | |||
| 9 | #endif | ||
| @@ -6,57 +6,6 @@ static int axis(Move m); | |||
| 6 | static void free_alglistnode(AlgListNode *aln); | 6 | static void free_alglistnode(AlgListNode *aln); |
| 7 | static void realloc_alg(Alg *alg, int n); | 7 | static void realloc_alg(Alg *alg, int n); |
| 8 | 8 | ||
| 9 | bool | ||
| 10 | allowed_HTM(Move m) | ||
| 11 | { | ||
| 12 | return m >= U && m <= B3; | ||
| 13 | } | ||
| 14 | |||
| 15 | bool | ||
| 16 | allowed_URF(Move m) | ||
| 17 | { | ||
| 18 | Move b = base_move(m); | ||
| 19 | |||
| 20 | return b == U || b == R || b == F; | ||
| 21 | } | ||
| 22 | |||
| 23 | bool | ||
| 24 | allowed_eofb(Move m) | ||
| 25 | { | ||
| 26 | Move b = base_move(m); | ||
| 27 | |||
| 28 | return b == U || b == D || b == R || b == L || | ||
| 29 | ((b == F || b == B) && m == b+1); | ||
| 30 | } | ||
| 31 | |||
| 32 | bool | ||
| 33 | allowed_drud(Move m) | ||
| 34 | { | ||
| 35 | Move b = base_move(m); | ||
| 36 | |||
| 37 | return b == U || b == D || | ||
| 38 | ((b == R || b == L || b == F || b == B) && m == b + 1); | ||
| 39 | } | ||
| 40 | |||
| 41 | bool | ||
| 42 | allowed_htr(Move m) | ||
| 43 | { | ||
| 44 | Move b = base_move(m); | ||
| 45 | |||
| 46 | return moveset_HTM.allowed(m) && m == b + 1; | ||
| 47 | } | ||
| 48 | |||
| 49 | bool | ||
| 50 | allowed_next_all(Move l2, Move l1, Move m) | ||
| 51 | { | ||
| 52 | bool p, q; | ||
| 53 | |||
| 54 | p = l1 != NULLMOVE && base_move(l1) == base_move(m); | ||
| 55 | q = l2 != NULLMOVE && base_move(l2) == base_move(m); | ||
| 56 | |||
| 57 | return !(p || (commute(l1, l2) && q)); | ||
| 58 | } | ||
| 59 | |||
| 60 | void | 9 | void |
| 61 | append_alg(AlgList *l, Alg *alg) | 10 | append_alg(AlgList *l, Alg *alg) |
| 62 | { | 11 | { |
| @@ -137,6 +86,32 @@ commute(Move m1, Move m2) | |||
| 137 | return axis(m1) == axis(m2); | 86 | return axis(m1) == axis(m2); |
| 138 | } | 87 | } |
| 139 | 88 | ||
| 89 | int | ||
| 90 | compare(Move m1, Move m2) | ||
| 91 | { | ||
| 92 | if (!commute(m1, m2)) | ||
| 93 | return 0; | ||
| 94 | |||
| 95 | return m1 < m2 ? 1 : -1; | ||
| 96 | } | ||
| 97 | |||
| 98 | int | ||
| 99 | compare_last(Alg *alg, Move m, bool inverse) | ||
| 100 | { | ||
| 101 | Move last; | ||
| 102 | int n; | ||
| 103 | |||
| 104 | if (inverse) { | ||
| 105 | n = alg->len_inverse; | ||
| 106 | last = n > 0 ? alg->move_inverse[n-1] : NULLMOVE; | ||
| 107 | } else { | ||
| 108 | n = alg->len_normal; | ||
| 109 | last = n > 0 ? alg->move_normal[n-1] : NULLMOVE; | ||
| 110 | } | ||
| 111 | |||
| 112 | return compare(last, m); | ||
| 113 | } | ||
| 114 | |||
| 140 | void | 115 | void |
| 141 | compose_alg(Alg *alg1, Alg *alg2) | 116 | compose_alg(Alg *alg1, Alg *alg2) |
| 142 | { | 117 | { |
| @@ -355,19 +330,6 @@ on_inverse(Alg *alg) | |||
| 355 | return ret; | 330 | return ret; |
| 356 | } | 331 | } |
| 357 | 332 | ||
| 358 | bool | ||
| 359 | possible_next(Move m, Moveset *ms, Move l0, Move l1) | ||
| 360 | { | ||
| 361 | bool allowed, order; | ||
| 362 | uint64_t mbit; | ||
| 363 | |||
| 364 | mbit = ((uint64_t)1) << m; | ||
| 365 | allowed = mbit & ms->mask[l1][l0]; | ||
| 366 | order = !commute(l0, m) || l0 < m; | ||
| 367 | |||
| 368 | return allowed && order; | ||
| 369 | } | ||
| 370 | |||
| 371 | void | 333 | void |
| 372 | print_alg(Alg *alg, bool l) | 334 | print_alg(Alg *alg, bool l) |
| 373 | { | 335 | { |
| @@ -431,6 +393,17 @@ realloc_alg(Alg *alg, int n) | |||
| 431 | } | 393 | } |
| 432 | 394 | ||
| 433 | void | 395 | void |
| 396 | remove_last_move(Alg *a) | ||
| 397 | { | ||
| 398 | a->len--; | ||
| 399 | |||
| 400 | if (a->inv[a->len]) | ||
| 401 | a->len_inverse--; | ||
| 402 | else | ||
| 403 | a->len_normal--; | ||
| 404 | } | ||
| 405 | |||
| 406 | void | ||
| 434 | swapmove(Move *m1, Move *m2) | 407 | swapmove(Move *m1, Move *m2) |
| 435 | { | 408 | { |
| 436 | Move aux; | 409 | Move aux; |
| @@ -484,29 +457,3 @@ unniss(Alg *alg) | |||
| 484 | 457 | ||
| 485 | return ret; | 458 | return ret; |
| 486 | } | 459 | } |
| 487 | |||
| 488 | void | ||
| 489 | init_moveset(Moveset *ms) | ||
| 490 | { | ||
| 491 | int j; | ||
| 492 | uint64_t l, one; | ||
| 493 | Move m, l2, l1; | ||
| 494 | |||
| 495 | one = 1; | ||
| 496 | |||
| 497 | for (j = 0, m = U; m < NMOVES; m++) | ||
| 498 | if (ms->allowed(m)) | ||
| 499 | ms->sorted_moves[j++] = m; | ||
| 500 | ms->sorted_moves[j] = NULLMOVE; | ||
| 501 | |||
| 502 | for (l1 = 0; l1 < NMOVES; l1++) { | ||
| 503 | for (l2 = 0; l2 < NMOVES; l2++) { | ||
| 504 | ms->mask[l2][l1] = 0; | ||
| 505 | for (l = 0; ms->sorted_moves[l] != NULLMOVE; l++) { | ||
| 506 | m = ms->sorted_moves[l]; | ||
| 507 | if (ms->allowed_next(l2, l1, m)) | ||
| 508 | ms->mask[l2][l1] |= (one<<m); | ||
| 509 | } | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | ||
| @@ -8,21 +8,11 @@ | |||
| 8 | #include "cubetypes.h" | 8 | #include "cubetypes.h" |
| 9 | #include "utils.h" | 9 | #include "utils.h" |
| 10 | 10 | ||
| 11 | bool allowed_all(Move m); | ||
| 12 | bool allowed_HTM(Move m); | ||
| 13 | bool allowed_URF(Move m); | ||
| 14 | bool allowed_eofb(Move m); | ||
| 15 | bool allowed_drud(Move m); | ||
| 16 | bool allowed_htr(Move m); | ||
| 17 | bool allowed_next_all(Move l2, Move l1, Move m); | ||
| 18 | |||
| 19 | void moveset_to_list(Moveset ms, Move *lst); | ||
| 20 | void init_moveset(Moveset *ms); | ||
| 21 | bool possible_next(Move m, Moveset *ms, Move l0, Move l1); | ||
| 22 | |||
| 23 | void append_alg(AlgList *l, Alg *alg); | 11 | void append_alg(AlgList *l, Alg *alg); |
| 24 | void append_move(Alg *alg, Move m, bool inverse); | 12 | void append_move(Alg *alg, Move m, bool inverse); |
| 25 | Move base_move(Move m); | 13 | Move base_move(Move m); |
| 14 | int compare(Move m1, Move m2); /* Return 1 (m1<m2), 0 or -1 (m1>m2) */ | ||
| 15 | int compare_last(Alg *alg, Move m, bool inverse); | ||
| 26 | void compose_alg(Alg *alg1, Alg *alg2); | 16 | void compose_alg(Alg *alg1, Alg *alg2); |
| 27 | bool commute(Move m1, Move m2); | 17 | bool commute(Move m1, Move m2); |
| 28 | void copy_alg(Alg *src, Alg *dst); | 18 | void copy_alg(Alg *src, Alg *dst); |
| @@ -36,70 +26,10 @@ AlgList * new_alglist(); | |||
| 36 | Alg * on_inverse(Alg *alg); | 26 | Alg * on_inverse(Alg *alg); |
| 37 | void print_alg(Alg *alg, bool l); | 27 | void print_alg(Alg *alg, bool l); |
| 38 | void print_alglist(AlgList *al, bool l); | 28 | void print_alglist(AlgList *al, bool l); |
| 29 | void remove_last_move(Alg *alg); | ||
| 39 | void swapmove(Move *m1, Move *m2); | 30 | void swapmove(Move *m1, Move *m2); |
| 40 | char * trans_string(Trans t); /* Here because similar to move_string, move? */ | 31 | char * trans_string(Trans t); /* Here because similar to move_string, move? */ |
| 41 | Alg * unniss(Alg *alg); | 32 | Alg * unniss(Alg *alg); |
| 42 | 33 | ||
| 43 | /* Movesets ******************************************************************/ | ||
| 44 | |||
| 45 | #ifndef ALG_C | ||
| 46 | |||
| 47 | extern Moveset moveset_HTM; | ||
| 48 | extern Moveset moveset_URF; | ||
| 49 | extern Moveset moveset_eofb; | ||
| 50 | extern Moveset moveset_drud; | ||
| 51 | extern Moveset moveset_htr; | ||
| 52 | |||
| 53 | extern Moveset * all_ms[]; | ||
| 54 | |||
| 55 | #else | ||
| 56 | |||
| 57 | Moveset | ||
| 58 | moveset_HTM = { | ||
| 59 | .name = "HTM", | ||
| 60 | .allowed = allowed_HTM, | ||
| 61 | .allowed_next = allowed_next_all, | ||
| 62 | }; | ||
| 63 | |||
| 64 | Moveset | ||
| 65 | moveset_URF = { | ||
| 66 | .name = "URF", | ||
| 67 | .allowed = allowed_URF, | ||
| 68 | .allowed_next = allowed_next_all, | ||
| 69 | }; | ||
| 70 | |||
| 71 | Moveset | ||
| 72 | moveset_eofb = { | ||
| 73 | .name = "eofb", | ||
| 74 | .allowed = allowed_eofb, | ||
| 75 | .allowed_next = allowed_next_all, | ||
| 76 | }; | ||
| 77 | |||
| 78 | Moveset | ||
| 79 | moveset_drud = { | ||
| 80 | .name = "drud", | ||
| 81 | .allowed = allowed_drud, | ||
| 82 | .allowed_next = allowed_next_all, | ||
| 83 | }; | ||
| 84 | |||
| 85 | Moveset | ||
| 86 | moveset_htr = { | ||
| 87 | .name = "htr", | ||
| 88 | .allowed = allowed_htr, | ||
| 89 | .allowed_next = allowed_next_all, | ||
| 90 | }; | ||
| 91 | |||
| 92 | Moveset * | ||
| 93 | all_ms[] = { | ||
| 94 | &moveset_HTM, | ||
| 95 | &moveset_URF, | ||
| 96 | &moveset_eofb, | ||
| 97 | &moveset_drud, | ||
| 98 | &moveset_htr, | ||
| 99 | NULL | ||
| 100 | }; | ||
| 101 | |||
| 102 | #endif | ||
| 103 | |||
| 104 | #endif | 34 | #endif |
| 105 | 35 | ||
diff --git a/src/commands.c b/src/commands.c index 9ac1ae6..a9e8fc9 100644 --- a/src/commands.c +++ b/src/commands.c | |||
| @@ -215,10 +215,21 @@ solve_exec(CommandArgs *args) | |||
| 215 | { | 215 | { |
| 216 | Cube c; | 216 | Cube c; |
| 217 | AlgList *sols; | 217 | AlgList *sols; |
| 218 | Solver *solver[99]; | ||
| 219 | Threader *threader; | ||
| 218 | 220 | ||
| 219 | make_solved(&c); | 221 | make_solved(&c); |
| 220 | apply_alg(args->scramble, &c); | 222 | apply_alg(args->scramble, &c); |
| 221 | sols = solve(&c, args->cs, args->opts); | 223 | /* TODO: adjust */ |
| 224 | /* threader = &threader_single;*/ | ||
| 225 | threader = &threader_eager; | ||
| 226 | |||
| 227 | /* TODO: adjust */ | ||
| 228 | int i; | ||
| 229 | for (i = 0; args->cs->step[i] != NULL; i++) | ||
| 230 | solver[i] = new_stepsolver_lazy(args->cs->step[i]); | ||
| 231 | solver[i] = NULL; | ||
| 232 | sols = solve(&c, args->opts, solver, threader); | ||
| 222 | 233 | ||
| 223 | if (args->opts->count_only) | 234 | if (args->opts->count_only) |
| 224 | printf("%d\n", sols->len); | 235 | printf("%d\n", sols->len); |
| @@ -285,7 +296,10 @@ scramble_exec(CommandArgs *args) | |||
| 285 | } | 296 | } |
| 286 | 297 | ||
| 287 | /* TODO: can be optimized for htr and dr using htrfin, drfin */ | 298 | /* TODO: can be optimized for htr and dr using htrfin, drfin */ |
| 299 | /* | ||
| 300 | TODO: solve_2phase was removed | ||
| 288 | scr = solve_2phase(&cube, 1); | 301 | scr = solve_2phase(&cube, 1); |
| 302 | */ | ||
| 289 | 303 | ||
| 290 | if (!strcmp(args->scrtype, "fmc")) { | 304 | if (!strcmp(args->scrtype, "fmc")) { |
| 291 | aux = new_alg(""); | 305 | aux = new_alg(""); |
| @@ -383,6 +397,7 @@ print_exec(CommandArgs *args) | |||
| 383 | print_cube(&c); | 397 | print_cube(&c); |
| 384 | } | 398 | } |
| 385 | 399 | ||
| 400 | /* | ||
| 386 | void | 401 | void |
| 387 | twophase_exec(CommandArgs *args) | 402 | twophase_exec(CommandArgs *args) |
| 388 | { | 403 | { |
| @@ -396,6 +411,7 @@ twophase_exec(CommandArgs *args) | |||
| 396 | print_alg(sol, false); | 411 | print_alg(sol, false); |
| 397 | free_alg(sol); | 412 | free_alg(sol); |
| 398 | } | 413 | } |
| 414 | */ | ||
| 399 | 415 | ||
| 400 | void | 416 | void |
| 401 | help_exec(CommandArgs *args) | 417 | help_exec(CommandArgs *args) |
diff --git a/src/commands.h b/src/commands.h index 5d9f4ee..65708e0 100644 --- a/src/commands.h +++ b/src/commands.h | |||
| @@ -5,6 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | #include "solve.h" | 6 | #include "solve.h" |
| 7 | #include "steps.h" | 7 | #include "steps.h" |
| 8 | #include "solver_step.h" | ||
| 9 | #include "threader_single.h" | ||
| 10 | #include "threader_eager.h" | ||
| 8 | 11 | ||
| 9 | void free_args(CommandArgs *args); | 12 | void free_args(CommandArgs *args); |
| 10 | CommandArgs * new_args(); | 13 | CommandArgs * new_args(); |
| @@ -29,7 +32,7 @@ void steps_exec(CommandArgs *args); | |||
| 29 | void commands_exec(CommandArgs *args); | 32 | void commands_exec(CommandArgs *args); |
| 30 | void freemem_exec(CommandArgs *args); | 33 | void freemem_exec(CommandArgs *args); |
| 31 | void print_exec(CommandArgs *args); | 34 | void print_exec(CommandArgs *args); |
| 32 | void twophase_exec(CommandArgs *args); | 35 | /*void twophase_exec(CommandArgs *args);*/ |
| 33 | void help_exec(CommandArgs *args); | 36 | void help_exec(CommandArgs *args); |
| 34 | void quit_exec(CommandArgs *args); | 37 | void quit_exec(CommandArgs *args); |
| 35 | void unniss_exec(CommandArgs *args); | 38 | void unniss_exec(CommandArgs *args); |
| @@ -138,6 +141,7 @@ help_cmd = { | |||
| 138 | .exec = help_exec, | 141 | .exec = help_exec, |
| 139 | }; | 142 | }; |
| 140 | 143 | ||
| 144 | /* | ||
| 141 | Command | 145 | Command |
| 142 | twophase_cmd = { | 146 | twophase_cmd = { |
| 143 | .name = "twophase", | 147 | .name = "twophase", |
| @@ -146,6 +150,7 @@ twophase_cmd = { | |||
| 146 | .parse_args = parse_only_scramble, | 150 | .parse_args = parse_only_scramble, |
| 147 | .exec = twophase_exec, | 151 | .exec = twophase_exec, |
| 148 | }; | 152 | }; |
| 153 | */ | ||
| 149 | 154 | ||
| 150 | Command | 155 | Command |
| 151 | quit_cmd = { | 156 | quit_cmd = { |
| @@ -194,7 +199,7 @@ Command *commands[] = { | |||
| 194 | &solve_cmd, | 199 | &solve_cmd, |
| 195 | &scramble_cmd, | 200 | &scramble_cmd, |
| 196 | &steps_cmd, | 201 | &steps_cmd, |
| 197 | &twophase_cmd, | 202 | /* &twophase_cmd,*/ |
| 198 | &cleanup_cmd, | 203 | &cleanup_cmd, |
| 199 | &unniss_cmd, | 204 | &unniss_cmd, |
| 200 | &version_cmd, | 205 | &version_cmd, |
diff --git a/src/cubetypes.h b/src/cubetypes.h index 8d38904..3752019 100644 --- a/src/cubetypes.h +++ b/src/cubetypes.h | |||
| @@ -89,7 +89,7 @@ typedef struct command Command; | |||
| 89 | typedef struct commandargs CommandArgs; | 89 | typedef struct commandargs CommandArgs; |
| 90 | typedef struct coordinate Coordinate; | 90 | typedef struct coordinate Coordinate; |
| 91 | typedef struct cube Cube; | 91 | typedef struct cube Cube; |
| 92 | typedef struct dfsarg DfsArg; | 92 | /*typedef struct dfsarg DfsArg;*/ |
| 93 | typedef struct fstcube FstCube; | 93 | typedef struct fstcube FstCube; |
| 94 | typedef struct indexer Indexer; | 94 | typedef struct indexer Indexer; |
| 95 | typedef struct movable Movable; | 95 | typedef struct movable Movable; |
| @@ -104,9 +104,9 @@ typedef struct transgroup TransGroup; | |||
| 104 | 104 | ||
| 105 | typedef bool (*Checker) (Cube *); | 105 | typedef bool (*Checker) (Cube *); |
| 106 | typedef bool (*CubeTester) (Cube *, Alg *); | 106 | typedef bool (*CubeTester) (Cube *, Alg *); |
| 107 | typedef bool (*DfsMover) (DfsArg *); | 107 | /*typedef bool (*DfsMover) (DfsArg *);*/ |
| 108 | typedef void (*DfsExtraCopier) (void *, void *); | 108 | typedef void (*DfsExtraCopier) (void *, void *); |
| 109 | typedef bool (*Validator) (Alg *); | 109 | typedef Alg * (*Validator) (Alg *); |
| 110 | typedef void (*Exec) (CommandArgs *); | 110 | typedef void (*Exec) (CommandArgs *); |
| 111 | typedef CommandArgs * (*ArgParser) (int, char **); | 111 | typedef CommandArgs * (*ArgParser) (int, char **); |
| 112 | typedef bool (*Tester) (void); | 112 | typedef bool (*Tester) (void); |
| @@ -206,13 +206,16 @@ cube | |||
| 206 | int xp[6]; | 206 | int xp[6]; |
| 207 | }; | 207 | }; |
| 208 | 208 | ||
| 209 | /* | ||
| 209 | struct | 210 | struct |
| 210 | movable | 211 | movable |
| 211 | { | 212 | { |
| 212 | uint64_t val; | 213 | uint64_t val; |
| 213 | Trans t; | 214 | Trans t; |
| 214 | }; | 215 | }; |
| 216 | */ | ||
| 215 | 217 | ||
| 218 | /* | ||
| 216 | struct | 219 | struct |
| 217 | dfsarg | 220 | dfsarg |
| 218 | { | 221 | { |
| @@ -224,13 +227,28 @@ dfsarg | |||
| 224 | int d; | 227 | int d; |
| 225 | int bound; | 228 | int bound; |
| 226 | bool niss; | 229 | bool niss; |
| 227 | Move last[2]; | ||
| 228 | Move lastinv[2]; | ||
| 229 | AlgList * sols; | 230 | AlgList * sols; |
| 230 | pthread_mutex_t * sols_mutex; | 231 | pthread_mutex_t * sols_mutex; |
| 231 | Alg * current_alg; | 232 | Alg * current_alg; |
| 232 | void * extra; | 233 | void * extra; |
| 233 | }; | 234 | }; |
| 235 | */ | ||
| 236 | |||
| 237 | /* | ||
| 238 | struct | ||
| 239 | dfsarg | ||
| 240 | { | ||
| 241 | void * cube_data; | ||
| 242 | SolveOptions * opts; | ||
| 243 | int d; | ||
| 244 | int bound; | ||
| 245 | bool niss; | ||
| 246 | AlgList * sols; | ||
| 247 | Alg * current_alg; | ||
| 248 | Solver * solver; | ||
| 249 | Threader * threader; | ||
| 250 | }; | ||
| 251 | */ | ||
| 234 | 252 | ||
| 235 | struct | 253 | struct |
| 236 | fstcube | 254 | fstcube |
| @@ -260,9 +278,9 @@ moveset | |||
| 260 | { | 278 | { |
| 261 | char * name; | 279 | char * name; |
| 262 | bool (*allowed)(Move); | 280 | bool (*allowed)(Move); |
| 263 | bool (*allowed_next)(Move, Move, Move); | 281 | bool (*can_append)(Alg *, Move, bool); |
| 282 | bool (*cancel_niss)(Alg *); | ||
| 264 | Move sorted_moves[NMOVES+1]; | 283 | Move sorted_moves[NMOVES+1]; |
| 265 | uint64_t mask[NMOVES][NMOVES]; | ||
| 266 | }; | 284 | }; |
| 267 | 285 | ||
| 268 | struct | 286 | struct |
| @@ -304,10 +322,11 @@ step | |||
| 304 | PruneData * pd[MAX_N_COORD]; | 322 | PruneData * pd[MAX_N_COORD]; |
| 305 | bool pd_compact[MAX_N_COORD]; | 323 | bool pd_compact[MAX_N_COORD]; |
| 306 | Validator is_valid; | 324 | Validator is_valid; |
| 307 | DfsMover custom_move_checkstop; | 325 | /*DfsMover custom_move_checkstop;*/ |
| 308 | DfsExtraCopier copy_extra; | 326 | DfsExtraCopier copy_extra; |
| 309 | }; | 327 | }; |
| 310 | 328 | ||
| 329 | /* | ||
| 311 | struct | 330 | struct |
| 312 | threaddatasolve | 331 | threaddatasolve |
| 313 | { | 332 | { |
| @@ -317,6 +336,7 @@ threaddatasolve | |||
| 317 | AlgListNode ** node; | 336 | AlgListNode ** node; |
| 318 | pthread_mutex_t * start_mutex; | 337 | pthread_mutex_t * start_mutex; |
| 319 | }; | 338 | }; |
| 339 | */ | ||
| 320 | 340 | ||
| 321 | struct | 341 | struct |
| 322 | threaddatagenpt | 342 | threaddatagenpt |
diff --git a/src/movesets.c b/src/movesets.c new file mode 100644 index 0000000..d8f5bc1 --- /dev/null +++ b/src/movesets.c | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | #define MOVESETS_C | ||
| 2 | |||
| 3 | #include "movesets.h" | ||
| 4 | |||
| 5 | static bool allowed_HTM(Move m); | ||
| 6 | static bool allowed_URF(Move m); | ||
| 7 | static bool allowed_eofb(Move m); | ||
| 8 | static bool allowed_drud(Move m); | ||
| 9 | static bool allowed_htr(Move m); | ||
| 10 | static bool can_append_HTM(Move l2, Move l1, Move m); | ||
| 11 | static bool can_append_HTM_cached(Alg *alg, Move m, bool inverse); | ||
| 12 | static bool cancel_niss_HTM_cached(Alg *alg); | ||
| 13 | static void init_can_append_HTM(); | ||
| 14 | |||
| 15 | Moveset | ||
| 16 | moveset_HTM = { | ||
| 17 | .name = "HTM", | ||
| 18 | .allowed = allowed_HTM, | ||
| 19 | .can_append = can_append_HTM_cached, | ||
| 20 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 21 | }; | ||
| 22 | |||
| 23 | Moveset | ||
| 24 | moveset_URF = { | ||
| 25 | .name = "URF", | ||
| 26 | .allowed = allowed_URF, | ||
| 27 | .can_append = can_append_HTM_cached, | ||
| 28 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 29 | }; | ||
| 30 | |||
| 31 | Moveset | ||
| 32 | moveset_eofb = { | ||
| 33 | .name = "eofb", | ||
| 34 | .allowed = allowed_eofb, | ||
| 35 | .can_append = can_append_HTM_cached, | ||
| 36 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 37 | }; | ||
| 38 | |||
| 39 | Moveset | ||
| 40 | moveset_drud = { | ||
| 41 | .name = "drud", | ||
| 42 | .allowed = allowed_drud, | ||
| 43 | .can_append = can_append_HTM_cached, | ||
| 44 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 45 | }; | ||
| 46 | |||
| 47 | Moveset | ||
| 48 | moveset_htr = { | ||
| 49 | .name = "htr", | ||
| 50 | .allowed = allowed_htr, | ||
| 51 | .can_append = can_append_HTM_cached, | ||
| 52 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 53 | }; | ||
| 54 | |||
| 55 | Moveset * | ||
| 56 | all_movesets[] = { | ||
| 57 | &moveset_HTM, | ||
| 58 | &moveset_URF, | ||
| 59 | &moveset_eofb, | ||
| 60 | &moveset_drud, | ||
| 61 | &moveset_htr, | ||
| 62 | NULL | ||
| 63 | }; | ||
| 64 | |||
| 65 | static uint64_t can_append_HTM_mask[NMOVES][NMOVES]; | ||
| 66 | |||
| 67 | static bool | ||
| 68 | allowed_HTM(Move m) | ||
| 69 | { | ||
| 70 | return m >= U && m <= B3; | ||
| 71 | } | ||
| 72 | |||
| 73 | static bool | ||
| 74 | allowed_URF(Move m) | ||
| 75 | { | ||
| 76 | Move b = base_move(m); | ||
| 77 | |||
| 78 | return b == U || b == R || b == F; | ||
| 79 | } | ||
| 80 | |||
| 81 | static bool | ||
| 82 | allowed_eofb(Move m) | ||
| 83 | { | ||
| 84 | Move b = base_move(m); | ||
| 85 | |||
| 86 | return b == U || b == D || b == R || b == L || | ||
| 87 | ((b == F || b == B) && m == b+1); | ||
| 88 | } | ||
| 89 | |||
| 90 | static bool | ||
| 91 | allowed_drud(Move m) | ||
| 92 | { | ||
| 93 | Move b = base_move(m); | ||
| 94 | |||
| 95 | return b == U || b == D || | ||
| 96 | ((b == R || b == L || b == F || b == B) && m == b + 1); | ||
| 97 | } | ||
| 98 | |||
| 99 | static bool | ||
| 100 | allowed_htr(Move m) | ||
| 101 | { | ||
| 102 | Move b = base_move(m); | ||
| 103 | |||
| 104 | return moveset_HTM.allowed(m) && m == b + 1; | ||
| 105 | } | ||
| 106 | |||
| 107 | static bool | ||
| 108 | can_append_HTM(Move l2, Move l1, Move m) | ||
| 109 | { | ||
| 110 | bool cancel, cancel_last, cancel_swap; | ||
| 111 | |||
| 112 | cancel_last = l1 != NULLMOVE && base_move(l1) == base_move(m); | ||
| 113 | cancel_swap = l2 != NULLMOVE && base_move(l2) == base_move(m); | ||
| 114 | cancel = cancel_last || (commute(l1, l2) && cancel_swap); | ||
| 115 | |||
| 116 | return !cancel; | ||
| 117 | } | ||
| 118 | |||
| 119 | static bool | ||
| 120 | can_append_HTM_cached(Alg *alg, Move m, bool inverse) | ||
| 121 | { | ||
| 122 | Move *moves, l1, l2; | ||
| 123 | uint64_t mbit; | ||
| 124 | int n; | ||
| 125 | |||
| 126 | if (inverse) { | ||
| 127 | moves = alg->move_inverse; | ||
| 128 | n = alg->len_inverse; | ||
| 129 | } else { | ||
| 130 | moves = alg->move_normal; | ||
| 131 | n = alg->len_normal; | ||
| 132 | } | ||
| 133 | |||
| 134 | l1 = n > 0 ? moves[n-1] : NULLMOVE; | ||
| 135 | l2 = n > 1 ? moves[n-2] : NULLMOVE; | ||
| 136 | |||
| 137 | mbit = ((uint64_t)1) << m; | ||
| 138 | |||
| 139 | return can_append_HTM_mask[l2][l1] & mbit; | ||
| 140 | } | ||
| 141 | |||
| 142 | static bool | ||
| 143 | cancel_niss_HTM_cached(Alg *alg) | ||
| 144 | { | ||
| 145 | Move i1, i2; | ||
| 146 | int n; | ||
| 147 | bool can_first, can_swap; | ||
| 148 | |||
| 149 | n = alg->len_inverse; | ||
| 150 | i1 = n > 0 ? alg->move_inverse[n-1] : NULLMOVE; | ||
| 151 | i2 = n > 1 ? alg->move_inverse[n-2] : NULLMOVE; | ||
| 152 | |||
| 153 | can_first = can_append_HTM_cached(alg, inverse_move(i1), false); | ||
| 154 | can_swap = can_append_HTM_cached(alg, inverse_move(i2), false); | ||
| 155 | |||
| 156 | return can_first && (!commute(i1, i2) || can_swap); | ||
| 157 | } | ||
| 158 | |||
| 159 | static void | ||
| 160 | init_can_append_HTM() | ||
| 161 | { | ||
| 162 | Move l2, l1, m; | ||
| 163 | |||
| 164 | for (l1 = 0; l1 < NMOVES; l1++) | ||
| 165 | for (l2 = 0; l2 < NMOVES; l2++) | ||
| 166 | for (m = 0; m < NMOVES; m++) | ||
| 167 | if (can_append_HTM(l2, l1, m)) | ||
| 168 | can_append_HTM_mask[l2][l1] | ||
| 169 | |= (((uint64_t)1) << m); | ||
| 170 | } | ||
| 171 | |||
| 172 | void | ||
| 173 | init_moveset(Moveset *ms) | ||
| 174 | { | ||
| 175 | int j; | ||
| 176 | Move m; | ||
| 177 | |||
| 178 | for (j = 0, m = U; m < NMOVES; m++) | ||
| 179 | if (ms->allowed(m)) | ||
| 180 | ms->sorted_moves[j++] = m; | ||
| 181 | ms->sorted_moves[j] = NULLMOVE; | ||
| 182 | |||
| 183 | /* TODO: should be here? maybe just init all movesets together anyway... */ | ||
| 184 | init_can_append_HTM(); | ||
| 185 | } | ||
| 186 | |||
| 187 | void | ||
| 188 | init_movesets() | ||
| 189 | { | ||
| 190 | int i; | ||
| 191 | |||
| 192 | for (i = 0; all_movesets[i] != NULL; i++) | ||
| 193 | init_moveset(all_movesets[i]); | ||
| 194 | } | ||
diff --git a/src/movesets.h b/src/movesets.h new file mode 100644 index 0000000..a02d171 --- /dev/null +++ b/src/movesets.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef MOVESETS_H | ||
| 2 | #define MOVESETS_H | ||
| 3 | |||
| 4 | #include "alg.h" | ||
| 5 | |||
| 6 | void init_moveset(Moveset *); | ||
| 7 | void init_movesets(); | ||
| 8 | |||
| 9 | extern Moveset moveset_HTM; | ||
| 10 | extern Moveset moveset_URF; | ||
| 11 | extern Moveset moveset_eofb; | ||
| 12 | extern Moveset moveset_drud; | ||
| 13 | extern Moveset moveset_htr; | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/src/pruning.h b/src/pruning.h index 86691c1..93ae863 100644 --- a/src/pruning.h +++ b/src/pruning.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define PRUNING_H | 2 | #define PRUNING_H |
| 3 | 3 | ||
| 4 | #include "coord.h" | 4 | #include "coord.h" |
| 5 | #include "movesets.h" | ||
| 5 | 6 | ||
| 6 | void free_pd(PruneData *pd); | 7 | void free_pd(PruneData *pd); |
| 7 | PruneData * genptable(PruneData *data, int nthreads); | 8 | PruneData * genptable(PruneData *data, int nthreads); |
diff --git a/src/solve.c b/src/solve.c index d5a8f3d..41f99a2 100644 --- a/src/solve.c +++ b/src/solve.c | |||
| @@ -2,485 +2,118 @@ | |||
| 2 | 2 | ||
| 3 | #include "solve.h" | 3 | #include "solve.h" |
| 4 | 4 | ||
| 5 | /* Local functions ***********************************************************/ | 5 | void |
| 6 | 6 | dfs(DfsArg *arg, Solver *solver, Threader *threader) | |
| 7 | static bool cancel_niss(DfsArg *arg); | ||
| 8 | static void copy_dfsarg(DfsArg *src, DfsArg *dst); | ||
| 9 | static void dfs(DfsArg *arg); | ||
| 10 | static void dfs_add_sol(DfsArg *arg); | ||
| 11 | static void dfs_niss(DfsArg *arg); | ||
| 12 | static bool dfs_move_checkstop(DfsArg *arg); | ||
| 13 | static void * instance_thread(void *arg); | ||
| 14 | static void multidfs(DfsArg *arg); | ||
| 15 | static bool niss_makes_sense(DfsArg *arg); | ||
| 16 | static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols); | ||
| 17 | |||
| 18 | /* Local functions ***********************************************************/ | ||
| 19 | |||
| 20 | static bool | ||
| 21 | cancel_niss(DfsArg *arg) | ||
| 22 | { | ||
| 23 | Moveset *ms; | ||
| 24 | Move i1, i2; | ||
| 25 | bool p, p1, p2, q, q1, q2; | ||
| 26 | |||
| 27 | if (arg->lastinv[0] == NULLMOVE) | ||
| 28 | return false; | ||
| 29 | |||
| 30 | ms = arg->s->moveset; | ||
| 31 | i1 = inverse_move(arg->lastinv[0]); | ||
| 32 | i2 = inverse_move(arg->lastinv[1]); | ||
| 33 | |||
| 34 | p1 = !ms->allowed_next(arg->last[1], arg->last[0], i1); | ||
| 35 | p2 = !ms->allowed_next(arg->last[1], i1, arg->last[0]); | ||
| 36 | p = p1 || (commute(i1, arg->last[0]) && p2); | ||
| 37 | |||
| 38 | q1 = !ms->allowed_next(arg->last[1], arg->last[0], i2); | ||
| 39 | q2 = !ms->allowed_next(arg->last[1], i2, arg->last[0]); | ||
| 40 | q = q1 || (commute(i2, arg->last[0]) && q2); | ||
| 41 | |||
| 42 | return p || (commute(i1, i2) && q); | ||
| 43 | } | ||
| 44 | |||
| 45 | static void | ||
| 46 | copy_dfsarg(DfsArg *src, DfsArg *dst) | ||
| 47 | { | 7 | { |
| 48 | int i; | 8 | int i; |
| 49 | |||
| 50 | dst->cube = src->cube; | ||
| 51 | dst->t = src->t; | ||
| 52 | dst->s = src->s; | ||
| 53 | dst->opts = src->opts; | ||
| 54 | dst->d = src->d; | ||
| 55 | dst->bound = src->bound; /* In theory not needed */ | ||
| 56 | dst->niss = src->niss; | ||
| 57 | dst->sols = src->sols; | ||
| 58 | dst->sols_mutex = src->sols_mutex; | ||
| 59 | dst->current_alg = src->current_alg; | ||
| 60 | |||
| 61 | for (i = 0; i < 2; i++) { | ||
| 62 | dst->last[i] = src->last[i]; | ||
| 63 | dst->lastinv[i] = src->lastinv[i]; | ||
| 64 | } | ||
| 65 | |||
| 66 | for (i = 0; i < src->s->n_coord; i++) { | ||
| 67 | dst->ind[i].val = src->ind[i].val; | ||
| 68 | dst->ind[i].t = src->ind[i].t; | ||
| 69 | } | ||
| 70 | |||
| 71 | src->s->copy_extra(src, dst); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void | ||
| 75 | dfs(DfsArg *arg) | ||
| 76 | { | ||
| 77 | int i; | ||
| 78 | Move m, l0, l1; | ||
| 79 | DfsArg newarg; | 9 | DfsArg newarg; |
| 10 | Alg *sol; | ||
| 11 | Move m; | ||
| 80 | 12 | ||
| 81 | if (dfs_move_checkstop(arg)) | 13 | if (arg->current_alg->len > arg->d) |
| 82 | return; | ||
| 83 | |||
| 84 | if (arg->bound == 0) { | ||
| 85 | if (arg->current_alg->len == arg->d) | ||
| 86 | dfs_add_sol(arg); | ||
| 87 | return; | 14 | return; |
| 88 | } | ||
| 89 | |||
| 90 | for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 91 | m = arg->s->moveset->sorted_moves[i]; | ||
| 92 | l0 = arg->last[0]; | ||
| 93 | l1 = arg->last[1]; | ||
| 94 | if (possible_next(m, arg->s->moveset, l0, l1)) { | ||
| 95 | copy_dfsarg(arg, &newarg); | ||
| 96 | newarg.last[1] = l0; | ||
| 97 | newarg.last[0] = m; | ||
| 98 | append_move(arg->current_alg, m, newarg.niss); | ||
| 99 | dfs(&newarg); | ||
| 100 | arg->current_alg->len--; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | if (niss_makes_sense(arg)) | ||
| 105 | dfs_niss(arg); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void | ||
| 109 | dfs_add_sol(DfsArg *arg) | ||
| 110 | { | ||
| 111 | bool valid, accepted, nisscanc; | ||
| 112 | 15 | ||
| 113 | valid = arg->s->is_valid==NULL || arg->s->is_valid(arg->current_alg); | 16 | if (solver->is_solved(solver->param, arg->cubedata)) { |
| 114 | accepted = valid || arg->opts->all; | 17 | /* TODO: the "all" option should be re-implemented as setting |
| 115 | nisscanc = arg->s->final && cancel_niss(arg); | 18 | validate to null */ |
| 116 | 19 | ||
| 117 | if (accepted && !nisscanc) { | 20 | /* TODO: we also have to check if cancel with NISS; |
| 118 | pthread_mutex_lock(arg->sols_mutex); | 21 | we can't because we have no access to the s->final field |
| 22 | this should be done by the step's validator? */ | ||
| 23 | sol = solver->validate_solution(solver->param,arg->current_alg); | ||
| 24 | bool accepted = sol != NULL; | ||
| 25 | bool too_short = arg->current_alg->len != arg->d; | ||
| 119 | 26 | ||
| 120 | if (arg->sols->len < arg->opts->max_solutions) { | 27 | if (accepted && !too_short) { |
| 121 | append_alg(arg->sols, arg->current_alg); | 28 | /* TODO: arg->t got lost in refactoring */ |
| 122 | transform_alg( | 29 | /* transform_alg(inverse_trans(arg->t), sol);*/ |
| 123 | inverse_trans(arg->t), arg->sols->last->alg); | ||
| 124 | if (arg->opts->verbose) | 30 | if (arg->opts->verbose) |
| 125 | print_alg(arg->sols->last->alg, false); | 31 | print_alg(sol, false); |
| 32 | threader->append_sol(sol, arg->threaddata); | ||
| 126 | } | 33 | } |
| 127 | 34 | return; | |
| 128 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | static void | ||
| 133 | dfs_niss(DfsArg *arg) | ||
| 134 | { | ||
| 135 | DfsArg newarg; | ||
| 136 | Alg *inv; | ||
| 137 | Cube *c; | ||
| 138 | |||
| 139 | copy_dfsarg(arg, &newarg); | ||
| 140 | |||
| 141 | /* Invert current alg and scramble */ | ||
| 142 | newarg.cube = malloc(sizeof(Cube)); | ||
| 143 | inv = inverse_alg(arg->current_alg); | ||
| 144 | c = malloc(sizeof(Cube)); | ||
| 145 | make_solved(newarg.cube); | ||
| 146 | apply_alg(inv, newarg.cube); | ||
| 147 | copy_cube(arg->cube, c); | ||
| 148 | invert_cube(c); | ||
| 149 | compose(c, newarg.cube); | ||
| 150 | |||
| 151 | /* New indexes */ | ||
| 152 | compute_ind(newarg.s, newarg.cube, newarg.ind); | ||
| 153 | |||
| 154 | swapmove(&(newarg.last[0]), &(newarg.lastinv[0])); | ||
| 155 | swapmove(&(newarg.last[1]), &(newarg.lastinv[1])); | ||
| 156 | newarg.niss = !(arg->niss); | ||
| 157 | |||
| 158 | dfs(&newarg); | ||
| 159 | |||
| 160 | free_alg(inv); | ||
| 161 | free(c); | ||
| 162 | free(newarg.cube); | ||
| 163 | } | ||
| 164 | |||
| 165 | static bool | ||
| 166 | dfs_move_checkstop(DfsArg *arg) | ||
| 167 | { | ||
| 168 | int i, goal, nsols; | ||
| 169 | Move mm; | ||
| 170 | Trans tt = uf; /* Avoid uninitialized warning */ | ||
| 171 | |||
| 172 | /* Moving and computing bound */ | ||
| 173 | arg->bound = 0; | ||
| 174 | goal = arg->d - arg->current_alg->len; | ||
| 175 | for (i = 0; i < arg->s->n_coord; i++) { | ||
| 176 | if (arg->last[0] != NULLMOVE) { | ||
| 177 | mm = transform_move(arg->ind[i].t, arg->last[0]); | ||
| 178 | arg->ind[i].val = move_coord(arg->s->coord[i], | ||
| 179 | mm, arg->ind[i].val, &tt); | ||
| 180 | arg->ind[i].t = transform_trans(tt, arg->ind[i].t); | ||
| 181 | } | ||
| 182 | |||
| 183 | arg->bound = | ||
| 184 | MAX(arg->bound, ptableval(arg->s->pd[i], arg->ind[i].val)); | ||
| 185 | if (arg->opts->can_niss && !arg->niss) | ||
| 186 | arg->bound = MIN(1, arg->bound); | ||
| 187 | |||
| 188 | if (arg->bound > goal) | ||
| 189 | return true; | ||
| 190 | } | ||
| 191 | |||
| 192 | pthread_mutex_lock(arg->sols_mutex); | ||
| 193 | nsols = arg->sols->len; | ||
| 194 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 195 | |||
| 196 | return nsols >= arg->opts->max_solutions; | ||
| 197 | } | ||
| 198 | |||
| 199 | static void * | ||
| 200 | instance_thread(void *arg) | ||
| 201 | { | ||
| 202 | bool b, inv; | ||
| 203 | Cube c; | ||
| 204 | Move m; | ||
| 205 | ThreadDataSolve *td; | ||
| 206 | AlgListNode *node; | ||
| 207 | DfsArg darg; | ||
| 208 | |||
| 209 | td = (ThreadDataSolve *)arg; | ||
| 210 | |||
| 211 | while (1) { | ||
| 212 | b = false; | ||
| 213 | |||
| 214 | pthread_mutex_lock(td->start_mutex); | ||
| 215 | if ((node = *(td->node)) == NULL) | ||
| 216 | b = true; | ||
| 217 | else | ||
| 218 | *(td->node) = (*(td->node))->next; | ||
| 219 | pthread_mutex_unlock(td->start_mutex); | ||
| 220 | |||
| 221 | if (b) | ||
| 222 | break; | ||
| 223 | |||
| 224 | inv = node->alg->inv[0]; | ||
| 225 | m = node->alg->move[0]; | ||
| 226 | |||
| 227 | copy_cube(td->arg.cube, &c); | ||
| 228 | if (inv) | ||
| 229 | invert_cube(&c); | ||
| 230 | |||
| 231 | copy_dfsarg(&td->arg, &darg); | ||
| 232 | compute_ind(td->arg.s, &c, darg.ind); | ||
| 233 | darg.cube = &c; | ||
| 234 | |||
| 235 | darg.niss = inv; | ||
| 236 | darg.last[0] = m; | ||
| 237 | darg.last[1] = NULLMOVE; | ||
| 238 | darg.lastinv[0] = NULLMOVE; | ||
| 239 | darg.lastinv[1] = NULLMOVE; | ||
| 240 | darg.current_alg = new_alg(""); | ||
| 241 | append_move(darg.current_alg, m, inv); | ||
| 242 | |||
| 243 | dfs(&darg); | ||
| 244 | |||
| 245 | free_alg(darg.current_alg); | ||
| 246 | } | 35 | } |
| 247 | 36 | ||
| 248 | return NULL; | 37 | if (arg->current_alg->len == arg->d) |
| 249 | } | 38 | return; |
| 250 | |||
| 251 | static void | ||
| 252 | multidfs(DfsArg *arg) | ||
| 253 | { | ||
| 254 | int i; | ||
| 255 | Cube local_cube; | ||
| 256 | Alg *alg; | ||
| 257 | AlgList *start; | ||
| 258 | AlgListNode **node; | ||
| 259 | pthread_t t[arg->opts->nthreads]; | ||
| 260 | ThreadDataSolve td[arg->opts->nthreads]; | ||
| 261 | pthread_mutex_t *start_mutex, *sols_mutex; | ||
| 262 | 39 | ||
| 263 | node = malloc(sizeof(AlgListNode *)); | 40 | /* TODO: do not alloc */ |
| 264 | start_mutex = malloc(sizeof(pthread_mutex_t)); | 41 | newarg.cubedata = solver->alloc_cubedata(solver->param); |
| 265 | sols_mutex = malloc(sizeof(pthread_mutex_t)); | 42 | for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { |
| 43 | m = solver->moveset->sorted_moves[i]; | ||
| 44 | if (solver->moveset->can_append(arg->current_alg, m, arg->niss) | ||
| 45 | && compare_last(arg->current_alg, m, arg->niss) >= 0) { | ||
| 46 | append_move(arg->current_alg, m, arg->niss); | ||
| 266 | 47 | ||
| 267 | start = new_alglist(); | 48 | solver->copy_cubedata( |
| 268 | pthread_mutex_init(start_mutex, NULL); | 49 | solver->param, arg->cubedata, newarg.cubedata); |
| 269 | pthread_mutex_init(sols_mutex, NULL); | 50 | newarg.threaddata = arg->threaddata; |
| 51 | newarg.opts = arg->opts; | ||
| 52 | newarg.d = arg->d; | ||
| 53 | newarg.niss = arg->niss; | ||
| 54 | newarg.current_alg = arg->current_alg; | ||
| 55 | if (!solver->move_check_stop( | ||
| 56 | solver->param, &newarg, threader)) | ||
| 57 | dfs(&newarg, solver, threader); | ||
| 270 | 58 | ||
| 271 | for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) { | 59 | remove_last_move(arg->current_alg); |
| 272 | alg = new_alg(""); | ||
| 273 | append_move(alg, arg->s->moveset->sorted_moves[i], false); | ||
| 274 | append_alg(start, alg); | ||
| 275 | if (arg->opts->can_niss && !arg->s->final) { | ||
| 276 | alg->inv[0] = true; | ||
| 277 | append_alg(start, alg); | ||
| 278 | } | 60 | } |
| 279 | free_alg(alg); | ||
| 280 | } | 61 | } |
| 281 | *node = start->first; | 62 | solver->free_cubedata(solver->param, newarg.cubedata); |
| 282 | |||
| 283 | copy_cube(arg->cube, &local_cube); | ||
| 284 | |||
| 285 | for (i = 0; i < arg->opts->nthreads; i++) { | ||
| 286 | copy_dfsarg(arg, &(td[i].arg)); | ||
| 287 | td[i].arg.cube = &local_cube; | ||
| 288 | td[i].arg.sols_mutex = sols_mutex; | ||
| 289 | |||
| 290 | td[i].thid = i; | ||
| 291 | td[i].start = start; | ||
| 292 | td[i].node = node; | ||
| 293 | td[i].start_mutex = start_mutex; | ||
| 294 | |||
| 295 | pthread_create(&t[i], NULL, instance_thread, &td[i]); | ||
| 296 | } | ||
| 297 | |||
| 298 | for (i = 0; i < arg->opts->nthreads; i++) | ||
| 299 | pthread_join(t[i], NULL); | ||
| 300 | |||
| 301 | free_alglist(start); | ||
| 302 | free(node); | ||
| 303 | free(start_mutex); | ||
| 304 | free(sols_mutex); | ||
| 305 | } | ||
| 306 | |||
| 307 | static bool | ||
| 308 | niss_makes_sense(DfsArg *arg) | ||
| 309 | { | ||
| 310 | Move m, mm; | ||
| 311 | uint64_t u; | ||
| 312 | int i; | ||
| 313 | |||
| 314 | if (arg->s->final || arg->niss || !arg->opts->can_niss) | ||
| 315 | return false; | ||
| 316 | |||
| 317 | if (arg->last[0] == NULLMOVE) | ||
| 318 | return true; | ||
| 319 | 63 | ||
| 320 | m = inverse_move(arg->last[0]); | 64 | if (arg->opts->can_niss && !arg->niss && |
| 321 | for (i = 0; i < arg->s->n_coord; i++) { | 65 | solver->niss_makes_sense( |
| 322 | mm = transform_move(arg->ind[i].t, m); | 66 | solver->param, arg->cubedata, arg->current_alg)) { |
| 323 | u = move_coord(arg->s->coord[i], mm, 0, NULL); | 67 | solver->invert_cube(solver->param, arg->cubedata); |
| 324 | if (ptableval(arg->s->pd[i], u) > 0) | 68 | arg->niss = true; |
| 325 | return true; | 69 | dfs(arg, solver, threader); |
| 326 | } | 70 | } |
| 327 | |||
| 328 | return false; | ||
| 329 | } | 71 | } |
| 330 | 72 | ||
| 331 | static bool | ||
| 332 | solvestop(int d, int op, SolveOptions *opts, AlgList *sols) | ||
| 333 | { | ||
| 334 | bool opt_done, max_moves_exceeded, max_sols_exceeded; | ||
| 335 | |||
| 336 | opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op; | ||
| 337 | max_moves_exceeded = d > opts->max_moves; | ||
| 338 | max_sols_exceeded = sols->len >= opts->max_solutions; | ||
| 339 | |||
| 340 | return opt_done || max_moves_exceeded || max_sols_exceeded; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* Public functions **********************************************************/ | ||
| 344 | |||
| 345 | AlgList * | 73 | AlgList * |
| 346 | solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts) | 74 | solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader) |
| 347 | { | 75 | { |
| 348 | int i, j, d, op, est; | 76 | int i, d, optimal; |
| 349 | bool ready[99], one_ready, zerosol; | 77 | bool ready[MAX_SOLVERS], stop, one_ready; |
| 350 | Movable ind[99][10]; | 78 | DfsArg arg[MAX_SOLVERS]; |
| 351 | AlgList *s; | 79 | AlgList *sols; |
| 352 | Cube *c[99]; | ||
| 353 | DfsArg arg[99]; | ||
| 354 | |||
| 355 | prepare_cs(cs, opts); | ||
| 356 | s = new_alglist(); | ||
| 357 | |||
| 358 | for (i = 0, one_ready = false; cs->step[i] != NULL; i++) { | ||
| 359 | c[i] = malloc(sizeof(Cube)); | ||
| 360 | copy_cube(cube, c[i]); | ||
| 361 | apply_trans(cs->t[i], c[i]); | ||
| 362 | 80 | ||
| 363 | arg[i].cube = c[i]; | 81 | one_ready = false; |
| 364 | arg[i].t = cs->t[i]; | 82 | for (i = 0; solver[i] != NULL; i++) { |
| 365 | arg[i].s = cs->step[i]; | 83 | arg[i].cubedata = |
| 84 | solver[i]->prepare_cube(solver[i]->param, cube); | ||
| 366 | arg[i].opts = opts; | 85 | arg[i].opts = opts; |
| 367 | arg[i].sols = s; | 86 | ready[i] = arg[i].cubedata != NULL; |
| 368 | 87 | one_ready = one_ready || ready[i]; | |
| 369 | if ((ready[i] = cs->step[i]->ready(c[i]))) { | ||
| 370 | one_ready = true; | ||
| 371 | /* Only for local use for 0 moves solutions */ | ||
| 372 | compute_ind(cs->step[i], c[i], ind[i]); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | if (!one_ready) { | ||
| 376 | fprintf(stderr, "Cube not ready for solving step: "); | ||
| 377 | fprintf(stderr, "%s\n", cs->ready_msg); | ||
| 378 | return s; | ||
| 379 | } | 88 | } |
| 380 | 89 | ||
| 381 | /* If the empty moves sequence is a solution for one of the | 90 | sols = new_alglist(); |
| 382 | * alternatives, all longer solutions will be discarded, so we may | 91 | if (!one_ready) { |
| 383 | * just set its ready[] value to false. If the solution is accepted | 92 | fprintf(stderr, "Cube not ready for solving\n"); |
| 384 | * we append it and start searching from d = 1. */ | 93 | return sols; |
| 385 | for (i = 0, zerosol = false; cs->step[i] != NULL; i++) { | ||
| 386 | if (ready[i]) { | ||
| 387 | est = 0; | ||
| 388 | for (j = 0; j < cs->step[i]->n_coord; j++) | ||
| 389 | est = MAX(est, ptableval(cs->step[i]->pd[j], | ||
| 390 | ind[i][j].val)); | ||
| 391 | if (est == 0) { | ||
| 392 | ready[i] = false; | ||
| 393 | zerosol = true; | ||
| 394 | } | ||
| 395 | } | ||
| 396 | } | ||
| 397 | if (zerosol && opts->min_moves == 0) { | ||
| 398 | append_alg(s, new_alg("")); | ||
| 399 | opts->min_moves = 1; | ||
| 400 | if (opts->verbose) | ||
| 401 | printf("Step is already solved" | ||
| 402 | "(empty alg is a solution)\n"); | ||
| 403 | } | 94 | } |
| 404 | 95 | ||
| 405 | for (d = opts->min_moves, op = -1; !solvestop(d, op, opts, s); d++) { | 96 | optimal = opts->max_moves; |
| 97 | stop = false; | ||
| 98 | for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) { | ||
| 406 | if (opts->verbose) | 99 | if (opts->verbose) |
| 407 | fprintf(stderr, "Searching depth %d\n", d); | 100 | fprintf(stderr, "Searching depth %d\n", d); |
| 408 | 101 | ||
| 409 | for (i=0; cs->step[i]!=NULL && !solvestop(d,op,opts,s); i++) { | 102 | for (i = 0; solver[i] != NULL && !stop; i++) { |
| 410 | if (!ready[i]) | 103 | if (!ready[i]) |
| 411 | continue; | 104 | continue; |
| 412 | 105 | ||
| 413 | arg[i].d = d; | 106 | arg[i].d = d; |
| 414 | multidfs(&arg[i]); | 107 | threader->dispatch(&arg[i], sols, solver[i], threader); |
| 415 | |||
| 416 | if (s->len > 0 && op == -1) | ||
| 417 | op = d; | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | for (i = 0; cs->step[i] != NULL; i++) | ||
| 422 | free(c[i]); | ||
| 423 | |||
| 424 | return s; | ||
| 425 | } | ||
| 426 | 108 | ||
| 427 | /* TODO: make more general! */ | 109 | if (sols->len > 0) |
| 428 | Alg * | 110 | optimal = MIN(optimal, d); |
| 429 | solve_2phase(Cube *cube, int nthreads) | ||
| 430 | { | ||
| 431 | int bestlen, newb; | ||
| 432 | Alg *bestalg, *ret; | ||
| 433 | AlgList *sols1, *sols2; | ||
| 434 | AlgListNode *i; | ||
| 435 | Cube c; | ||
| 436 | SolveOptions opts1, opts2; | ||
| 437 | |||
| 438 | opts1.min_moves = 0; | ||
| 439 | opts1.max_moves = 13; | ||
| 440 | opts1.max_solutions = 20; | ||
| 441 | opts1.nthreads = nthreads; | ||
| 442 | opts1.optimal = 3; | ||
| 443 | opts1.can_niss = false; | ||
| 444 | opts1.verbose = false; | ||
| 445 | opts1.all = true; | ||
| 446 | 111 | ||
| 447 | opts2.min_moves = 0; | 112 | stop = sols->len >= opts->max_solutions; |
| 448 | opts2.max_moves = 19; | ||
| 449 | opts2.max_solutions = 1; | ||
| 450 | opts2.nthreads = nthreads; | ||
| 451 | opts2.can_niss = false; | ||
| 452 | opts2.verbose = false; | ||
| 453 | |||
| 454 | /* We skip step1 if it is solved on U/D */ | ||
| 455 | if (check_drud(cube)) { | ||
| 456 | sols1 = new_alglist(); | ||
| 457 | append_alg(sols1, new_alg("")); | ||
| 458 | } else { | ||
| 459 | sols1 = solve(cube, &drud_HTM, &opts1); | ||
| 460 | } | ||
| 461 | bestalg = new_alg(""); | ||
| 462 | bestlen = 999; | ||
| 463 | for (i = sols1->first; i != NULL; i = i->next) { | ||
| 464 | copy_cube(cube, &c); | ||
| 465 | apply_alg(i->alg, &c); | ||
| 466 | sols2 = solve(&c, &dranyfin_DR, &opts2); | ||
| 467 | |||
| 468 | if (sols2->len > 0) { | ||
| 469 | newb = i->alg->len + sols2->first->alg->len; | ||
| 470 | if (newb < bestlen) { | ||
| 471 | bestlen = newb; | ||
| 472 | copy_alg(i->alg, bestalg); | ||
| 473 | compose_alg(bestalg, sols2->first->alg); | ||
| 474 | } | ||
| 475 | } | 113 | } |
| 476 | 114 | stop = stop || | |
| 477 | free_alglist(sols2); | 115 | (opts->optimal != -1 && d >= opts->optimal + optimal); |
| 478 | } | 116 | } |
| 479 | 117 | ||
| 480 | free_alglist(sols1); | 118 | return sols; |
| 481 | |||
| 482 | ret = cleanup(bestalg); | ||
| 483 | free_alg(bestalg); | ||
| 484 | |||
| 485 | return ret; | ||
| 486 | } | 119 | } |
diff --git a/src/solve.h b/src/solve.h index 9a284ff..b09c81b 100644 --- a/src/solve.h +++ b/src/solve.h | |||
| @@ -2,10 +2,52 @@ | |||
| 2 | #define SOLVE_H | 2 | #define SOLVE_H |
| 3 | 3 | ||
| 4 | #include "moves.h" | 4 | #include "moves.h" |
| 5 | #include "steps.h" | ||
| 6 | #include "trans.h" | ||
| 7 | 5 | ||
| 8 | AlgList * solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts); | 6 | #define MAX_SOLVERS 99 |
| 9 | Alg * solve_2phase(Cube *cube, int nthreads); | 7 | |
| 8 | typedef struct dfsarg DfsArg; | ||
| 9 | typedef struct threader Threader; | ||
| 10 | typedef struct solver Solver; | ||
| 11 | |||
| 12 | /* TODO: add solver and threader in DfsData, remove from dispatch args and similar */ | ||
| 13 | |||
| 14 | struct dfsarg { | ||
| 15 | void * cubedata; | ||
| 16 | void * threaddata; | ||
| 17 | SolveOptions * opts; | ||
| 18 | int d; | ||
| 19 | bool niss; | ||
| 20 | Alg * current_alg; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct threader { | ||
| 24 | void (*append_sol)(Alg *, void *); | ||
| 25 | void (*dispatch)(DfsArg *, AlgList *, Solver *, Threader *); | ||
| 26 | int (*get_nsol)(void *); | ||
| 27 | /* TODO: threader should have param, like solver? */ | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct solver { | ||
| 31 | Moveset * moveset; | ||
| 32 | bool (*move_check_stop)(void *, DfsArg *, Threader *); | ||
| 33 | Alg * (*validate_solution)(void *, Alg *); | ||
| 34 | bool (*niss_makes_sense)(void *, void *, Alg *); | ||
| 35 | /* TODO: move param to somewhere where it makes more sense */ | ||
| 36 | void * param; | ||
| 37 | /* TODO: the following should be part of a generic cube description */ | ||
| 38 | /* TODO: remove alloc? */ | ||
| 39 | void * (*alloc_cubedata)(void *); | ||
| 40 | void (*copy_cubedata)(void *, void *, void *); | ||
| 41 | void (*free_cubedata)(void *, void *); | ||
| 42 | void (*invert_cube)(void *, void *); | ||
| 43 | bool (*is_solved)(void *, void *); | ||
| 44 | void (*apply_alg)(void *, void *, Alg *); | ||
| 45 | /* TODO: remove dependence on Cube, preparation should be done before */ | ||
| 46 | void * (*prepare_cube)(void *, Cube *); | ||
| 47 | }; | ||
| 48 | |||
| 49 | void dfs(DfsArg *, Solver *, Threader *); | ||
| 50 | /* TODO: remove dependence on Cube, preparation should be done before */ | ||
| 51 | AlgList * solve(Cube *, SolveOptions *, Solver **, Threader *); | ||
| 10 | 52 | ||
| 11 | #endif | 53 | #endif |
diff --git a/src/solver_step.c b/src/solver_step.c new file mode 100644 index 0000000..5c9d149 --- /dev/null +++ b/src/solver_step.c | |||
| @@ -0,0 +1,296 @@ | |||
| 1 | #include "solver_step.h" | ||
| 2 | |||
| 3 | typedef struct { | ||
| 4 | Cube * cube; | ||
| 5 | uint64_t * val; | ||
| 6 | Trans * t; | ||
| 7 | } CubeData; | ||
| 8 | |||
| 9 | static void apply_alg_cubedata(void *, void *, Alg *); | ||
| 10 | static void init_indexes(Step *, CubeData *); | ||
| 11 | static void * prepare_cube(void *, Cube *); | ||
| 12 | static bool move_check_stop_eager(void *, DfsArg *, Threader *); | ||
| 13 | static bool move_check_stop_lazy(void *, DfsArg *, Threader *); | ||
| 14 | static bool move_check_stop_nonsol(void *, DfsArg *, Threader *); | ||
| 15 | static bool is_solved_step(void *, void *); | ||
| 16 | static Alg * validate_solution(void *, Alg *); | ||
| 17 | static void * alloc_cubedata(void *); | ||
| 18 | static void copy_cubedata(void *, void *, void *); | ||
| 19 | static void free_cubedata(void *, void *); | ||
| 20 | static void invert_cubedata(void *, void *); | ||
| 21 | static bool niss_makes_sense(void *, void *, Alg *); | ||
| 22 | static Solver * new_stepsolver_nocheckstop(Step *step); | ||
| 23 | |||
| 24 | static void | ||
| 25 | apply_alg_cubedata(void *param, void *cubedata, Alg *alg) | ||
| 26 | { | ||
| 27 | Step *s = (Step *)param; | ||
| 28 | CubeData *data = (CubeData *)cubedata; | ||
| 29 | |||
| 30 | apply_alg(alg, data->cube); | ||
| 31 | init_indexes(s, data); | ||
| 32 | } | ||
| 33 | |||
| 34 | static void | ||
| 35 | init_indexes(Step *step, CubeData *data) | ||
| 36 | { | ||
| 37 | int i; | ||
| 38 | Cube moved; | ||
| 39 | Trans t, tt; | ||
| 40 | |||
| 41 | for (i = 0; i < step->n_coord; i++) { | ||
| 42 | t = step->coord_trans[i]; | ||
| 43 | copy_cube(data->cube, &moved); | ||
| 44 | apply_trans(t, &moved); | ||
| 45 | data->val[i] = index_coord(step->coord[i], &moved, &tt); | ||
| 46 | data->t[i] = transform_trans(tt, t); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | static void * | ||
| 51 | prepare_cube(void *param, Cube *cube) | ||
| 52 | { | ||
| 53 | int i; | ||
| 54 | Step *s; | ||
| 55 | CubeData *data; | ||
| 56 | |||
| 57 | s = (Step *)param; | ||
| 58 | |||
| 59 | for (i = 0; i < s->n_coord; i++) { | ||
| 60 | s->pd[i] = malloc(sizeof(PruneData)); | ||
| 61 | s->pd[i]->moveset = s->moveset; | ||
| 62 | /* TODO: check if moveset initialization works fine, | ||
| 63 | e.g. if there is a variable to save the initialized status | ||
| 64 | or if it gets initialized multiple times */ | ||
| 65 | init_moveset(s->moveset); | ||
| 66 | s->pd[i]->coord = s->coord[i]; | ||
| 67 | gen_coord(s->coord[i]); | ||
| 68 | s->pd[i]->compact = s->pd_compact[i]; | ||
| 69 | s->pd[i] = genptable(s->pd[i], 4); /* TODO: threads */ | ||
| 70 | } | ||
| 71 | |||
| 72 | data = alloc_cubedata(param); | ||
| 73 | data->cube = malloc(sizeof(Cube)); | ||
| 74 | copy_cube(cube, data->cube); | ||
| 75 | init_indexes(s, data); | ||
| 76 | |||
| 77 | return data; | ||
| 78 | } | ||
| 79 | |||
| 80 | static bool | ||
| 81 | move_check_stop_eager(void *param, DfsArg *arg, Threader *threader) | ||
| 82 | { | ||
| 83 | int nsol; | ||
| 84 | |||
| 85 | if (move_check_stop_nonsol(param, arg, threader)) | ||
| 86 | return true; | ||
| 87 | |||
| 88 | nsol = threader->get_nsol(arg->threaddata); | ||
| 89 | return nsol >= arg->opts->max_solutions; | ||
| 90 | } | ||
| 91 | |||
| 92 | static bool | ||
| 93 | move_check_stop_lazy(void *param, DfsArg *arg, Threader *threader) | ||
| 94 | { | ||
| 95 | int nsol; | ||
| 96 | |||
| 97 | nsol = threader->get_nsol(arg->threaddata); | ||
| 98 | if (nsol >= arg->opts->max_solutions) | ||
| 99 | return true; | ||
| 100 | |||
| 101 | return move_check_stop_nonsol(param, arg, threader); | ||
| 102 | } | ||
| 103 | |||
| 104 | static bool | ||
| 105 | move_check_stop_nonsol(void *param, DfsArg *arg, Threader *threader) | ||
| 106 | { | ||
| 107 | int i, goal, bound; | ||
| 108 | Move mm, lastmove; | ||
| 109 | Trans tt = uf; | ||
| 110 | CubeData *data; | ||
| 111 | Step *s; | ||
| 112 | |||
| 113 | s = (Step *)param; | ||
| 114 | data = (CubeData *)arg->cubedata; | ||
| 115 | |||
| 116 | bound = 0; | ||
| 117 | goal = arg->d - arg->current_alg->len; | ||
| 118 | /* TODO: check if len is 0 */ | ||
| 119 | lastmove = arg->current_alg->move[arg->current_alg->len-1]; | ||
| 120 | for (i = 0; i < s->n_coord; i++) { | ||
| 121 | mm = transform_move(data->t[i], lastmove); | ||
| 122 | data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt); | ||
| 123 | data->t[i] = transform_trans(tt, data->t[i]); | ||
| 124 | |||
| 125 | bound = MAX(bound, ptableval(s->pd[i], data->val[i])); | ||
| 126 | if (arg->opts->can_niss && !arg->niss) | ||
| 127 | bound = MIN(1, bound); | ||
| 128 | |||
| 129 | if (bound > goal) { | ||
| 130 | return true; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | return false; | ||
| 135 | } | ||
| 136 | |||
| 137 | static bool | ||
| 138 | is_solved_step(void *param, void *cubedata) | ||
| 139 | { | ||
| 140 | int i; | ||
| 141 | Step *s; | ||
| 142 | CubeData *data; | ||
| 143 | |||
| 144 | s = (Step *)param; | ||
| 145 | data = (CubeData *)cubedata; | ||
| 146 | |||
| 147 | for (i = 0; i < s->n_coord; i++) | ||
| 148 | if (data->val[i] != 0) | ||
| 149 | return false; | ||
| 150 | |||
| 151 | return true; | ||
| 152 | } | ||
| 153 | |||
| 154 | static Alg * | ||
| 155 | validate_solution(void *param, Alg *alg) | ||
| 156 | { | ||
| 157 | return ((Step *)param)->is_valid(alg); | ||
| 158 | } | ||
| 159 | |||
| 160 | static void * | ||
| 161 | alloc_cubedata(void *param) | ||
| 162 | { | ||
| 163 | Step *s; | ||
| 164 | CubeData *data; | ||
| 165 | |||
| 166 | s = (Step *)param; | ||
| 167 | |||
| 168 | data = malloc(sizeof(CubeData)); | ||
| 169 | /* We do not need to allocate a cube */ | ||
| 170 | data->val = malloc(s->n_coord * sizeof(uint64_t)); | ||
| 171 | data->t = malloc(s->n_coord * sizeof(Trans)); | ||
| 172 | |||
| 173 | return data; | ||
| 174 | } | ||
| 175 | |||
| 176 | static void | ||
| 177 | copy_cubedata(void *param, void *src, void *dst) | ||
| 178 | { | ||
| 179 | int i; | ||
| 180 | Step *s; | ||
| 181 | CubeData *newdata, *olddata; | ||
| 182 | |||
| 183 | s = (Step *)param; | ||
| 184 | olddata = (CubeData *)src; | ||
| 185 | newdata = (CubeData *)dst; | ||
| 186 | |||
| 187 | /* Copy reference: we never move the cube */ | ||
| 188 | newdata->cube = olddata->cube; | ||
| 189 | for (i = 0; i < s->n_coord; i++) { | ||
| 190 | newdata->val[i] = olddata->val[i]; | ||
| 191 | newdata->t[i] = olddata->t[i]; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | static void | ||
| 196 | free_cubedata(void *param, void *cubedata) | ||
| 197 | { | ||
| 198 | CubeData *data; | ||
| 199 | |||
| 200 | data = (CubeData *)cubedata; | ||
| 201 | |||
| 202 | free(data->t); | ||
| 203 | free(data->val); | ||
| 204 | /* We do not free the cube */ | ||
| 205 | free(data); | ||
| 206 | } | ||
| 207 | |||
| 208 | static void | ||
| 209 | invert_cubedata(void *param, void *cubedata) | ||
| 210 | { | ||
| 211 | Step *s; | ||
| 212 | CubeData *data; | ||
| 213 | |||
| 214 | s = (Step *)param; | ||
| 215 | data = (CubeData *)cubedata; | ||
| 216 | |||
| 217 | invert_cube(data->cube); | ||
| 218 | init_indexes(s, data); | ||
| 219 | } | ||
| 220 | |||
| 221 | static bool | ||
| 222 | niss_makes_sense(void *param, void *cubedata, Alg *alg) | ||
| 223 | { | ||
| 224 | Step *s; | ||
| 225 | CubeData *data; | ||
| 226 | |||
| 227 | s = (Step *)param; | ||
| 228 | data = (CubeData *)cubedata; | ||
| 229 | |||
| 230 | if (s->final) | ||
| 231 | return false; | ||
| 232 | |||
| 233 | if (alg->len_normal == 0) | ||
| 234 | return true; | ||
| 235 | |||
| 236 | Move m = inverse_move(alg->move_normal[alg->len_normal-1]); | ||
| 237 | for (int i = 0; i < s->n_coord; i++) { | ||
| 238 | Move mm = transform_move(data->t[i], m); | ||
| 239 | uint64_t u = move_coord(s->coord[i], mm, 0, NULL); | ||
| 240 | if (ptableval(s->pd[i], u) > 0) | ||
| 241 | return true; | ||
| 242 | } | ||
| 243 | |||
| 244 | return false; | ||
| 245 | } | ||
| 246 | |||
| 247 | static Solver * | ||
| 248 | new_stepsolver_nocheckstop(Step *step) | ||
| 249 | { | ||
| 250 | Solver *solver; | ||
| 251 | |||
| 252 | solver = malloc(sizeof(Solver)); | ||
| 253 | |||
| 254 | solver->moveset = step->moveset; | ||
| 255 | solver->param = step; | ||
| 256 | |||
| 257 | solver->apply_alg = apply_alg_cubedata; | ||
| 258 | solver->prepare_cube = prepare_cube; | ||
| 259 | solver->is_solved = is_solved_step; | ||
| 260 | solver->validate_solution = validate_solution; | ||
| 261 | solver->alloc_cubedata = alloc_cubedata; | ||
| 262 | solver->copy_cubedata = copy_cubedata; | ||
| 263 | solver->free_cubedata = free_cubedata; | ||
| 264 | solver->invert_cube = invert_cubedata; | ||
| 265 | solver->niss_makes_sense = niss_makes_sense; | ||
| 266 | |||
| 267 | return solver; | ||
| 268 | } | ||
| 269 | |||
| 270 | Solver * | ||
| 271 | new_stepsolver_eager(Step *step) | ||
| 272 | { | ||
| 273 | Solver *solver; | ||
| 274 | |||
| 275 | solver = new_stepsolver_nocheckstop(step); | ||
| 276 | solver->move_check_stop = move_check_stop_eager; | ||
| 277 | |||
| 278 | return solver; | ||
| 279 | } | ||
| 280 | |||
| 281 | Solver * | ||
| 282 | new_stepsolver_lazy(Step *step) | ||
| 283 | { | ||
| 284 | Solver *solver; | ||
| 285 | |||
| 286 | solver = new_stepsolver_nocheckstop(step); | ||
| 287 | solver->move_check_stop = move_check_stop_lazy; | ||
| 288 | |||
| 289 | return solver; | ||
| 290 | } | ||
| 291 | |||
| 292 | void | ||
| 293 | free_stepsolver(Solver *solver) | ||
| 294 | { | ||
| 295 | free(solver); | ||
| 296 | } | ||
diff --git a/src/solver_step.h b/src/solver_step.h new file mode 100644 index 0000000..f68d077 --- /dev/null +++ b/src/solver_step.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef SOLVER_STEP_H | ||
| 2 | #define SOLVER_STEP_H | ||
| 3 | |||
| 4 | #include "cube.h" | ||
| 5 | #include "solve.h" | ||
| 6 | #include "steps.h" | ||
| 7 | |||
| 8 | Solver *new_stepsolver_eager(Step *); | ||
| 9 | Solver *new_stepsolver_lazy(Step *); | ||
| 10 | void free_stepsolver(Solver *); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/src/steps.c b/src/steps.c index 2f5fd2c..cdba763 100644 --- a/src/steps.c +++ b/src/steps.c | |||
| @@ -106,11 +106,12 @@ check_htr(Cube *cube) | |||
| 106 | return true; | 106 | return true; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | bool | 109 | Alg * |
| 110 | validate_singlecw_ending(Alg *alg) | 110 | validate_singlecw_ending(Alg *alg) |
| 111 | { | 111 | { |
| 112 | int i; | 112 | int i; |
| 113 | bool nor, inv; | 113 | bool nor, inv; |
| 114 | Alg *ret; | ||
| 114 | Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; | 115 | Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; |
| 115 | 116 | ||
| 116 | for (i = 0; i < alg->len; i++) { | 117 | for (i = 0; i < alg->len; i++) { |
| @@ -126,11 +127,19 @@ validate_singlecw_ending(Alg *alg) | |||
| 126 | nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); | 127 | nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); |
| 127 | inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); | 128 | inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); |
| 128 | 129 | ||
| 129 | return nor && inv; | 130 | if (nor && inv) { |
| 131 | ret = new_alg(""); | ||
| 132 | copy_alg(alg, ret); | ||
| 133 | } else { | ||
| 134 | ret = NULL; | ||
| 135 | } | ||
| 136 | |||
| 137 | return ret; | ||
| 130 | } | 138 | } |
| 131 | 139 | ||
| 132 | /* Public functions **********************************************************/ | 140 | /* Public functions **********************************************************/ |
| 133 | 141 | ||
| 142 | /* | ||
| 134 | void | 143 | void |
| 135 | compute_ind(Step *s, Cube *cube, Movable *ind) | 144 | compute_ind(Step *s, Cube *cube, Movable *ind) |
| 136 | { | 145 | { |
| @@ -147,6 +156,7 @@ compute_ind(Step *s, Cube *cube, Movable *ind) | |||
| 147 | ind[i].t = transform_trans(tt, t); | 156 | ind[i].t = transform_trans(tt, t); |
| 148 | } | 157 | } |
| 149 | } | 158 | } |
| 159 | */ | ||
| 150 | 160 | ||
| 151 | void | 161 | void |
| 152 | prepare_cs(ChoiceStep *cs, SolveOptions *opts) | 162 | prepare_cs(ChoiceStep *cs, SolveOptions *opts) |
diff --git a/src/steps.h b/src/steps.h index 0511b27..206f8b4 100644 --- a/src/steps.h +++ b/src/steps.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define STEPS_H | 2 | #define STEPS_H |
| 3 | 3 | ||
| 4 | #include "pruning.h" | 4 | #include "pruning.h" |
| 5 | #include "movesets.h" | ||
| 5 | 6 | ||
| 6 | bool check_centers(Cube *cube); | 7 | bool check_centers(Cube *cube); |
| 7 | bool check_coud_HTM(Cube *cube); | 8 | bool check_coud_HTM(Cube *cube); |
| @@ -13,10 +14,10 @@ bool check_cornershtr(Cube *cube); | |||
| 13 | bool check_eofb(Cube *cube); | 14 | bool check_eofb(Cube *cube); |
| 14 | bool check_drud(Cube *cube); | 15 | bool check_drud(Cube *cube); |
| 15 | bool check_htr(Cube *cube); | 16 | bool check_htr(Cube *cube); |
| 16 | void compute_ind(Step *a, Cube *cube, Movable *ind); | 17 | /*void compute_ind(Step *a, Cube *cube, Movable *ind);*/ |
| 17 | void prepare_cs(ChoiceStep *cs, SolveOptions *opts); | 18 | void prepare_cs(ChoiceStep *cs, SolveOptions *opts); |
| 18 | bool always_valid(Alg *alg); | 19 | bool always_valid(Alg *alg); |
| 19 | bool validate_singlecw_ending(Alg *alg); | 20 | Alg * validate_singlecw_ending(Alg *alg); |
| 20 | 21 | ||
| 21 | #ifndef STEPS_C | 22 | #ifndef STEPS_C |
| 22 | 23 | ||
diff --git a/src/threader_eager.c b/src/threader_eager.c new file mode 100644 index 0000000..7013518 --- /dev/null +++ b/src/threader_eager.c | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | #include <pthread.h> | ||
| 2 | #include "threader_eager.h" | ||
| 3 | |||
| 4 | typedef struct { | ||
| 5 | AlgList * sols; | ||
| 6 | pthread_mutex_t * sols_mutex; | ||
| 7 | } ThreadData; | ||
| 8 | |||
| 9 | typedef struct { | ||
| 10 | DfsArg * arg; | ||
| 11 | Solver * solver; | ||
| 12 | Threader * threader; | ||
| 13 | AlgList * starts; | ||
| 14 | AlgListNode ** node; | ||
| 15 | pthread_mutex_t * start_mutex; | ||
| 16 | } ThreadInitData; | ||
| 17 | |||
| 18 | static void append_sol(Alg *, void *); | ||
| 19 | static void * instance_thread(void *); | ||
| 20 | static void dispatch(DfsArg *, AlgList *, Solver *, Threader *); | ||
| 21 | static AlgList * possible_starts(DfsArg *, Solver *); | ||
| 22 | static int get_nsol(void *); | ||
| 23 | |||
| 24 | Threader threader_eager = { | ||
| 25 | .append_sol = append_sol, | ||
| 26 | .dispatch = dispatch, | ||
| 27 | .get_nsol = get_nsol, | ||
| 28 | }; | ||
| 29 | |||
| 30 | static void | ||
| 31 | append_sol(Alg *alg, void *threaddata) | ||
| 32 | { | ||
| 33 | ThreadData *td = (ThreadData *)threaddata; | ||
| 34 | |||
| 35 | pthread_mutex_lock(td->sols_mutex); | ||
| 36 | append_alg(td->sols, alg); | ||
| 37 | pthread_mutex_unlock(td->sols_mutex); | ||
| 38 | } | ||
| 39 | |||
| 40 | static AlgList * | ||
| 41 | possible_starts(DfsArg *arg, Solver *solver) | ||
| 42 | { | ||
| 43 | AlgList *ret = new_alglist(); | ||
| 44 | |||
| 45 | if (solver->is_solved(solver->param, arg->cubedata)) { | ||
| 46 | if (arg->opts->min_moves == 0) | ||
| 47 | append_sol(new_alg(""), arg->threaddata); | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | for (int i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 52 | Move m = solver->moveset->sorted_moves[i]; | ||
| 53 | Alg *alg = new_alg(""); | ||
| 54 | append_move(alg, m, false); | ||
| 55 | append_alg(ret, alg); | ||
| 56 | free_alg(alg); | ||
| 57 | |||
| 58 | /* TODO: check if step not final */ | ||
| 59 | if (arg->opts->can_niss) { | ||
| 60 | alg = new_alg(""); | ||
| 61 | append_move(alg, m, true); | ||
| 62 | append_alg(ret, alg); | ||
| 63 | free_alg(alg); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | return ret; | ||
| 68 | } | ||
| 69 | |||
| 70 | static void * | ||
| 71 | instance_thread(void *arg) | ||
| 72 | { | ||
| 73 | ThreadInitData *tid = (ThreadInitData *)arg; | ||
| 74 | |||
| 75 | while (true) { | ||
| 76 | pthread_mutex_lock(tid->start_mutex); | ||
| 77 | AlgListNode *node = *(tid->node); | ||
| 78 | if (node == NULL) { | ||
| 79 | pthread_mutex_unlock(tid->start_mutex); | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | *(tid->node) = (*(tid->node))->next; | ||
| 83 | pthread_mutex_unlock(tid->start_mutex); | ||
| 84 | |||
| 85 | void *data = tid->solver->alloc_cubedata(tid->solver->param); | ||
| 86 | tid->solver->copy_cubedata( | ||
| 87 | tid->solver->param, tid->arg->cubedata, data); | ||
| 88 | tid->solver->apply_alg( | ||
| 89 | tid->solver->param, data, node->alg); | ||
| 90 | bool inv = node->alg->inv[node->alg->len-1]; | ||
| 91 | if (inv) | ||
| 92 | tid->solver->invert_cube( | ||
| 93 | tid->solver->param, data); | ||
| 94 | |||
| 95 | DfsArg newarg; | ||
| 96 | newarg.cubedata = data; | ||
| 97 | newarg.threaddata = tid->arg->threaddata; | ||
| 98 | newarg.opts = tid->arg->opts; | ||
| 99 | newarg.d = tid->arg->d; | ||
| 100 | newarg.niss = inv; | ||
| 101 | newarg.current_alg = new_alg(""); | ||
| 102 | copy_alg(node->alg, newarg.current_alg); | ||
| 103 | |||
| 104 | dfs(&newarg, tid->solver, tid->threader); | ||
| 105 | |||
| 106 | tid->solver->free_cubedata(tid->solver->param, data); | ||
| 107 | free_alg(newarg.current_alg); | ||
| 108 | } | ||
| 109 | |||
| 110 | return NULL; | ||
| 111 | } | ||
| 112 | |||
| 113 | static void | ||
| 114 | dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader) | ||
| 115 | { | ||
| 116 | int nthreads = arg->opts->nthreads; | ||
| 117 | ThreadInitData tid[nthreads]; | ||
| 118 | pthread_t t[nthreads]; | ||
| 119 | |||
| 120 | pthread_mutex_t *sols_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 121 | pthread_mutex_init(sols_mutex, NULL); | ||
| 122 | |||
| 123 | arg->threaddata = malloc(sizeof(ThreadData)); | ||
| 124 | ThreadData *td = (ThreadData *)arg->threaddata; | ||
| 125 | td->sols = sols; | ||
| 126 | td->sols_mutex = sols_mutex; | ||
| 127 | |||
| 128 | AlgList *starts = possible_starts(arg, solver); | ||
| 129 | AlgListNode *node = starts->first; | ||
| 130 | pthread_mutex_t *start_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 131 | pthread_mutex_init(start_mutex, NULL); | ||
| 132 | for (int i = 0; i < nthreads; i++) { | ||
| 133 | tid[i].arg = arg; | ||
| 134 | tid[i].solver = solver; | ||
| 135 | tid[i].threader = threader; | ||
| 136 | tid[i].starts = starts; | ||
| 137 | tid[i].node = &node; | ||
| 138 | tid[i].start_mutex = start_mutex; | ||
| 139 | |||
| 140 | pthread_create(&t[i], NULL, instance_thread, &tid[i]); | ||
| 141 | } | ||
| 142 | |||
| 143 | for (int i = 0; i < nthreads; i++) | ||
| 144 | pthread_join(t[i], NULL); | ||
| 145 | |||
| 146 | free(td); | ||
| 147 | free(sols_mutex); | ||
| 148 | free_alglist(starts); | ||
| 149 | free(start_mutex); | ||
| 150 | } | ||
| 151 | |||
| 152 | static int | ||
| 153 | get_nsol(void *threaddata) | ||
| 154 | { | ||
| 155 | ThreadData *td = (ThreadData *)threaddata; | ||
| 156 | |||
| 157 | pthread_mutex_lock(td->sols_mutex); | ||
| 158 | int n = td->sols->len; | ||
| 159 | pthread_mutex_unlock(td->sols_mutex); | ||
| 160 | |||
| 161 | return n; | ||
| 162 | } | ||
diff --git a/src/threader_eager.h b/src/threader_eager.h new file mode 100644 index 0000000..e39b27f --- /dev/null +++ b/src/threader_eager.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef THREADER_EAGER_H | ||
| 2 | #define THREADER_EAGER_H | ||
| 3 | |||
| 4 | #include "solve.h" | ||
| 5 | |||
| 6 | extern Threader threader_eager; | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/src/threader_single.c b/src/threader_single.c new file mode 100644 index 0000000..232835d --- /dev/null +++ b/src/threader_single.c | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #include "threader_single.h" | ||
| 2 | |||
| 3 | static void append_sol(Alg *, void *); | ||
| 4 | static void dispatch(DfsArg *, AlgList *, Solver *, Threader *); | ||
| 5 | static int get_nsol(void *); | ||
| 6 | |||
| 7 | Threader threader_single = { | ||
| 8 | .append_sol = append_sol, | ||
| 9 | .dispatch = dispatch, | ||
| 10 | .get_nsol = get_nsol, | ||
| 11 | }; | ||
| 12 | |||
| 13 | static void | ||
| 14 | append_sol(Alg *alg, void *threaddata) | ||
| 15 | { | ||
| 16 | append_alg((AlgList *)threaddata, alg); | ||
| 17 | } | ||
| 18 | |||
| 19 | static void | ||
| 20 | dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader) | ||
| 21 | { | ||
| 22 | arg->threaddata = sols; | ||
| 23 | arg->niss = false; | ||
| 24 | arg->current_alg = new_alg(""); | ||
| 25 | |||
| 26 | dfs(arg, solver, threader); | ||
| 27 | |||
| 28 | free_alg(arg->current_alg); | ||
| 29 | } | ||
| 30 | |||
| 31 | static int | ||
| 32 | get_nsol(void *threaddata) | ||
| 33 | { | ||
| 34 | return ((AlgList *)threaddata)->len; | ||
| 35 | } | ||
diff --git a/src/threader_single.h b/src/threader_single.h new file mode 100644 index 0000000..2c0bfab --- /dev/null +++ b/src/threader_single.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef THREADER_SINGLE_H | ||
| 2 | #define THREADER_SINGLE_H | ||
| 3 | |||
| 4 | #include "solve.h" | ||
| 5 | |||
| 6 | extern Threader threader_single; | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/tests/alg_tests.h b/tests/alg_tests.h index 518b33e..a24b51f 100644 --- a/tests/alg_tests.h +++ b/tests/alg_tests.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | extern Test test_append_move; | 7 | extern Test test_append_move; |
| 8 | extern Test test_new_alg; | 8 | extern Test test_new_alg; |
| 9 | /* | 9 | /* |
| 10 | extern Test remove_last_move; | ||
| 10 | extern Test test_compose_alg; | 11 | extern Test test_compose_alg; |
| 11 | extern Test test_inverse_alg; | 12 | extern Test test_inverse_alg; |
| 12 | extern Test test_on_inverse; | 13 | extern Test test_on_inverse; |
