1 #ifdef _WIN32
2 # include <malloc.h>
3 #endif
4 #include <string.h>
5 #include <stdlib.h>
6 #include <time.h>
7 #include <assert.h>
8 // XXX remove these two, needed for debugging only
9 #include <stdio.h>
10 #include <errno.h>
11
12 #include "librcps.h"
13 #include "../config.h"
14 #include "structs.h"
15 #include "decode.h"
16 #include "fitness.h"
17 #include "initial.h"
18 #include "repair.h"
19 #include "lib.h"
20 #include "ops.h"
21
22 #define DEFAULT_POP_SIZE 600
23 #define DEFAULT_MUT_MODE 500
24 #define DEFAULT_MUT_SCHED 500
25 #define DEFAULT_MUT_ALT 500
26
rcps_version()27 const char *rcps_version() {
28 return VERSION;
29 }
30
rcps_problem_new()31 struct rcps_problem* rcps_problem_new() {
32 struct rcps_problem *ret;
33 ret = (struct rcps_problem*)malloc(sizeof(struct rcps_problem));
34 if (ret) {
35 memset(ret, 0, sizeof(struct rcps_problem));
36 }
37 return ret;
38 }
39
rcps_problem_free(struct rcps_problem * p)40 void rcps_problem_free(struct rcps_problem *p) {
41 int i;
42 for (i = 0; i < p->resource_count; i++) {
43 rcps_resource_free(p->resources[i]);
44 }
45 free(p->resources);
46 for (i = 0; i < p->job_count; i++) {
47 rcps_job_free(p->jobs[i]);
48 }
49 free(p->jobs);
50 free(p);
51 }
52
rcps_problem_setfitness_mode(struct rcps_problem * p,int mode)53 void rcps_problem_setfitness_mode(struct rcps_problem *p, int mode) {
54 p->fitness_mode = mode;
55 }
56
rcps_problem_set_weight_callback(struct rcps_problem * p,int (* weight_callback)(int time,int duration,struct rcps_fitness * nominal_weight,void * arg,void * fitness_arg))57 void rcps_problem_set_weight_callback(struct rcps_problem *p,
58 int (*weight_callback)(int time, int duration, struct rcps_fitness *nominal_weight, void *arg, void *fitness_arg)) {
59 p->weight_callback = weight_callback;
60 }
61
rcps_problem_set_fitness_callback(struct rcps_problem * p,void * (* fitness_callback_init)(void * arg),void * init_arg,int (* fitness_callback_result)(struct rcps_fitness * fitness,void * arg))62 void rcps_problem_set_fitness_callback(struct rcps_problem *p,
63 void* (*fitness_callback_init)(void *arg),
64 void *init_arg,
65 int (*fitness_callback_result)(struct rcps_fitness *fitness, void *arg)) {
66 p->fitness_callback_init = fitness_callback_init;
67 p->fitness_init_arg = init_arg;
68 p->fitness_callback_result = fitness_callback_result;
69 }
70
rcps_resource_new()71 struct rcps_resource* rcps_resource_new() {
72 struct rcps_resource *ret;
73 ret = (struct rcps_resource*)malloc(sizeof(struct rcps_resource));
74 if (ret) {
75 memset(ret, 0, sizeof(struct rcps_resource));
76 }
77 return ret;
78 }
79
rcps_resource_free(struct rcps_resource * r)80 void rcps_resource_free(struct rcps_resource *r) {
81 free(r->name);
82 free(r);
83 }
84
rcps_resource_getname(struct rcps_resource * r)85 char* rcps_resource_getname(struct rcps_resource *r) {
86 return r->name;
87 }
88
rcps_resource_setname(struct rcps_resource * r,const char * name)89 void rcps_resource_setname(struct rcps_resource *r, const char *name) {
90 r->name = (char*)malloc((strlen(name)+1)*sizeof(char));
91 strcpy(r->name, name);
92 }
93
rcps_resource_gettype(struct rcps_resource * r)94 int rcps_resource_gettype(struct rcps_resource *r) {
95 return r->type;
96 }
97
rcps_resource_settype(struct rcps_resource * r,int type)98 void rcps_resource_settype(struct rcps_resource *r, int type) {
99 // XXX assert valid values in these functions
100 r->type = type;
101 }
102
rcps_resource_getavail(struct rcps_resource * r)103 int rcps_resource_getavail(struct rcps_resource *r) {
104 return r->avail;
105 }
106
rcps_resource_setavail(struct rcps_resource * r,int avail)107 void rcps_resource_setavail(struct rcps_resource *r, int avail) {
108 r->avail = avail;
109 }
110
rcps_resource_add(struct rcps_problem * p,struct rcps_resource * r)111 void rcps_resource_add(struct rcps_problem *p, struct rcps_resource *r) {
112 p->resource_count++;
113 p->resources = (struct rcps_resource**)
114 realloc(p->resources, p->resource_count *
115 sizeof(struct rcps_resource*));
116 p->resources[p->resource_count-1] = r;
117 }
118
rcps_resource_count(struct rcps_problem * p)119 int rcps_resource_count(struct rcps_problem *p) {
120 return p->resource_count;
121 }
122
rcps_resource_get(struct rcps_problem * p,int r)123 struct rcps_resource* rcps_resource_get(struct rcps_problem *p, int r) {
124 return p->resources[r];
125 }
126
rcps_resource_getbyname(struct rcps_problem * p,char * name)127 struct rcps_resource* rcps_resource_getbyname(struct rcps_problem *p,
128 char *name) {
129 int i;
130 for (i = 0; i < p->resource_count; i++) {
131 struct rcps_resource *cr = p->resources[i];
132 if (strcmp(cr->name, name) == 0) {
133 return cr;
134 }
135 }
136 return NULL;
137 }
138
rcps_resource_remove(struct rcps_problem * p,int r)139 struct rcps_resource* rcps_resource_remove(struct rcps_problem *p, int r) {
140 struct rcps_resource *ret = p->resources[r];
141 memmove(p->resources[r], p->resources[r+1],
142 (p->resource_count-r-1)*sizeof(struct rcps_problem*));
143 p->resource_count--;
144 return ret;
145 }
146
rcps_job_new()147 struct rcps_job* rcps_job_new() {
148 struct rcps_job *ret = (struct rcps_job*)malloc(
149 sizeof(struct rcps_job));
150 if (ret) {
151 memset(ret, 0, sizeof(struct rcps_job));
152 ret->res_start = RCPS_UNDEF;
153 ret->res_mode = RCPS_UNDEF;
154 }
155 return ret;
156 }
157
rcps_job_free(struct rcps_job * j)158 void rcps_job_free(struct rcps_job *j) {
159 free(j->name);
160 free(j->successors);
161 free(j->successor_types);
162 free(j->predeccessors);
163 free(j->modes);
164 free(j);
165 }
166
rcps_job_getname(struct rcps_job * j)167 char* rcps_job_getname(struct rcps_job *j) {
168 return j->name;
169 }
170
rcps_job_setname(struct rcps_job * j,const char * name)171 void rcps_job_setname(struct rcps_job *j, const char *name) {
172 j->name = (char*)malloc((strlen(name)+1)*sizeof(char));
173 strcpy(j->name, name);
174 }
175
rcps_job_setearliest_start(struct rcps_job * j,int time)176 void rcps_job_setearliest_start(struct rcps_job *j, int time) {
177 j->earliest_start = time;
178 }
179
rcps_job_getearliest_start(struct rcps_job * j)180 int rcps_job_getearliest_start(struct rcps_job *j) {
181 return j->earliest_start;
182 }
183
184
rcps_job_setweight(struct rcps_job * j,int weight)185 void rcps_job_setweight(struct rcps_job *j, int weight) {
186 j->weight = weight;
187 }
188
189 /* add a job struct to a problem */
190 void rcps_job_add(struct rcps_problem *p, struct rcps_job *j);
191
rcps_job_add(struct rcps_problem * p,struct rcps_job * j)192 void rcps_job_add(struct rcps_problem *p, struct rcps_job *j) {
193 p->job_count++;
194 p->jobs = (struct rcps_job**)
195 realloc(p->jobs, p->job_count*sizeof(struct rcps_job*));
196 p->jobs[p->job_count-1] = j;
197 }
198
rcps_job_count(struct rcps_problem * p)199 int rcps_job_count(struct rcps_problem *p) {
200 return p->job_count;
201 }
202
rcps_job_get(struct rcps_problem * p,int j)203 struct rcps_job* rcps_job_get(struct rcps_problem *p, int j) {
204 return p->jobs[j];
205 }
206
rcps_job_getbyname(struct rcps_problem * p,char * name)207 struct rcps_job* rcps_job_getbyname(struct rcps_problem *p, char *name) {
208 int i;
209 for (i = 0; i < p->job_count; i++) {
210 struct rcps_job *cj = p->jobs[i];
211 if (strcmp(cj->name, name) == 0) {
212 return cj;
213 }
214 }
215 return NULL;
216 }
217
rcps_job_remove(struct rcps_problem * p,int j)218 struct rcps_job* rcps_job_remove(struct rcps_problem *p, int j) {
219 struct rcps_job *ret = p->jobs[j];
220 memmove(p->jobs[j], p->jobs[j+1],
221 (p->job_count-j-1)*sizeof(struct rcps_problem*));
222 p->job_count--;
223 return ret;
224 }
225
rcps_job_successor_add(struct rcps_job * j,struct rcps_job * s,int type)226 void rcps_job_successor_add(struct rcps_job *j, struct rcps_job *s, int type) {
227 assert(type >= SUCCESSOR_FINISH_START);
228 assert(type <= SUCCESSOR_FINISH_FINISH);
229 j->successor_count++;
230 j->successors = (struct rcps_job**)
231 realloc(j->successors, j->successor_count *
232 sizeof(struct rcps_job*));
233 j->successor_types = (int*)
234 realloc(j->successor_types, j->successor_count *
235 sizeof(int));
236 j->successors[j->successor_count-1] = s;
237 j->successor_types[j->successor_count-1] = type;
238 }
239
rcps_job_predeccessor_add(struct rcps_job * j,struct rcps_job * p,int type)240 void rcps_job_predeccessor_add(struct rcps_job *j, struct rcps_job *p, int type) {
241 j->predeccessor_count++;
242 j->predeccessors = (struct rcps_job**)
243 realloc(j->predeccessors, j->predeccessor_count *
244 sizeof(struct rcps_job*));
245 j->predeccessor_types = (int*)
246 realloc(j->predeccessor_types, j->predeccessor_count *
247 sizeof(int));
248 j->predeccessors[j->predeccessor_count-1] = p;
249 j->predeccessor_types[j->predeccessor_count-1] = type;
250 }
251
rcps_job_successor_count(struct rcps_job * j)252 int rcps_job_successor_count(struct rcps_job *j) {
253 return j->successor_count;
254 }
255
rcps_job_successor_get(struct rcps_job * j,int s)256 struct rcps_job* rcps_job_successor_get(struct rcps_job *j, int s) {
257 return j->successors[s];
258 }
259
rcps_job_successor_type_get(struct rcps_job * j,int s)260 int rcps_job_successor_type_get(struct rcps_job *j, int s) {
261 return j->successor_types[s];
262 }
263
rcps_job_successor_remove(struct rcps_job * j,int s)264 struct rcps_job* rcps_job_successor_remove(struct rcps_job *j, int s) {
265 struct rcps_job *ret = j->successors[s];
266 memmove(&j->successors[s], &j->successors[s+1],
267 (j->successor_count-s-1)*sizeof(struct rcps_job*));
268 memmove(&j->successor_types[s], &j->successor_types[s+1],
269 (j->successor_count-s-1)*sizeof(struct rcps_job*));
270 j->successor_count--;
271 return ret;
272 }
273
rcps_job_getstart_res(struct rcps_job * j)274 int rcps_job_getstart_res(struct rcps_job *j) {
275 return j->res_start;
276 }
277
rcps_job_getmode_res(struct rcps_job * j)278 int rcps_job_getmode_res(struct rcps_job *j) {
279 return j->res_mode;
280 }
281
rcps_mode_new()282 struct rcps_mode* rcps_mode_new() {
283 struct rcps_mode *ret = (struct rcps_mode*)malloc(
284 sizeof(struct rcps_mode));
285 if (ret) {
286 memset(ret, 0, sizeof(struct rcps_mode));
287 }
288 return ret;
289 }
290
rcps_mode_free(struct rcps_mode * m)291 void rcps_mode_free(struct rcps_mode *m) {
292 int i;
293 for (i = 0; i < m->request_count; i++) {
294 rcps_request_free(m->requests[i]);
295 }
296 free(m->requests);
297 free(m);
298 }
299
rcps_mode_getduration(struct rcps_mode * m)300 int rcps_mode_getduration(struct rcps_mode *m) {
301 return m->duration;
302 }
303
rcps_mode_setduration(struct rcps_mode * m,int d)304 void rcps_mode_setduration(struct rcps_mode *m, int d) {
305 m->duration = d;
306 }
307
rcps_mode_set_cbarg(struct rcps_mode * m,void * arg)308 void rcps_mode_set_cbarg(struct rcps_mode *m, void *arg) {
309 m->cb_arg = arg;
310 }
311
rcps_mode_get_cbarg(struct rcps_mode * m)312 void* rcps_mode_get_cbarg(struct rcps_mode *m) {
313 return m->cb_arg;
314 }
315
rcps_mode_set_weight_cbarg(struct rcps_mode * m,void * arg)316 void rcps_mode_set_weight_cbarg(struct rcps_mode *m, void *arg) {
317 m->weight_cb_arg = arg;
318 }
319
rcps_mode_get_weight_cbarg(struct rcps_mode * m)320 void *rcps_mode_get_weight_cbarg(struct rcps_mode *m) {
321 return m->weight_cb_arg;
322 }
323
rcps_mode_add(struct rcps_job * j,struct rcps_mode * m)324 void rcps_mode_add(struct rcps_job *j, struct rcps_mode *m) {
325 j->mode_count++;
326 j->modes = (struct rcps_mode**)
327 realloc(j->modes, j->mode_count *
328 sizeof(struct rcps_mode*));
329 j->modes[j->mode_count-1] = m;
330 }
331
rcps_mode_count(struct rcps_job * j)332 int rcps_mode_count(struct rcps_job *j) {
333 return j->mode_count;
334 }
335
rcps_mode_get(struct rcps_job * j,int m)336 struct rcps_mode* rcps_mode_get(struct rcps_job *j, int m) {
337 return j->modes[m];
338 }
339
rcps_mode_remove(struct rcps_job * j,int m)340 struct rcps_mode* rcps_mode_remove(struct rcps_job *j, int m) {
341 struct rcps_mode *ret = j->modes[m];
342 memmove(j->modes[m], j->modes[m+1],
343 (j->mode_count-m-1)*sizeof(struct rcps_mode*));
344 j->mode_count--;
345 return ret;
346 }
347
rcps_request_new()348 struct rcps_request* rcps_request_new() {
349 struct rcps_request *ret = (struct rcps_request*)malloc(
350 sizeof(struct rcps_request));
351 if (ret) {
352 memset(ret, 0, sizeof(struct rcps_request));
353 ret->res_alternative = RCPS_UNDEF;
354 }
355 return ret;
356 }
357
rcps_request_free(struct rcps_request * r)358 void rcps_request_free(struct rcps_request *r) {
359 free(r);
360 }
361
rcps_request_add(struct rcps_mode * m,struct rcps_request * r)362 void rcps_request_add(struct rcps_mode *m, struct rcps_request *r) {
363 m->request_count++;
364 m->requests = (struct rcps_request**)
365 realloc(m->requests, m->request_count *
366 sizeof(struct rcps_request*));
367 m->requests[m->request_count-1] = r;
368 }
369
rcps_request_count(struct rcps_mode * m)370 int rcps_request_count(struct rcps_mode *m) {
371 return m->request_count;
372 }
373
rcps_request_get(struct rcps_mode * m,int r)374 struct rcps_request* rcps_request_get(struct rcps_mode *m, int r) {
375 return m->requests[r];
376 }
377
rcps_request_remove(struct rcps_mode * m,int r)378 struct rcps_request* rcps_request_remove(struct rcps_mode *m, int r) {
379 struct rcps_request *ret = m->requests[r];
380 memmove(m->requests[r], m->requests[r+1],
381 (m->request_count-r-1)*sizeof(struct rcps_request*));
382 m->request_count--;
383 return ret;
384 }
385
rcps_request_getalternative_res(struct rcps_request * r)386 int rcps_request_getalternative_res(struct rcps_request *r) {
387 if (r->res_alternative < 0)
388 return 0;
389 return r->res_alternative;
390 }
391
rcps_alternative_new()392 struct rcps_alternative* rcps_alternative_new() {
393 struct rcps_alternative *ret = (struct rcps_alternative*)malloc(
394 sizeof(struct rcps_alternative));
395 if (ret) {
396 memset(ret, 0, sizeof(struct rcps_alternative));
397 }
398 return ret;
399 }
400
rcps_alternative_free(struct rcps_alternative * a)401 void rcps_alternative_free(struct rcps_alternative *a) {
402 free(a);
403 }
404
rcps_alternative_getamount(struct rcps_alternative * a)405 int rcps_alternative_getamount(struct rcps_alternative *a) {
406 return a->amount;
407 }
408
rcps_alternative_setamount(struct rcps_alternative * a,int m)409 void rcps_alternative_setamount(struct rcps_alternative *a, int m) {
410 a->amount = m;
411 }
412
rcps_alternative_getresource(struct rcps_alternative * a)413 struct rcps_resource* rcps_alternative_getresource(
414 struct rcps_alternative *a) {
415 return a->resource;
416 }
417
rcps_alternative_setresource(struct rcps_alternative * a,struct rcps_resource * r)418 void rcps_alternative_setresource(struct rcps_alternative *a,
419 struct rcps_resource *r) {
420 a->resource = r;
421 }
422
rcps_alternative_add(struct rcps_request * r,struct rcps_alternative * a)423 void rcps_alternative_add(struct rcps_request *r, struct rcps_alternative *a) {
424 r->alternative_count++;
425 r->alternatives = (struct rcps_alternative**)
426 realloc(r->alternatives, r->alternative_count *
427 sizeof(struct rcps_alternative*));
428 r->alternatives[r->alternative_count-1] = a;
429 }
430
rcps_alternative_count(struct rcps_request * r)431 int rcps_alternative_count(struct rcps_request *r) {
432 return r->alternative_count;
433 }
434
rcps_alternative_get(struct rcps_request * r,int a)435 struct rcps_alternative* rcps_alternative_get(struct rcps_request *r, int a) {
436 return r->alternatives[a];
437 }
438
rcps_alternative_remove(struct rcps_request * r,int a)439 struct rcps_alternative* rcps_alternative_remove(struct rcps_request *r,
440 int a) {
441 struct rcps_alternative *ret = r->alternatives[a];
442 memmove(r->alternatives[a], r->alternatives[a+1],
443 (r->alternative_count-a-1)*sizeof(struct rcps_alternative*));
444 r->alternative_count--;
445 return ret;
446 }
447
rcps_solver_getparam(struct rcps_solver * s,int param)448 int rcps_solver_getparam(struct rcps_solver *s, int param) {
449 switch (param) {
450 case SOLVER_PARAM_POPSIZE:
451 return s->pop_size;
452 break;
453 case SOLVER_PARAM_MUTSCHED:
454 return s->mut_sched;
455 break;
456 case SOLVER_PARAM_MUTMODE:
457 return s->mut_mode;
458 break;
459 case SOLVER_PARAM_MUTALT:
460 return s->mut_alt;
461 break;
462 case SOLVER_PARAM_JOBS:
463 return s->jobs;
464 break;
465 default:
466 return -1;
467 }
468 }
469
rcps_solver_setparam(struct rcps_solver * s,int param,int value)470 void rcps_solver_setparam(struct rcps_solver *s, int param, int value) {
471 switch (param) {
472 case SOLVER_PARAM_POPSIZE:
473 s->pop_size = value;
474 break;
475 case SOLVER_PARAM_MUTSCHED:
476 s->mut_sched = value;
477 break;
478 case SOLVER_PARAM_MUTMODE:
479 s->mut_mode = value;
480 break;
481 case SOLVER_PARAM_MUTALT:
482 s->mut_alt = value;
483 break;
484 case SOLVER_PARAM_JOBS:
485 #ifdef HAVE_PTHREAD
486 s->jobs = value;
487 #else
488 // XXX report that this is not supported
489 #endif
490 break;
491 // XXX return error by default
492 }
493 }
494
rcps_solver_new()495 struct rcps_solver* rcps_solver_new() {
496 struct rcps_solver *ret = (struct rcps_solver*)malloc(
497 sizeof(struct rcps_solver));
498 if (ret) {
499 memset(ret, 0, sizeof(struct rcps_solver));
500 }
501
502 ret->pop_size = DEFAULT_POP_SIZE;
503 ret->mut_sched = DEFAULT_MUT_SCHED;
504 ret->mut_mode = DEFAULT_MUT_MODE;
505 ret->mut_alt = DEFAULT_MUT_ALT;
506 ret->jobs = 1; // XXX autodetect on some platforms?
507 ret->reproductions = RCPS_UNDEF;
508 #ifdef HAVE_PTHREAD
509 // XXX look at error code, perhaps use an if to not use the lock if there is
510 // only one thread
511 //pthread_init();
512 assert(pthread_mutex_init(&ret->lock, NULL) == 0);
513 #endif
514 return ret;
515 }
516
rcps_solver_free(struct rcps_solver * s)517 void rcps_solver_free(struct rcps_solver *s) {
518 #ifdef HAVE_PTHREAD
519 // XXX look at error code
520 assert(pthread_mutex_destroy(&s->lock) == 0);
521 #endif
522 free(s);
523 }
524
525 static const char check_ok[] = "Ok";
526 static const char check_start_job_missing[] = "Start job missing";
527 static const char check_multiple_end_jobs[] = "Multiple end jobs";
528 static const char check_end_job_missing[] = "End job missing";
529 static const char check_circular_dependency[] = "Circular dependency";
530 static const char check_unknown_code[] = "Unknown error code";
531
rcps_error(int code)532 const char *rcps_error(int code) {
533 const char *r = check_unknown_code;
534 if (code == RCPS_CHECK_OK) {
535 r = check_ok;
536 } else if (code & RCPS_CHECK_START_JOB_MISSING) {
537 r = check_start_job_missing;
538 } else if (code & RCPS_CHECK_MULTIPLE_END_JOBS ) {
539 r = check_multiple_end_jobs;
540 } else if (code & RCPS_CHECK_END_JOB_MISSING ) {
541 r = check_end_job_missing;
542 } else if (code & RCPS_CHECK_CIRCULAR_DEPENDENCY ) {
543 r = check_circular_dependency;
544 }
545 return r;
546 }
547
job_compare(const void * a,const void * b)548 int job_compare(const void *a, const void *b) {
549 return (char *)a - (char *)b;
550 }
551
check_circulardependencies(struct rcps_job * job,struct slist * visited)552 int check_circulardependencies(struct rcps_job *job, struct slist *visited) {
553 int result = RCPS_CHECK_OK;
554 int i;
555 struct slist_node *n;
556 //printf("check_circulardependencies: %s visited: %i\n", job->name, slist_count(visited));
557 if ( slist_find(visited, job)) {
558 result = RCPS_CHECK_CIRCULAR_DEPENDENCY;
559 //printf("check_circulardependencies: %s already visited\n", job->name);
560 } else {
561 n = slist_node_new(job);
562 slist_add(visited, n);
563 for (i = 0; i < job->successor_count; ++i) {
564 result = check_circulardependencies( job->successors[ i ], visited );
565 if ( result != RCPS_CHECK_OK ) {
566 break;
567 }
568 }
569 // remove this job from the visited to avoid false positive
570 slist_unlink(visited, n);
571 slist_node_free(n, NULL);
572 }
573 return result;
574 }
575 /* all jobs must have successors except the end job, and all jobs must have predeccessors except the start job */
check_dependencies(struct rcps_problem * p)576 int check_dependencies(struct rcps_problem *p) {
577 int result = RCPS_CHECK_OK;
578 int end_count = 0;
579 int i, k;
580 struct rcps_job *start_job;
581 struct slist *visited;
582 struct slist *has_predecessor = slist_new(job_compare);
583
584 for (i = 0; i < p->job_count; ++i) {
585 struct rcps_job *j = p->jobs[ i ];
586 //printf("check_dependencies: job %s successors: %i\n", j->name, j->successor_count);
587 if (j->successor_count == 0) {
588 ++end_count;
589 } else {
590 for (k = 0; k < j->successor_count; ++k) {
591 //printf("check_dependencies: job %s successor[%i] = %s\n", j->name, k, j->successors[k]->name);
592 slist_add(has_predecessor, slist_node_new(j->successors[k]));
593 }
594 }
595 }
596 if (end_count > 1) {
597 result += RCPS_CHECK_MULTIPLE_END_JOBS;
598 } else if (end_count == 0) {
599 result += RCPS_CHECK_END_JOB_MISSING;
600 }
601 if (result == RCPS_CHECK_OK) {
602 start_job = 0;
603 for (i = 0; i < p->job_count; ++i) {
604 if (!slist_find(has_predecessor, p->jobs[i])) {
605 start_job = p->jobs[i];
606 }
607 }
608 if (start_job) {
609 /* All other jobs should be successors of the start job */
610 //printf("check_dependencies: check circular\n");
611 visited = slist_new(job_compare);
612 result += check_circulardependencies(start_job, visited);
613 slist_free(visited, NULL);
614 } else {
615 result += RCPS_CHECK_START_JOB_MISSING;
616 }
617
618 }
619 slist_free(has_predecessor, NULL);
620 //printf("check_dependencies: result=%i\n", result);
621 return result;
622 }
623
rcps_check(struct rcps_problem * p)624 int rcps_check(struct rcps_problem *p) {
625 /* XXX check for structural problems */
626 int result = RCPS_CHECK_OK;
627 result = check_dependencies( p );
628 printf("rcps_check: result='%s'\n", rcps_error(result));
629 return result;
630 }
631
rcps_fitness_cmp(const struct rcps_fitness * a,const struct rcps_fitness * b)632 int rcps_fitness_cmp(const struct rcps_fitness *a, const struct rcps_fitness *b) {
633 return a->group == b->group ? a->weight - b->weight : a->group - b->group;
634 }
635
individual_cmp(const void * a,const void * b)636 int individual_cmp(const void *a, const void *b) {
637 return rcps_fitness_cmp(&(((struct rcps_individual*)a)->fitness), &(((struct rcps_individual*)b)->fitness));
638 }
639
add_individual(struct rcps_individual * ind,struct rcps_population * pop)640 void add_individual(struct rcps_individual *ind, struct rcps_population *pop) {
641 struct slist_node *n;
642 struct rcps_individual *i;
643
644 n = slist_node_new(ind);
645 slist_add(pop->individuals, n);
646 ++pop->size;
647 // what is this? (da)
648 while (slist_count(pop->individuals) > pop->size) {
649 n = slist_last(pop->individuals);
650 if (!n) {
651 // XXX what the fuck is that?
652 fprintf(stderr, "uhu, no one there?\n");
653 }
654 slist_unlink(pop->individuals, n);
655 i = (struct rcps_individual*)slist_node_getdata(n);
656 slist_node_free(n, NULL);
657 free(i->genome.schedule);
658 free(i->genome.modes);
659 free(i->genome.alternatives);
660 free(i);
661 }
662 }
663
new_population(struct rcps_solver * s,struct rcps_problem * problem)664 struct rcps_population *new_population(struct rcps_solver *s,
665 struct rcps_problem *problem) {
666 struct rcps_population *pop;
667 struct rcps_individual *ind;
668 int i;
669 int lcount = 0;
670 struct rcps_fitness best_fitness;
671 best_fitness.group = FITNESS_MAX_GROUP;
672 best_fitness.weight = 0;
673
674 pop = (struct rcps_population*)malloc(sizeof(struct rcps_population));
675 pop->individuals = slist_new(individual_cmp);
676 pop->size = 0;
677 for (i = 0; i < s->pop_size; i++) {
678 ind = (struct rcps_individual*)malloc(sizeof(struct rcps_individual));
679 initial(problem, &ind->genome);
680 if (repair(problem, &ind->genome)) {
681 struct rcps_phenotype *pheno = decode(s, problem,
682 &ind->genome);
683 ind->fitness = fitness(problem, &ind->genome, pheno);
684 if (rcps_fitness_cmp(&(ind->fitness), &best_fitness) < 0) {
685 best_fitness = ind->fitness;
686 }
687 add_individual(ind, pop);
688 }
689 else {
690 // XXX somehow track this and abort with an error if we never add a
691 // valid individual
692 free(ind->genome.schedule);
693 free(ind->genome.modes);
694 free(ind->genome.alternatives);
695 free(ind);
696 i--;
697 }
698 if (s->progress_callback) {
699 if (i >= (lcount + s->cb_steps)) {
700 if (s->progress_callback(0, best_fitness, s->cb_arg)) {
701 return pop;
702 }
703 lcount = i;
704 }
705 }
706 }
707 return pop;
708 }
709
710
run_alg(struct rcps_solver * s,struct rcps_problem * p)711 int run_alg(struct rcps_solver *s, struct rcps_problem *p) {
712 /* run the algorithm */
713 int end = 0;
714 int count = 0;
715 int tcount = 0;
716 int lcount = 0;
717 struct rcps_fitness last_fitness;
718 int last_overuse = 1;
719 int breakoff_count = 0;
720 int desperate = 0;
721
722 last_fitness.group = FITNESS_MAX_GROUP;
723 last_fitness.weight = 0;
724
725 fflush(stderr);
726
727 // make this configurable
728 breakoff_count = 100000 / s->jobs;
729
730 #ifdef HAVE_PTHREAD
731 // XXX look at error code
732 pthread_mutex_lock(&s->lock);
733 #endif
734 do {
735 // breed
736 int i,j;
737 int son_overuse, daughter_overuse, best_overuse;
738 struct rcps_individual *father;
739 struct rcps_individual *mother;
740 struct rcps_individual *son;
741 struct rcps_individual *daughter;
742 struct rcps_phenotype *pheno;
743 struct rcps_fitness f1, f2;
744 f1.group = FITNESS_MAX_GROUP;
745 f1.weight = 0;
746 f2 = f1;
747
748 son = (struct rcps_individual*)malloc(sizeof(struct rcps_individual));
749 son->genome.schedule = (int*)malloc(sizeof(int) * p->job_count);
750 son->genome.modes = (int*)malloc(p->genome_modes * sizeof(int));
751 son->genome.alternatives = (int*)malloc(p->genome_alternatives * sizeof(int));
752 daughter = (struct rcps_individual*)malloc(sizeof(struct rcps_individual));
753 daughter->genome.schedule = (int*)malloc(sizeof(int) * p->job_count);
754 daughter->genome.modes = (int*)malloc(p->genome_modes * sizeof(int));
755 daughter->genome.alternatives = (int*)malloc(p->genome_alternatives * sizeof(int));
756 // select father and mother
757 // XXX we want a configurable bias towards better individuals here
758 i = irand(s->population->size - 1);
759 j = 1 + irand(s->population->size - 1);
760 j = (i + j) % s->population->size;
761 father = (struct rcps_individual*)slist_node_getdata(
762 slist_at(s->population->individuals, i));
763 mother = (struct rcps_individual*)slist_node_getdata(
764 slist_at(s->population->individuals, j));
765 // crossover
766 sched_crossover2(s, p,
767 father->genome.schedule, mother->genome.schedule,
768 son->genome.schedule, daughter->genome.schedule);
769 crossover2(father->genome.modes, mother->genome.modes,
770 son->genome.modes, daughter->genome.modes, p->genome_modes);
771 crossover2(father->genome.alternatives, mother->genome.alternatives,
772 son->genome.alternatives, daughter->genome.alternatives,
773 p->genome_alternatives);
774 #ifdef HAVE_PTHREAD
775 // XXX look at error code
776 pthread_mutex_unlock(&s->lock);
777 #endif
778
779 // mutate
780 sched_mutation(s, p, son->genome.schedule, s->mut_sched);
781 sched_mutation(s, p, daughter->genome.schedule, s->mut_sched);
782 mutation(son->genome.modes, p->modes_max,
783 p->genome_modes, s->mut_mode);
784 mutation(daughter->genome.modes, p->modes_max,
785 p->genome_modes, s->mut_mode);
786 mutation(son->genome.alternatives, p->alternatives_max,
787 p->genome_alternatives, s->mut_alt);
788 mutation(daughter->genome.alternatives, p->alternatives_max,
789 p->genome_alternatives, s->mut_mode);
790
791 // add to population
792 pheno = decode(s, p, &son->genome);
793 son->fitness = fitness(p, &son->genome, pheno);
794 son_overuse = pheno->overuse_count;
795 pheno = decode(s, p, &daughter->genome);
796 daughter->fitness = fitness(p, &daughter->genome, pheno);
797 daughter_overuse = pheno->overuse_count;
798
799 #ifdef HAVE_PTHREAD
800 // XXX look at error code
801 pthread_mutex_lock(&s->lock);
802 #endif
803 add_individual(son, s->population);
804 add_individual(daughter, s->population);
805 // check if we have a better individual, if yes reset count
806 f1 = ((struct rcps_individual*)slist_node_getdata(slist_first(
807 s->population->individuals)))->fitness;
808 // get the best overuse count
809 best_overuse = son_overuse < daughter_overuse ?
810 son_overuse : daughter_overuse;
811 // check if we want to stop
812 if (rcps_fitness_cmp(&f1, &last_fitness) < 0) {
813 last_fitness = f1;
814 last_overuse = best_overuse;
815 count = 0;
816 }
817 count++;
818 tcount++;
819 if (count >= breakoff_count) {
820 if ((last_overuse > 0) && (!desperate)) {
821 // we are going into desperate mode
822 desperate = 1;
823 breakoff_count *= 10;
824 // XXX threading problem: do not do this because is affects
825 // other threads too! intead us desperate accordingly above
826 /* s->population->size *= 5;
827 s->mut_sched += 1000;
828 s->mut_mode += 1000;
829 s->mut_alt += 1000;*/
830 }
831 else {
832 end = 1;
833 }
834 }
835 // XXX if we use multiple threads, communicate to the others as well!
836 if (s->progress_callback) {
837 if (tcount >= (lcount + s->cb_steps)) {
838 end |= s->progress_callback(tcount, last_fitness, s->cb_arg);
839 lcount = tcount;
840 }
841 }
842 } while (!end);
843 #ifdef HAVE_PTHREAD
844 // XXX look at error code
845 pthread_mutex_unlock(&s->lock);
846 #endif
847 return tcount;
848 }
849
850 #ifdef HAVE_PTHREAD
851 struct thread_arg {
852 struct rcps_solver *s;
853 struct rcps_problem *p;
854 };
855
threadfunc(void * a)856 void *threadfunc(void *a) {
857 struct thread_arg *args = (struct thread_arg*)a;
858 int tcount = run_alg(args->s, args->p);
859 // XXX can be moved to run_alg
860 assert(pthread_mutex_lock(&args->s->lock) == 0);
861 args->s->reproductions += tcount;
862 assert(pthread_mutex_unlock(&args->s->lock) == 0);
863 return NULL;
864 }
865 #endif
866
rcps_solver_set_progress_callback(struct rcps_solver * s,int steps,void * arg,int (* progress_callback)(int generations,struct rcps_fitness fitness,void * arg))867 void rcps_solver_set_progress_callback(struct rcps_solver *s,
868 int steps, void *arg,
869 int (*progress_callback)(int generations, struct rcps_fitness fitness, void *arg)) {
870 s->progress_callback = progress_callback;
871 s->cb_arg = arg;
872 s->cb_steps = steps;
873 }
874
rcps_solver_set_duration_callback(struct rcps_solver * s,int (* duration_callback)(int direction,int starttime,int nominal_duration,void * arg))875 void rcps_solver_set_duration_callback(struct rcps_solver *s,
876 int (*duration_callback)(int direction, int starttime,
877 int nominal_duration, void *arg)) {
878 s->duration_callback = duration_callback;
879 }
880
rcps_solver_solve(struct rcps_solver * s,struct rcps_problem * p)881 void rcps_solver_solve(struct rcps_solver *s, struct rcps_problem *p) {
882 int i, j, k;
883 struct rcps_genome *genome;
884 struct rcps_phenotype *pheno;
885 /* init the random number generator */
886 srand(time(NULL));
887 /* fix the indices */
888 for (i = 0; i < p->job_count; i++) {
889 p->jobs[i]->index = i;
890 }
891 for (i = 0; i < p->resource_count; i++) {
892 p->resources[i]->index = i;
893 }
894 /* fix the predeccessors */
895 for (i = 0; i < p->job_count; i++) {
896 free(p->jobs[i]->predeccessors);
897 p->jobs[i]->predeccessor_count = 0;
898 }
899 for (i = 0; i < p->job_count; i++) {
900 for (j = 0; j < p->jobs[i]->successor_count; j++) {
901 rcps_job_predeccessor_add(p->jobs[i]->successors[j],
902 p->jobs[i], p->jobs[i]->successor_types[j]);
903 }
904 }
905 /* do other precalculations */
906 /* modes and alternatives */
907 p->genome_modes = 0;
908 p->genome_alternatives = 0;
909 for (i = 0; i < p->job_count; i++) {
910 struct rcps_job *job = p->jobs[i];
911 // do the modes
912 if (job->mode_count > 1) {
913 p->genome_modes++;
914 p->modes_max = (int*) realloc(p->modes_max, p->genome_modes*sizeof(int));
915 p->modes_max[p->genome_modes-1] = job->mode_count;
916 job->genome_position = p->genome_modes-1;
917 }
918 else {
919 job->genome_position = -1;
920 }
921 job->res_start = -1;
922 job->res_mode = -1;
923 for (j = 0; j < job->mode_count; j++) {
924 struct rcps_mode *mode = job->modes[j];
925 for (k = 0; k < mode->request_count; k++) {
926 struct rcps_request *request = mode->requests[k];
927 request->res_alternative = -1;
928 // do the alternatives
929 if (request->alternative_count > 1) {
930 p->genome_alternatives++;
931 p->alternatives_max = (int*) realloc(p->alternatives_max,
932 p->genome_alternatives*sizeof(int));
933 p->alternatives_max[p->genome_alternatives-1] =
934 request->alternative_count;
935 request->genome_position = p->genome_alternatives-1;
936 }
937 else {
938 request->genome_position = -1;
939 }
940 }
941 }
942 }
943 /* hash of predecessor relations */
944 free(s->predecessor_hash);
945 s->predecessor_hash = (char*)malloc(sizeof(char)*p->job_count*p->job_count);
946 for (i = 0; i < p->job_count*p->job_count; i++) {
947 s->predecessor_hash[i] = -1;
948 }
949
950 /* initialize the population */
951 s->population = new_population(s, p);
952
953 /* here we run the algorithm */
954 #ifdef HAVE_PTHREAD
955 if (s->jobs <= 1) {
956 s->reproductions = run_alg(s, p);
957 }
958 else {
959 s->reproductions = 0;
960 pthread_t *threads = (pthread_t*)malloc(sizeof(pthread_t) * s->jobs);
961 struct thread_arg args;
962 args.s = s;
963 args.p = p;
964 int i;
965 for (i = 0; i < s->jobs; i++) {
966 int result = pthread_create(&threads[i], NULL, threadfunc, &args);
967 assert(result == 0);
968 }
969
970 // XXX join them all!
971 for (i = 0; i < s->jobs; i++) {
972 int result = pthread_join(threads[i], NULL);
973 assert(result == 0);
974 }
975 }
976 #else
977 s->reproductions = run_alg(s, p);
978 #endif
979
980 // struct rcps_fitness fit = ((struct rcps_individual*)slist_node_getdata(slist_first(
981 // s->population->individuals)))->fitness;
982 // printf("cycles: \t%i\nfitness:\t[%d, %d]\n", tcount, fit.group, fit.weight);
983
984 // transfer the results to the problem structure
985 genome = &((struct rcps_individual*)slist_node_getdata(
986 slist_first(s->population->individuals)))->genome;
987 // XXX we could save us this decoding step if we would keep the best ones
988 // from before, not really worth it
989
990 // save a warning if the schedule is not valid
991 pheno = decode(s, p, genome);
992 if (pheno->overuse_count) {
993 s->warnings = 1;
994 }
995 else {
996 s->warnings = 0;
997 }
998
999 for (i = 0; i < p->job_count; i++) {
1000 struct rcps_job *job;
1001 struct rcps_mode *mode;
1002 job = p->jobs[i];
1003 job->res_start = pheno->job_start[job->index];
1004 job->res_mode =
1005 job->genome_position == -1
1006 ? 0
1007 : genome->modes[job->genome_position];
1008
1009 mode = job->modes[job->res_mode];
1010 for (j = 0; j < mode->request_count; j++) {
1011 struct rcps_request *request;
1012 request = mode->requests[j];
1013 request->res_alternative =
1014 request->genome_position == -1
1015 ? 0
1016 : genome->alternatives[request->genome_position];
1017 }
1018 }
1019 }
1020
rcps_solver_getreps(struct rcps_solver * s)1021 int rcps_solver_getreps(struct rcps_solver *s) {
1022 return s->reproductions;
1023 }
1024
rcps_solver_getwarnings(struct rcps_solver * s)1025 int rcps_solver_getwarnings(struct rcps_solver *s) {
1026 return s->warnings;
1027 }
1028