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