Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
2188 views
1
/*
2
* Main developer: Nico Van Cleemput
3
* In collaboration with: Craig Larson
4
*
5
* Copyright (C) 2013 Ghent University.
6
* Licensed under the GNU GPL, read the file LICENSE.txt for details.
7
*/
8
9
#include <stdlib.h>
10
#include <stdio.h>
11
#include <getopt.h>
12
#include <math.h>
13
#include <ctype.h>
14
#include <string.h>
15
#include <signal.h>
16
#include <unistd.h>
17
#include <float.h>
18
19
#include "bintrees.h"
20
#include "util.h"
21
#include "printing.h"
22
#include "printing_pb.h"
23
24
#define INVARIANT_LABEL 0
25
#define UNARY_LABEL 1
26
#define COMM_BINARY_LABEL 2
27
#define NON_COMM_BINARY_LABEL 3
28
29
//UNDEFINED is used for undefined values when making property based conjectures
30
#define UNDEFINED -1
31
32
int verbose = FALSE;
33
34
char outputType = 'h';
35
36
int targetUnary; //number of unary nodes in the generated trees
37
int targetBinary; //number of binary nodes in the generated trees
38
39
int invariantCount;
40
boolean invariantsUsed[MAX_INVARIANT_COUNT];
41
42
int mainInvariant;
43
44
boolean allowMainInvariantInExpressions = FALSE;
45
boolean useInvariantNames = FALSE;
46
47
float allowedPercentageOfSkips = 0.2f;
48
49
char invariantNames[MAX_INVARIANT_COUNT][1024];
50
char *invariantNamesPointers[MAX_INVARIANT_COUNT];
51
52
#define LEQ 0 // i.e., MI <= expression
53
#define LESS 1 // i.e., MI < expression
54
#define GEQ 2 // i.e., MI >= expression
55
#define GREATER 3 // i.e., MI > expression
56
57
#define SUFFICIENT 0 // i.e., MI <= expression
58
#define NECESSARY 2 // i.e., MI => expression
59
60
int inequality = LEQ; // == SUFFICIENT
61
62
int unaryOperatorCount = 10;
63
/*
64
* 1: x - 1
65
* 2: x + 1
66
* 3: x * 2
67
* 4: x / 2
68
* 5: x ** 2
69
* 6: x * (-1)
70
* 7: x ** (-1)
71
* 8: sqrt(x)
72
* 9: ln(x)
73
* 10: log_10(x)
74
*/
75
int unaryOperators[MAX_UNARY_OPERATORS];
76
77
int commBinaryOperatorCount = 4;
78
/*
79
* 1: x + y
80
* 2: x * y
81
* 3: max(x,y)
82
* 4: min(x,y)
83
*/
84
int commBinaryOperators[MAX_COMM_BINARY_OPERATORS];
85
86
int nonCommBinaryOperatorCount = 3;
87
/*
88
* 1: x - y
89
* 2: x / y
90
* 3: x ** y
91
*/
92
int nonCommBinaryOperators[MAX_NCOMM_BINARY_OPERATORS];
93
94
double invariantValues[MAX_OBJECT_COUNT][MAX_INVARIANT_COUNT];
95
boolean invariantValues_propertyBased[MAX_OBJECT_COUNT][MAX_INVARIANT_COUNT];
96
97
double knownTheory[MAX_OBJECT_COUNT];
98
boolean knownTheory_propertyBased[MAX_OBJECT_COUNT];
99
100
int objectCount = 0;
101
102
unsigned long int treeCount = 0;
103
unsigned long int labeledTreeCount = 0;
104
unsigned long int validExpressionsCount = 0;
105
106
unsigned long int timeOut = 0;
107
boolean timeOutReached = FALSE;
108
109
boolean userInterrupted = FALSE;
110
boolean terminationSignalReceived = FALSE;
111
112
boolean heuristicStoppedGeneration = FALSE;
113
114
boolean onlyUnlabeled = FALSE;
115
boolean onlyLabeled = FALSE;
116
boolean generateExpressions = FALSE;
117
boolean doConjecturing = FALSE;
118
boolean propertyBased = FALSE;
119
boolean theoryProvided = FALSE;
120
121
boolean printValidExpressions = FALSE;
122
123
#define GRINVIN_NEXT_OPERATOR_COUNT 0
124
125
int nextOperatorCountMethod = GRINVIN_NEXT_OPERATOR_COUNT;
126
127
FILE *operatorFile = NULL;
128
boolean closeOperatorFile = FALSE;
129
FILE *invariantsFile = NULL;
130
boolean closeInvariantsFile = FALSE;
131
132
#define NO_HEURISTIC -1
133
#define DALMATIAN_HEURISTIC 0
134
#define GRINVIN_HEURISTIC 1
135
136
int selectedHeuristic = NO_HEURISTIC;
137
138
boolean (*heuristicStopConditionReached)() = NULL;
139
void (*heuristicInit)() = NULL;
140
void (*heuristicPostProcessing)() = NULL;
141
142
//function declarations
143
144
void outputExpression(TREE *tree, FILE *f);
145
void printExpression(TREE *tree, FILE *f);
146
boolean handleComparator(double left, double right, int id);
147
148
void printExpression_propertyBased(TREE *tree, FILE *f);
149
boolean handleComparator_propertyBased(boolean left, boolean right, int id);
150
151
/*
152
* Returns non-zero value if the tree satisfies the current target counts
153
* for unary and binary operators. Returns 0 in all other cases.
154
*/
155
boolean isComplete(TREE *tree){
156
return tree->unaryCount == targetUnary && tree->binaryCount == targetBinary;
157
}
158
159
//----------- Heuristics -------------
160
161
//dalmatian heuristic
162
163
boolean dalmatianFirst = TRUE;
164
165
double dalmatianCurrentConjectureValues[MAX_OBJECT_COUNT][MAX_OBJECT_COUNT];
166
boolean dalmatianCurrentConjectureValues_propertyBased[MAX_OBJECT_COUNT][MAX_OBJECT_COUNT];
167
168
int dalmatianBestConjectureForObject[MAX_OBJECT_COUNT];
169
170
boolean dalmatianObjectInBoundArea[MAX_OBJECT_COUNT] = {FALSE}; //only for property based conjectures
171
172
boolean dalmatianConjectureInUse[MAX_OBJECT_COUNT] = {FALSE};
173
174
TREE dalmatianConjectures[MAX_OBJECT_COUNT];
175
176
int dalmatianHitCount = 0;
177
178
inline void dalmatianUpdateHitCount(){
179
dalmatianHitCount = 0;
180
int i;
181
for(i=0; i<objectCount; i++){
182
double currentBest =
183
dalmatianCurrentConjectureValues[dalmatianBestConjectureForObject[i]][i];
184
if(currentBest == invariantValues[i][mainInvariant]){
185
dalmatianHitCount++;
186
}
187
}
188
189
}
190
191
void dalmatianHeuristic(TREE *tree, double *values){
192
int i;
193
//this heuristic assumes the expression was true for all objects
194
195
//if known theory is provided, we check that first
196
boolean isMoreSignificant = FALSE;
197
if(theoryProvided){
198
for(i=0; i<objectCount; i++){
199
if(!handleComparator(knownTheory[i], values[i], inequality)){
200
if(verbose){
201
fprintf(stderr, "Conjecture is more significant than known theory for object %d.\n", i+1);
202
fprintf(stderr, "%11.6lf vs. %11.6lf\n", knownTheory[i], values[i]);
203
}
204
isMoreSignificant = TRUE;
205
}
206
}
207
208
//check if there is at least one object for which this bound is more significant than the known theory
209
if(!isMoreSignificant) return;
210
}
211
212
//if this is the first conjecture, we just store it and return
213
if(dalmatianFirst){
214
if(verbose){
215
fprintf(stderr, "Saving expression\n");
216
printExpression(tree, stderr);
217
}
218
memcpy(dalmatianCurrentConjectureValues[0], values,
219
sizeof(double)*(MAX_OBJECT_COUNT));
220
for(i=0; i<objectCount; i++){
221
dalmatianBestConjectureForObject[i] = 0;
222
}
223
dalmatianConjectureInUse[0] = TRUE;
224
copyTree(tree, dalmatianConjectures + 0);
225
dalmatianFirst = FALSE;
226
dalmatianUpdateHitCount();
227
return;
228
}
229
230
//check the significance
231
//----------------------
232
233
//find the objects for which this bound is better
234
isMoreSignificant = FALSE; //the conjecture is not necessarily more significant than the other conjectures
235
int conjectureFrequency[MAX_OBJECT_COUNT] = {0};
236
for(i=0; i<objectCount; i++){
237
double currentBest =
238
dalmatianCurrentConjectureValues[dalmatianBestConjectureForObject[i]][i];
239
if(handleComparator(currentBest, values[i], inequality)){
240
conjectureFrequency[dalmatianBestConjectureForObject[i]]++;
241
} else {
242
if(verbose){
243
fprintf(stderr, "Conjecture is more significant for object %d.\n", i+1);
244
fprintf(stderr, "%11.6lf vs. %11.6lf\n", currentBest, values[i]);
245
}
246
dalmatianBestConjectureForObject[i] = MAX_OBJECT_COUNT;
247
isMoreSignificant = TRUE;
248
}
249
}
250
251
//check if there is at least one object for which this bound is more significant
252
if(!isMoreSignificant) return;
253
254
if(verbose){
255
fprintf(stderr, "Saving expression\n");
256
printExpression(tree, stderr);
257
}
258
259
//if we get here, then the current bound is at least for one object more significant
260
//we store the values and that conjecture
261
int smallestAvailablePosition = 0;
262
263
while(smallestAvailablePosition < objectCount &&
264
conjectureFrequency[smallestAvailablePosition]>0){
265
smallestAvailablePosition++;
266
}
267
if(smallestAvailablePosition == objectCount){
268
BAILOUT("Error when handling dalmatian heuristic")
269
}
270
271
for(i=smallestAvailablePosition+1; i<objectCount; i++){
272
if(conjectureFrequency[i]==0){
273
dalmatianConjectureInUse[i] = FALSE;
274
}
275
}
276
277
memcpy(dalmatianCurrentConjectureValues[smallestAvailablePosition], values,
278
sizeof(double)*(MAX_OBJECT_COUNT));
279
for(i=0; i<objectCount; i++){
280
if(dalmatianBestConjectureForObject[i] == MAX_OBJECT_COUNT){
281
dalmatianBestConjectureForObject[i] = smallestAvailablePosition;
282
}
283
}
284
copyTree(tree, dalmatianConjectures + smallestAvailablePosition);
285
dalmatianConjectureInUse[smallestAvailablePosition] = TRUE;
286
287
dalmatianUpdateHitCount();
288
289
}
290
291
boolean dalmatianHeuristicStopConditionReached(){
292
return dalmatianHitCount == objectCount;
293
}
294
295
void dalmatianHeuristicInit(){
296
int i;
297
for(i=0;i<objectCount;i++){
298
initTree(dalmatianConjectures+i);
299
}
300
}
301
302
void dalmatianHeuristicPostProcessing(){
303
int i;
304
for(i=0;i<objectCount;i++){
305
if(dalmatianConjectureInUse[i]){
306
outputExpression(dalmatianConjectures+i, stdout);
307
}
308
freeTree(dalmatianConjectures+i);
309
}
310
}
311
312
inline void dalmatianUpdateHitCount_propertyBased(){
313
dalmatianHitCount = 0;
314
int i;
315
for(i=0; i<objectCount; i++){
316
if(invariantValues_propertyBased[i][mainInvariant] == UNDEFINED){
317
continue;
318
}
319
if(dalmatianObjectInBoundArea[i]){
320
dalmatianHitCount++;
321
}
322
}
323
324
}
325
326
void dalmatianHeuristic_propertyBased(TREE *tree, boolean *values){
327
int i;
328
//this heuristic assumes the expression was true for all objects
329
330
//if known theory is provided, we check that first
331
boolean isMoreSignificant = FALSE;
332
if(theoryProvided){
333
for(i=0; i<objectCount; i++){
334
if(inequality == SUFFICIENT){
335
if(invariantValues_propertyBased[i][mainInvariant] == UNDEFINED ||
336
!(invariantValues_propertyBased[i][mainInvariant])){
337
//we're only looking at object that have the main property to decide
338
//the significance.
339
continue;
340
}
341
} else if(inequality == NECESSARY){
342
if(invariantValues_propertyBased[i][mainInvariant] == UNDEFINED ||
343
(invariantValues_propertyBased[i][mainInvariant])){
344
//we're only looking at object that do not have the main property
345
//to decide the significance.
346
continue;
347
}
348
} else {
349
BAILOUT("Error when handling dalmatian heuristic: unknown inequality")
350
}
351
352
if(!handleComparator_propertyBased(knownTheory_propertyBased[i],
353
values[i], inequality)){
354
if(verbose){
355
fprintf(stderr, "Conjecture is more significant than known theory for object %d.\n", i+1);
356
}
357
isMoreSignificant = TRUE;
358
}
359
}
360
361
//check if there is at least one object for which this bound is more significant than the known theory
362
if(!isMoreSignificant) return;
363
}
364
365
//if this is the first conjecture, we just store it and return
366
if(dalmatianFirst){
367
if(verbose){
368
fprintf(stderr, "Saving expression\n");
369
printExpression_propertyBased(tree, stderr);
370
}
371
memcpy(dalmatianCurrentConjectureValues_propertyBased[0], values,
372
sizeof(double)*(MAX_OBJECT_COUNT));
373
for(i=0; i<objectCount; i++){
374
if(values[i] == UNDEFINED){
375
continue;
376
}
377
if(values[i]){
378
dalmatianObjectInBoundArea[i] = TRUE;
379
}
380
}
381
dalmatianConjectureInUse[0] = TRUE;
382
copyTree(tree, dalmatianConjectures + 0);
383
dalmatianFirst = FALSE;
384
dalmatianUpdateHitCount_propertyBased();
385
return;
386
}
387
388
//check the significance
389
//----------------------
390
391
//find the objects for which this bound is better
392
isMoreSignificant = FALSE; //the conjecture is not necessarily more significant than the other conjectures
393
for(i=0; i<objectCount; i++){
394
if(inequality == SUFFICIENT){
395
if(invariantValues_propertyBased[i][mainInvariant] == UNDEFINED ||
396
!(invariantValues_propertyBased[i][mainInvariant])){
397
//we're only looking at object that have the main property to decide
398
//the significance.
399
continue;
400
}
401
} else if(inequality == NECESSARY){
402
if(invariantValues_propertyBased[i][mainInvariant] == UNDEFINED ||
403
(invariantValues_propertyBased[i][mainInvariant])){
404
//we're only looking at object that do not have the main property
405
//to decide the significance.
406
continue;
407
}
408
} else {
409
BAILOUT("Error when handling dalmatian heuristic: unknown inequality")
410
}
411
412
if(!handleComparator_propertyBased(dalmatianObjectInBoundArea[i],
413
values[i], inequality)){
414
if(verbose){
415
fprintf(stderr, "Conjecture is more significant for object %d.\n", i+1);
416
}
417
isMoreSignificant = TRUE;
418
}
419
}
420
421
//check if there is at least one object for which this bound is more significant
422
if(!isMoreSignificant) return;
423
424
if(verbose){
425
fprintf(stderr, "Saving expression\n");
426
printExpression_propertyBased(tree, stderr);
427
}
428
429
//if we get here, then the current bound is at least for one object more significant
430
//we store the values and that conjecture
431
int smallestAvailablePosition = 0;
432
433
while(smallestAvailablePosition < objectCount &&
434
dalmatianConjectureInUse[smallestAvailablePosition]){
435
smallestAvailablePosition++;
436
}
437
if(smallestAvailablePosition == objectCount){
438
BAILOUT("Error when handling dalmatian heuristic")
439
}
440
441
memcpy(dalmatianCurrentConjectureValues_propertyBased[smallestAvailablePosition],
442
values, sizeof(boolean)*(MAX_OBJECT_COUNT));
443
copyTree(tree, dalmatianConjectures + smallestAvailablePosition);
444
dalmatianConjectureInUse[smallestAvailablePosition] = TRUE;
445
446
//update bounded area
447
if(inequality == SUFFICIENT){
448
for(i = 0; i < objectCount; i++){
449
if(values[i] == UNDEFINED){
450
continue;
451
}
452
dalmatianObjectInBoundArea[i] =
453
dalmatianObjectInBoundArea[i] || values[i];
454
}
455
} else if(inequality == NECESSARY){
456
for(i = 0; i < objectCount; i++){
457
if(values[i] == UNDEFINED){
458
continue;
459
}
460
dalmatianObjectInBoundArea[i] =
461
dalmatianObjectInBoundArea[i] && values[i];
462
}
463
} else {
464
BAILOUT("Error when handling dalmatian heuristic: unknown inequality")
465
}
466
467
dalmatianUpdateHitCount_propertyBased();
468
469
//prune conjectures
470
/* We just loop through the conjectures and remove the ones that are no longer
471
* significant. At the moment we avoid doing anything special like looking for
472
* the best set of conjectures to prune.
473
*
474
* By definition, this pruning will not influence the bounding area (and the
475
* hit count).
476
*/
477
int j, k;
478
479
if(inequality == SUFFICIENT){
480
for(i = 0; i < objectCount; i++){
481
if(dalmatianConjectureInUse[i]){
482
isMoreSignificant = FALSE;
483
for(j = 0; j < objectCount; j++){
484
if(invariantValues_propertyBased[j][mainInvariant] == UNDEFINED ||
485
!(invariantValues_propertyBased[j][mainInvariant])){
486
//we're only looking at object that have the main property to decide
487
//the significance.
488
continue;
489
}
490
491
//first we check whether the object is in the bound area
492
boolean localObjectInBoundArea = FALSE;
493
494
for(k = 0; k < objectCount; k++){
495
if(dalmatianConjectureInUse[k] && k!=i){
496
if(dalmatianCurrentConjectureValues_propertyBased[k][j] ==
497
UNDEFINED){
498
continue;
499
}
500
localObjectInBoundArea =
501
localObjectInBoundArea ||
502
dalmatianCurrentConjectureValues_propertyBased[k][j];
503
}
504
}
505
506
//then we check whether this conjecture is still significant
507
if(!handleComparator_propertyBased(localObjectInBoundArea,
508
dalmatianCurrentConjectureValues_propertyBased[i][j],
509
inequality)){
510
if(verbose){
511
fprintf(stderr, "Conjecture %d is more significant for object %d.\n", i+1, j+1);
512
}
513
isMoreSignificant = TRUE;
514
break;
515
}
516
}
517
//we only keep the conjecture if it is still more significant
518
//for at least one object.
519
dalmatianConjectureInUse[i] = isMoreSignificant;
520
}
521
}
522
} else if(inequality == NECESSARY){
523
for(i = 0; i < objectCount; i++){
524
if(dalmatianConjectureInUse[i]){
525
isMoreSignificant = FALSE;
526
for(j = 0; j < objectCount; j++){
527
if(invariantValues_propertyBased[j][mainInvariant] == UNDEFINED ||
528
(invariantValues_propertyBased[j][mainInvariant])){
529
//we're only looking at object that do not have the main property to decide
530
//the significance.
531
continue;
532
}
533
534
//first we check whether the object is in the bound area
535
boolean localObjectInBoundArea = TRUE;
536
537
for(k = 0; k < objectCount; k++){
538
if(dalmatianConjectureInUse[k] && k!=i){
539
if(dalmatianCurrentConjectureValues_propertyBased[k][j] ==
540
UNDEFINED){
541
continue;
542
}
543
localObjectInBoundArea =
544
localObjectInBoundArea &&
545
dalmatianCurrentConjectureValues_propertyBased[k][j];
546
}
547
}
548
549
//then we check whether this conjecture is still significant
550
if(!handleComparator_propertyBased(localObjectInBoundArea,
551
dalmatianCurrentConjectureValues_propertyBased[i][j],
552
inequality)){
553
if(verbose){
554
fprintf(stderr, "Conjecture %d is more significant for object %d.\n", i+1, j+1);
555
}
556
isMoreSignificant = TRUE;
557
break;
558
}
559
}
560
//we only keep the conjecture if it is still more significant
561
//for at least one object.
562
dalmatianConjectureInUse[i] = isMoreSignificant;
563
}
564
}
565
} else {
566
BAILOUT("Error when handling dalmatian heuristic: unknown inequality")
567
}
568
}
569
570
boolean dalmatianHeuristicStopConditionReached_propertyBased(){
571
int pCount = 0; //i.e., the number of object that have the main property
572
int i;
573
574
for(i = 0; i < objectCount; i++){
575
if(invariantValues_propertyBased[i][mainInvariant] == UNDEFINED){
576
continue;
577
}
578
if(invariantValues_propertyBased[i][mainInvariant]){
579
pCount++;
580
}
581
}
582
583
/* If we specified sufficient conditions, then the variable dalmatianHitCount
584
* contains the number of objects in the intersection of all conditions.
585
* If we specified necessary conditions, then the variable dalmatianHitCount
586
* contains the number of objects in the union of all conditions.
587
*/
588
return dalmatianHitCount == pCount;
589
}
590
591
void (* const dalmatianHeuristicInit_propertyBased)(void) =
592
dalmatianHeuristicInit;
593
594
void (* const dalmatianHeuristicPostProcessing_propertyBased)(void) =
595
dalmatianHeuristicPostProcessing;
596
597
//grinvin heuristic
598
599
double grinvinBestError = DBL_MAX;
600
TREE grinvinBestExpression;
601
602
double grinvinValueError(double *values){
603
double result = 0.0;
604
int i;
605
606
for(i=0; i<objectCount; i++){
607
double diff = values[i] - invariantValues[mainInvariant][i];
608
result += (diff*diff);
609
}
610
return result;
611
}
612
613
void grinvinHeuristic(TREE *tree, double *values){
614
//this heuristic assumes the expression was true for all objects
615
double valueError = grinvinValueError(values);
616
if(valueError < grinvinBestError){
617
grinvinBestError = valueError;
618
copyTree(tree, &grinvinBestExpression);
619
}
620
}
621
622
boolean grinvinHeuristicStopConditionReached(){
623
return (1 << (2*targetBinary + targetUnary)) * objectCount >= grinvinBestError;
624
}
625
626
void grinvinHeuristicInit(){
627
initTree(&grinvinBestExpression);
628
}
629
630
void grinvinHeuristicPostProcessing(){
631
outputExpression(&grinvinBestExpression, stdout);
632
freeTree(&grinvinBestExpression);
633
}
634
635
//------ Stop generation -------
636
637
boolean shouldGenerationProcessBeTerminated(){
638
if(heuristicStopConditionReached!=NULL){
639
if(heuristicStopConditionReached()){
640
heuristicStoppedGeneration = TRUE;
641
return TRUE;
642
}
643
}
644
if(timeOutReached || userInterrupted || terminationSignalReceived){
645
return TRUE;
646
}
647
648
return FALSE;
649
}
650
651
void handleAlarmSignal(int sig){
652
if(sig==SIGALRM){
653
timeOutReached = TRUE;
654
} else {
655
fprintf(stderr, "Handler called with wrong signal -- ignoring!\n");
656
}
657
}
658
659
void handleInterruptSignal(int sig){
660
if(sig==SIGINT){
661
userInterrupted = TRUE;
662
} else {
663
fprintf(stderr, "Handler called with wrong signal -- ignoring!\n");
664
}
665
}
666
667
void handleTerminationSignal(int sig){
668
if(sig==SIGTERM){
669
terminationSignalReceived = TRUE;
670
} else {
671
fprintf(stderr, "Handler called with wrong signal -- ignoring!\n");
672
}
673
}
674
675
//------ Expression operations -------
676
677
void outputExpressionStack(TREE *tree, FILE *f){
678
int i, length;
679
if(useInvariantNames){
680
fprintf(f, "%s\n", invariantNames[mainInvariant]);
681
} else {
682
fprintf(f, "I%d\n", mainInvariant + 1);
683
}
684
685
//start by ordering nodes
686
NODE *orderedNodes[tree->unaryCount + 2*(tree->binaryCount) + 1];
687
688
length = 0;
689
getOrderedNodes(tree->root, orderedNodes, &length);
690
691
for(i=0; i<length; i++){
692
printSingleNode(orderedNodes[i], f,
693
useInvariantNames ? invariantNamesPointers : NULL);
694
fprintf(f, "\n");
695
}
696
printComparator(inequality, f);
697
fprintf(f, "\n\n");
698
}
699
700
void outputExpressionStack_propertyBased(TREE *tree, FILE *f){
701
int i, length;
702
if(useInvariantNames){
703
fprintf(f, "%s\n", invariantNames[mainInvariant]);
704
} else {
705
fprintf(f, "I%d\n", mainInvariant + 1);
706
}
707
708
//start by ordering nodes
709
NODE *orderedNodes[tree->unaryCount + 2*(tree->binaryCount) + 1];
710
711
length = 0;
712
getOrderedNodes(tree->root, orderedNodes, &length);
713
714
for(i=0; i<length; i++){
715
printSingleNode_propertyBased(orderedNodes[i], f,
716
useInvariantNames ? invariantNamesPointers : NULL);
717
fprintf(f, "\n");
718
}
719
printComparator_propertyBased(inequality, f);
720
fprintf(f, "\n\n");
721
}
722
723
void printExpression(TREE *tree, FILE *f){
724
if(useInvariantNames){
725
fprintf(f, "%s ", invariantNames[mainInvariant]);
726
} else {
727
fprintf(f, "I%d ", mainInvariant + 1);
728
}
729
printComparator(inequality, f);
730
fprintf(f, " ");
731
printNode(tree->root, f,
732
useInvariantNames ? invariantNamesPointers : NULL);
733
fprintf(f, "\n");
734
}
735
736
void printExpression_propertyBased(TREE *tree, FILE *f){
737
if(useInvariantNames){
738
fprintf(f, "%s ", invariantNames[mainInvariant]);
739
} else {
740
fprintf(f, "I%d ", mainInvariant + 1);
741
}
742
printComparator_propertyBased(inequality, f);
743
fprintf(f, " ");
744
printNode_propertyBased(tree->root, f,
745
useInvariantNames ? invariantNamesPointers : NULL);
746
fprintf(f, "\n");
747
}
748
749
void outputExpression(TREE *tree, FILE *f){
750
if(propertyBased){
751
if(outputType=='h'){
752
printExpression_propertyBased(tree, f);
753
} else if(outputType=='s'){
754
outputExpressionStack_propertyBased(tree, f);
755
}
756
} else {
757
if(outputType=='h'){
758
printExpression(tree, f);
759
} else if(outputType=='s'){
760
outputExpressionStack(tree, f);
761
}
762
}
763
}
764
765
void handleExpression(TREE *tree, double *values, int calculatedValues, int hitCount, int skipCount){
766
validExpressionsCount++;
767
if(printValidExpressions){
768
printExpression(tree, stderr);
769
}
770
if(doConjecturing){
771
if(selectedHeuristic==DALMATIAN_HEURISTIC){
772
if(skipCount > allowedPercentageOfSkips * objectCount){
773
return;
774
}
775
dalmatianHeuristic(tree, values);
776
} else if(selectedHeuristic==GRINVIN_HEURISTIC){
777
if(skipCount > allowedPercentageOfSkips * objectCount){
778
return;
779
}
780
grinvinHeuristic(tree, values);
781
}
782
}
783
}
784
785
void handleExpression_propertyBased(TREE *tree, boolean *values, int calculatedValues, int hitCount, int skipCount){
786
validExpressionsCount++;
787
if(printValidExpressions){
788
printExpression_propertyBased(tree, stderr);
789
}
790
if(doConjecturing){
791
if(selectedHeuristic==DALMATIAN_HEURISTIC){
792
if(skipCount > allowedPercentageOfSkips * objectCount){
793
return;
794
}
795
dalmatianHeuristic_propertyBased(tree, values);
796
} else if(selectedHeuristic==GRINVIN_HEURISTIC){
797
BAILOUT("Grinvin heuristic is not defined for property-based conjectures.")
798
}
799
}
800
}
801
802
double handleUnaryOperator(int id, double value){
803
if(id==0){
804
return value - 1;
805
} else if(id==1){
806
return value + 1;
807
} else if(id==2){
808
return value * 2;
809
} else if(id==3){
810
return value / 2;
811
} else if(id==4){
812
return value*value;
813
} else if(id==5){
814
return -value;
815
} else if(id==6){
816
return 1/value;
817
} else if(id==7){
818
return sqrt(value);
819
} else if(id==8){
820
return log(value);
821
} else if(id==9){
822
return log10(value);
823
} else {
824
BAILOUT("Unknown unary operator ID")
825
}
826
}
827
828
void writeUnaryOperatorExample(FILE *f){
829
fprintf(f, "U 0 x - 1\n");
830
fprintf(f, "U 1 x + 1\n");
831
fprintf(f, "U 2 x * 2\n");
832
fprintf(f, "U 3 x / 2\n");
833
fprintf(f, "U 4 x ^ 2\n");
834
fprintf(f, "U 5 -x\n");
835
fprintf(f, "U 6 1 / x\n");
836
fprintf(f, "U 7 sqrt(x)\n");
837
fprintf(f, "U 8 ln(x)\n");
838
fprintf(f, "U 9 log_10(x)\n");
839
}
840
841
double handleCommutativeBinaryOperator(int id, double left, double right){
842
if(id==0){
843
return left + right;
844
} else if(id==1){
845
return left*right;
846
} else if(id==2){
847
return left < right ? right : left;
848
} else if(id==3){
849
return left < right ? left : right;
850
} else {
851
BAILOUT("Unknown commutative binary operator ID")
852
}
853
}
854
855
void writeCommutativeBinaryOperatorExample(FILE *f){
856
fprintf(f, "C 0 x + y\n");
857
fprintf(f, "C 1 x * y\n");
858
fprintf(f, "C 2 max(x,y)\n");
859
fprintf(f, "C 3 min(x,y)\n");
860
}
861
862
double handleNonCommutativeBinaryOperator(int id, double left, double right){
863
if(id==0){
864
return left - right;
865
} else if(id==1){
866
return left/right;
867
} else if(id==2){
868
return pow(left, right);
869
} else {
870
BAILOUT("Unknown non-commutative binary operator ID")
871
}
872
}
873
874
void writeNonCommutativeBinaryOperatorExample(FILE *f){
875
fprintf(f, "N 0 x - y\n");
876
fprintf(f, "N 1 x / y\n");
877
fprintf(f, "N 2 x ^ y\n");
878
}
879
880
boolean handleComparator(double left, double right, int id){
881
if(id==0){
882
return left <= right;
883
} else if(id==1){
884
return left < right;
885
} else if(id==2){
886
return left >= right;
887
} else if(id==3){
888
return left > right;
889
} else {
890
BAILOUT("Unknown comparator ID")
891
}
892
}
893
894
double evaluateNode(NODE *node, int object){
895
if (node->contentLabel[0]==INVARIANT_LABEL) {
896
return invariantValues[object][node->contentLabel[1]];
897
} else if (node->contentLabel[0]==UNARY_LABEL) {
898
return handleUnaryOperator(node->contentLabel[1], evaluateNode(node->left, object));
899
} else if (node->contentLabel[0]==NON_COMM_BINARY_LABEL){
900
return handleNonCommutativeBinaryOperator(node->contentLabel[1],
901
evaluateNode(node->left, object), evaluateNode(node->right, object));
902
} else if (node->contentLabel[0]==COMM_BINARY_LABEL){
903
return handleCommutativeBinaryOperator(node->contentLabel[1],
904
evaluateNode(node->left, object), evaluateNode(node->right, object));
905
} else {
906
BAILOUT("Unknown content label type")
907
}
908
}
909
910
boolean handleUnaryOperator_propertyBased(int id, boolean value){
911
if(value==UNDEFINED){
912
return UNDEFINED;
913
}
914
if(id==0){
915
return !value;
916
} else {
917
BAILOUT("Unknown unary operator ID")
918
}
919
}
920
921
void writeUnaryOperatorExample_propertyBased(FILE *f){
922
fprintf(f, "U 0 !x\n");
923
}
924
925
boolean handleCommutativeBinaryOperator_propertyBased(int id, boolean left, boolean right){
926
if(left==UNDEFINED || right==UNDEFINED){
927
return UNDEFINED;
928
}
929
if(id==0){
930
return left && right;
931
} else if(id==1){
932
return left || right;
933
} else if(id==2){
934
return (!left) != (!right); //XOR
935
} else {
936
BAILOUT("Unknown commutative binary operator ID")
937
}
938
}
939
940
void writeCommutativeBinaryOperatorExample_propertyBased(FILE *f){
941
fprintf(f, "C 0 x & y\n");
942
fprintf(f, "C 1 x | y\n");
943
fprintf(f, "C 2 x ^ y (XOR)\n");
944
}
945
946
boolean handleNonCommutativeBinaryOperator_propertyBased(int id, boolean left, boolean right){
947
if(left==UNDEFINED || right==UNDEFINED){
948
return UNDEFINED;
949
}
950
if(id==0){
951
return (!left) || right;
952
} else {
953
BAILOUT("Unknown non-commutative binary operator ID")
954
}
955
}
956
957
void writeNonCommutativeBinaryOperatorExample_propertyBased(FILE *f){
958
fprintf(f, "N 0 x => y\n");
959
}
960
961
boolean handleComparator_propertyBased(boolean left, boolean right, int id){
962
if(left==UNDEFINED || right==UNDEFINED){
963
return UNDEFINED;
964
}
965
if(id==0){
966
return (!right) || left;
967
} else if(id==2){
968
return (!left) || right;
969
} else {
970
BAILOUT("Unknown comparator ID")
971
}
972
}
973
974
boolean evaluateNode_propertyBased(NODE *node, int object){
975
if (node->contentLabel[0]==INVARIANT_LABEL) {
976
return invariantValues_propertyBased[object][node->contentLabel[1]];
977
} else if (node->contentLabel[0]==UNARY_LABEL) {
978
return handleUnaryOperator_propertyBased(node->contentLabel[1],
979
evaluateNode_propertyBased(node->left, object));
980
} else if (node->contentLabel[0]==NON_COMM_BINARY_LABEL){
981
return handleNonCommutativeBinaryOperator_propertyBased(node->contentLabel[1],
982
evaluateNode_propertyBased(node->left, object),
983
evaluateNode_propertyBased(node->right, object));
984
} else if (node->contentLabel[0]==COMM_BINARY_LABEL){
985
return handleCommutativeBinaryOperator_propertyBased(node->contentLabel[1],
986
evaluateNode_propertyBased(node->left, object),
987
evaluateNode_propertyBased(node->right, object));
988
} else {
989
BAILOUT("Unknown content label type")
990
}
991
}
992
993
boolean evaluateTree(TREE *tree, double *values, int *calculatedValues, int *hits, int *skips){
994
int i;
995
int hitCount = 0;
996
int skipCount = 0;
997
for(i=0; i<objectCount; i++){
998
if(isnan(invariantValues[i][mainInvariant])){
999
skipCount++;
1000
continue; //skip NaN
1001
}
1002
double expression = evaluateNode(tree->root, i);
1003
values[i] = expression;
1004
if(isnan(expression)){
1005
skipCount++;
1006
continue; //skip NaN
1007
}
1008
if(!handleComparator(invariantValues[i][mainInvariant], expression, inequality)){
1009
*calculatedValues = i+1;
1010
*hits = hitCount;
1011
*skips = skipCount;
1012
return FALSE;
1013
} else if(expression==invariantValues[i][mainInvariant]) {
1014
hitCount++;
1015
}
1016
}
1017
*hits = hitCount;
1018
*skips = skipCount;
1019
*calculatedValues = objectCount;
1020
if(skipCount == objectCount){
1021
return FALSE;
1022
}
1023
return TRUE;
1024
}
1025
1026
boolean evaluateTree_propertyBased(TREE *tree, boolean *values, int *calculatedValues, int *hits, int *skips){
1027
int i;
1028
int hitCount = 0;
1029
int skipCount = 0;
1030
for(i=0; i<objectCount; i++){
1031
if(invariantValues_propertyBased[i][mainInvariant]==UNDEFINED){
1032
skipCount++;
1033
continue; //skip undefined values
1034
}
1035
boolean expression = evaluateNode_propertyBased(tree->root, i);
1036
values[i] = expression;
1037
if(expression == UNDEFINED){
1038
skipCount++;
1039
continue; //skip NaN
1040
}
1041
if(!handleComparator_propertyBased(invariantValues_propertyBased[i][mainInvariant], expression, inequality)){
1042
*calculatedValues = i+1;
1043
*hits = hitCount;
1044
*skips = skipCount;
1045
return FALSE;
1046
} else if(!(expression) == !(invariantValues_propertyBased[i][mainInvariant])) {
1047
hitCount++;
1048
}
1049
}
1050
*hits = hitCount;
1051
*skips = skipCount;
1052
*calculatedValues = objectCount;
1053
if(skipCount == objectCount){
1054
return FALSE;
1055
}
1056
return TRUE;
1057
}
1058
1059
void checkExpression(TREE *tree){
1060
double values[MAX_OBJECT_COUNT];
1061
int calculatedValues = 0;
1062
int hitCount = 0;
1063
int skipCount = 0;
1064
if (evaluateTree(tree, values, &calculatedValues, &hitCount, &skipCount)){
1065
handleExpression(tree, values, objectCount, hitCount, skipCount);
1066
}
1067
}
1068
1069
void checkExpression_propertyBased(TREE *tree){
1070
boolean values[MAX_OBJECT_COUNT];
1071
int calculatedValues = 0;
1072
int hitCount = 0;
1073
int skipCount = 0;
1074
if (evaluateTree_propertyBased(tree, values, &calculatedValues, &hitCount, &skipCount)){
1075
handleExpression_propertyBased(tree, values, objectCount, hitCount, skipCount);
1076
}
1077
}
1078
1079
//------ Labeled tree generation -------
1080
1081
void handleLabeledTree(TREE *tree){
1082
labeledTreeCount++;
1083
if(generateExpressions || doConjecturing){
1084
if(propertyBased){
1085
checkExpression_propertyBased(tree);
1086
} else {
1087
checkExpression(tree);
1088
}
1089
}
1090
}
1091
1092
boolean leftSideBiggest(NODE *node, NODE **orderedNodes){
1093
NODE *leftMost = node->left;
1094
while (leftMost->left != NULL) leftMost = leftMost->left;
1095
int startLeft = leftMost->pos;
1096
int startRight = node->left->pos+1;
1097
int lengthLeft = startRight - startLeft;
1098
int lengthRight = node->pos - startRight;
1099
1100
if(lengthLeft > lengthRight){
1101
return TRUE;
1102
} else if (lengthLeft < lengthRight){
1103
return FALSE;
1104
} else {
1105
int i = 0;
1106
while (i<lengthLeft &&
1107
orderedNodes[startLeft + i]->contentLabel[0]==orderedNodes[startRight + i]->contentLabel[0] &&
1108
orderedNodes[startLeft + i]->contentLabel[1]==orderedNodes[startRight + i]->contentLabel[1]){
1109
i++;
1110
}
1111
return i==lengthLeft ||
1112
(orderedNodes[startLeft + i]->contentLabel[0] > orderedNodes[startRight + i]->contentLabel[0]) ||
1113
((orderedNodes[startLeft + i]->contentLabel[0] == orderedNodes[startRight + i]->contentLabel[0]) &&
1114
(orderedNodes[startLeft + i]->contentLabel[1] > orderedNodes[startRight + i]->contentLabel[1]));
1115
}
1116
}
1117
1118
void generateLabeledTree(TREE *tree, NODE **orderedNodes, int pos){
1119
int i;
1120
1121
if (pos == targetUnary + 2*targetBinary + 1){
1122
handleLabeledTree(tree);
1123
} else {
1124
NODE *currentNode = orderedNodes[pos];
1125
if (currentNode->type == 0){
1126
currentNode->contentLabel[0] = INVARIANT_LABEL;
1127
for (i=0; i<invariantCount; i++){
1128
if (!invariantsUsed[i]){
1129
currentNode->contentLabel[1] = i;
1130
invariantsUsed[i] = TRUE;
1131
generateLabeledTree(tree, orderedNodes, pos+1);
1132
invariantsUsed[i] = FALSE;
1133
}
1134
if(shouldGenerationProcessBeTerminated()){
1135
return;
1136
}
1137
}
1138
} else if (currentNode->type == 1){
1139
currentNode->contentLabel[0] = UNARY_LABEL;
1140
for (i=0; i<unaryOperatorCount; i++){
1141
currentNode->contentLabel[1] = unaryOperators[i];
1142
generateLabeledTree(tree, orderedNodes, pos+1);
1143
if(shouldGenerationProcessBeTerminated()){
1144
return;
1145
}
1146
}
1147
} else { // currentNode->type == 2
1148
//first try non-commutative binary operators
1149
currentNode->contentLabel[0] = NON_COMM_BINARY_LABEL;
1150
for (i=0; i<nonCommBinaryOperatorCount; i++){
1151
currentNode->contentLabel[1] = nonCommBinaryOperators[i];
1152
generateLabeledTree(tree, orderedNodes, pos+1);
1153
if(shouldGenerationProcessBeTerminated()){
1154
return;
1155
}
1156
}
1157
1158
//then try commutative binary operators
1159
if (leftSideBiggest(currentNode, orderedNodes)){
1160
currentNode->contentLabel[0] = COMM_BINARY_LABEL;
1161
for (i=0; i<commBinaryOperatorCount; i++){
1162
currentNode->contentLabel[1] = commBinaryOperators[i];
1163
generateLabeledTree(tree, orderedNodes, pos+1);
1164
if(shouldGenerationProcessBeTerminated()){
1165
return;
1166
}
1167
}
1168
}
1169
}
1170
}
1171
}
1172
1173
//------ Unlabeled tree generation -------
1174
1175
void handleTree(TREE *tree){
1176
treeCount++;
1177
if(onlyUnlabeled) return;
1178
1179
//start by ordering nodes
1180
NODE *orderedNodes[targetUnary + 2*targetBinary + 1];
1181
1182
int pos = 0;
1183
getOrderedNodes(tree->root, orderedNodes, &pos);
1184
1185
//mark all invariants as unused
1186
int i;
1187
for (i=0; i<invariantCount; i++){
1188
invariantsUsed[i] = FALSE;
1189
}
1190
1191
if(!allowMainInvariantInExpressions){
1192
invariantsUsed[mainInvariant] = TRUE;
1193
}
1194
1195
generateLabeledTree(tree, orderedNodes, 0);
1196
}
1197
1198
void generateTreeImpl(TREE *tree){
1199
int i, start;
1200
1201
if(tree->unaryCount > targetUnary + 1 || tree->binaryCount > targetBinary)
1202
return;
1203
1204
if(isComplete(tree)){
1205
handleTree(tree);
1206
return;
1207
}
1208
1209
start = tree->levelWidth[tree->depth-1]-1;
1210
while(start>=0 && tree->nodesAtDepth[tree->depth-1][start]->type==0){
1211
start--;
1212
}
1213
if(start>=0 && tree->nodesAtDepth[tree->depth-1][start]->type==1){
1214
start--;
1215
}
1216
1217
for(i=start+1; i<tree->levelWidth[tree->depth-1]; i++){
1218
NODE *parent = tree->nodesAtDepth[tree->depth-1][i];
1219
addChildToNodeInTree(tree, parent);
1220
generateTreeImpl(tree);
1221
removeChildFromNodeInTree(tree, parent);
1222
if(shouldGenerationProcessBeTerminated()){
1223
return;
1224
}
1225
}
1226
1227
for(i=0; i<tree->levelWidth[tree->depth]; i++){
1228
NODE *parent = tree->nodesAtDepth[tree->depth][i];
1229
addChildToNodeInTree(tree, parent);
1230
generateTreeImpl(tree);
1231
removeChildFromNodeInTree(tree, parent);
1232
if(shouldGenerationProcessBeTerminated()){
1233
return;
1234
}
1235
}
1236
}
1237
1238
void generateTree(int unary, int binary){
1239
if(verbose){
1240
fprintf(stderr, "Generating trees with %d unary node%s and %d binary node%s.\n",
1241
unary, unary == 1 ? "" : "s", binary, binary == 1 ? "" : "s");
1242
}
1243
TREE tree;
1244
targetUnary = unary;
1245
targetBinary = binary;
1246
initTree(&tree);
1247
1248
if (unary==0 && binary==0){
1249
handleTree(&tree);
1250
} else {
1251
addChildToNodeInTree(&tree, tree.root);
1252
generateTreeImpl(&tree);
1253
removeChildFromNodeInTree(&tree, tree.root);
1254
}
1255
1256
freeTree(&tree);
1257
1258
if(verbose && doConjecturing){
1259
fprintf(stderr, "Status: %lu unlabeled tree%s, %lu labeled tree%s, %lu expression%s\n",
1260
treeCount, treeCount==1 ? "" : "s",
1261
labeledTreeCount, labeledTreeCount==1 ? "" : "s",
1262
validExpressionsCount, validExpressionsCount==1 ? "" : "s");
1263
}
1264
}
1265
1266
//------ conjecturing functions -------
1267
1268
void getNextOperatorCount(int *unary, int *binary){
1269
if(nextOperatorCountMethod == GRINVIN_NEXT_OPERATOR_COUNT){
1270
if((*binary)==0){
1271
if((*unary)%2==0){
1272
(*binary) = (*unary)/2;
1273
(*unary) = 1;
1274
} else {
1275
(*binary) = (*unary + 1)/2;
1276
(*unary) = 0;
1277
}
1278
} else {
1279
(*binary)--;
1280
(*unary)+=2;
1281
}
1282
} else {
1283
BAILOUT("Unknown method to determine next operator count")
1284
}
1285
}
1286
1287
void conjecture(int startUnary, int startBinary){
1288
int unary = startUnary;
1289
int binary = startBinary;
1290
int availableInvariants = invariantCount - (allowMainInvariantInExpressions ? 0 : 1);
1291
1292
generateTree(unary, binary);
1293
getNextOperatorCount(&unary, &binary);
1294
while(!shouldGenerationProcessBeTerminated()) {
1295
if(unary <= MAX_UNARY_COUNT &&
1296
binary <= MAX_BINARY_COUNT &&
1297
availableInvariants >= binary+1)
1298
generateTree(unary, binary);
1299
getNextOperatorCount(&unary, &binary);
1300
}
1301
}
1302
1303
//------ Various functions -------
1304
1305
void readOperators(){
1306
//set operator counts to zero
1307
unaryOperatorCount = commBinaryOperatorCount = nonCommBinaryOperatorCount = 0;
1308
1309
//read the operators from the file
1310
int i;
1311
int operatorCount = 0;
1312
char line[1024]; //array to temporarily store a line
1313
if(fgets(line, sizeof(line), operatorFile)){
1314
if(sscanf(line, "%d", &operatorCount) != 1) {
1315
BAILOUT("Error while reading operators")
1316
}
1317
} else {
1318
BAILOUT("Error while reading operators")
1319
}
1320
for(i=0; i<operatorCount; i++){
1321
if(fgets(line, sizeof(line), operatorFile)){
1322
//read operator
1323
char operatorType = 'E'; //E for Error
1324
int operatorNumber = -1;
1325
if(sscanf(line, "%c %d", &operatorType, &operatorNumber) != 2) {
1326
BAILOUT("Error while reading operators")
1327
}
1328
//process operator
1329
if(operatorType=='U'){
1330
unaryOperators[unaryOperatorCount++] = operatorNumber;
1331
} else if(operatorType=='C'){
1332
commBinaryOperators[commBinaryOperatorCount++] = operatorNumber;
1333
} else if(operatorType=='N'){
1334
nonCommBinaryOperators[nonCommBinaryOperatorCount++] = operatorNumber;
1335
} else {
1336
fprintf(stderr, "Unknown operator type '%c' -- exiting!\n", operatorType);
1337
exit(EXIT_FAILURE);
1338
}
1339
} else {
1340
BAILOUT("Error while reading operators")
1341
}
1342
}
1343
}
1344
1345
char *trim(char *str){
1346
//http://stackoverflow.com/questions/122616/how-do-i-trim-leading-trailing-whitespace-in-a-standard-way
1347
char *end;
1348
1349
// Trim leading space
1350
while(isspace(*str)) str++;
1351
1352
if(*str == 0) // All spaces?
1353
return str;
1354
1355
// Trim trailing space
1356
end = str + strlen(str) - 1;
1357
while(end > str && isspace(*end)) end--;
1358
1359
// Write new null terminator
1360
*(end+1) = 0;
1361
1362
return str;
1363
}
1364
1365
void readInvariantsValues(){
1366
int i,j;
1367
char line[1024]; //array to temporarily store a line
1368
1369
//first read number of invariants and number of entities
1370
if(fgets(line, sizeof(line), invariantsFile)){
1371
if(sscanf(line, "%d %d %d", &objectCount, &invariantCount, &mainInvariant) != 3) {
1372
BAILOUT("Error while reading invariants")
1373
}
1374
mainInvariant--; //internally we work zero-based
1375
} else {
1376
BAILOUT("Error while reading invariants")
1377
}
1378
1379
if(objectCount > MAX_OBJECT_COUNT){
1380
fprintf(stderr, "Recompile with a higher value for MAX_OBJECT_COUNT to handle this many objects.\n");
1381
fprintf(stderr, "Number of objects is %d.\n", objectCount);
1382
fprintf(stderr, "Value of MAX_OBJECT_COUNT is %d.\n", MAX_OBJECT_COUNT);
1383
exit(EXIT_FAILURE);
1384
}
1385
1386
if(invariantCount > MAX_INVARIANT_COUNT){
1387
fprintf(stderr, "Recompile with a higher value for MAX_INVARIANT_COUNT to handle this many invariants.\n");
1388
fprintf(stderr, "Number of invariants is %d.\n", invariantCount);
1389
fprintf(stderr, "Value of MAX_INVARIANT_COUNT is %d.\n", MAX_INVARIANT_COUNT);
1390
exit(EXIT_FAILURE);
1391
}
1392
1393
//maybe read invariant names
1394
if(useInvariantNames){
1395
for(j=0; j<invariantCount; j++){
1396
if(fgets(line, sizeof(line), invariantsFile)){
1397
char *name = trim(line);
1398
strcpy(invariantNames[j], name);
1399
invariantNamesPointers[j] = invariantNames[j];
1400
} else {
1401
BAILOUT("Error while reading invariant names")
1402
}
1403
}
1404
}
1405
1406
if(theoryProvided){
1407
//first read the known theory
1408
for(i=0; i<objectCount; i++){
1409
if(fgets(line, sizeof(line), invariantsFile)){
1410
double value = 0.0;
1411
if(sscanf(line, "%lf", &value) != 1) {
1412
BAILOUT("Error while reading known theory")
1413
}
1414
knownTheory[i] = value;
1415
} else {
1416
BAILOUT("Error while reading known theory")
1417
}
1418
}
1419
}
1420
1421
//start reading the individual values
1422
for(i=0; i<objectCount; i++){
1423
for(j=0; j<invariantCount; j++){
1424
if(fgets(line, sizeof(line), invariantsFile)){
1425
double value = 0.0;
1426
if(sscanf(line, "%lf", &value) != 1) {
1427
BAILOUT("Error while reading invariants")
1428
}
1429
invariantValues[i][j] = value;
1430
} else {
1431
BAILOUT("Error while reading invariants")
1432
}
1433
}
1434
}
1435
}
1436
1437
void readInvariantsValues_propertyBased(){
1438
int i,j;
1439
char line[1024]; //array to temporarily store a line
1440
1441
//first read number of invariants and number of entities
1442
if(fgets(line, sizeof(line), invariantsFile)){
1443
if(sscanf(line, "%d %d %d", &objectCount, &invariantCount, &mainInvariant) != 3) {
1444
BAILOUT("Error while reading invariants")
1445
}
1446
mainInvariant--; //internally we work zero-based
1447
} else {
1448
BAILOUT("Error while reading invariants")
1449
}
1450
1451
if(objectCount > MAX_OBJECT_COUNT){
1452
fprintf(stderr, "Recompile with a higher value for MAX_OBJECT_COUNT to handle this many objects.\n");
1453
fprintf(stderr, "Number of objects is %d.\n", objectCount);
1454
fprintf(stderr, "Value of MAX_OBJECT_COUNT is %d.\n", MAX_OBJECT_COUNT);
1455
exit(EXIT_FAILURE);
1456
}
1457
1458
if(invariantCount > MAX_INVARIANT_COUNT){
1459
fprintf(stderr, "Recompile with a higher value for MAX_INVARIANT_COUNT to handle this many invariants.\n");
1460
fprintf(stderr, "Number of invariants is %d.\n", invariantCount);
1461
fprintf(stderr, "Value of MAX_INVARIANT_COUNT is %d.\n", MAX_INVARIANT_COUNT);
1462
exit(EXIT_FAILURE);
1463
}
1464
1465
//maybe read invariant names
1466
if(useInvariantNames){
1467
for(j=0; j<invariantCount; j++){
1468
if(fgets(line, sizeof(line), invariantsFile)){
1469
char *name = trim(line);
1470
strcpy(invariantNames[j], name);
1471
invariantNamesPointers[j] = invariantNames[j];
1472
} else {
1473
BAILOUT("Error while reading invariant names")
1474
}
1475
}
1476
}
1477
1478
if(theoryProvided){
1479
//first read the known theory
1480
for(i=0; i<objectCount; i++){
1481
if(fgets(line, sizeof(line), invariantsFile)){
1482
boolean value = UNDEFINED;
1483
if(sscanf(line, "%d", &value) != 1) {
1484
BAILOUT("Error while reading known theory")
1485
}
1486
if(value == UNDEFINED ||
1487
value == FALSE ||
1488
value == TRUE){
1489
knownTheory_propertyBased[i] = value;
1490
} else {
1491
BAILOUT("Error while reading known theory")
1492
}
1493
} else {
1494
BAILOUT("Error while reading known theory")
1495
}
1496
}
1497
}
1498
1499
//start reading the individual values
1500
for(i=0; i<objectCount; i++){
1501
for(j=0; j<invariantCount; j++){
1502
if(fgets(line, sizeof(line), invariantsFile)){
1503
boolean value = UNDEFINED;
1504
if(sscanf(line, "%d", &value) != 1) {
1505
BAILOUT("Error while reading invariants")
1506
}
1507
if(value == UNDEFINED ||
1508
value == FALSE ||
1509
value == TRUE){
1510
invariantValues_propertyBased[i][j] = value;
1511
} else {
1512
BAILOUT("Error while reading invariants")
1513
}
1514
} else {
1515
BAILOUT("Error while reading invariants")
1516
}
1517
}
1518
}
1519
}
1520
1521
boolean checkKnownTheory(){
1522
if(!theoryProvided) return TRUE;
1523
int i;
1524
int hitCount = 0;
1525
for(i=0; i<objectCount; i++){
1526
if(isnan(invariantValues[i][mainInvariant])){
1527
continue; //skip NaN
1528
}
1529
if(isnan(knownTheory[i])){
1530
continue; //skip NaN
1531
}
1532
if(!handleComparator(invariantValues[i][mainInvariant], knownTheory[i], inequality)){
1533
return FALSE;
1534
} else if(invariantValues[i][mainInvariant] == knownTheory[i]){
1535
hitCount++;
1536
}
1537
}
1538
if(hitCount==objectCount){
1539
fprintf(stderr, "Warning: can not improve on known theory using these objects.\n");
1540
}
1541
return TRUE;
1542
}
1543
1544
boolean checkKnownTheory_propertyBased(){
1545
if(!theoryProvided) return TRUE;
1546
int i;
1547
int hitCount = 0;
1548
for(i=0; i<objectCount; i++){
1549
if(invariantValues_propertyBased[i][mainInvariant]==UNDEFINED){
1550
continue; //skip undefined values
1551
}
1552
if(knownTheory_propertyBased[i] == UNDEFINED){
1553
continue; //skip NaN
1554
}
1555
if(!handleComparator_propertyBased(
1556
invariantValues_propertyBased[i][mainInvariant],
1557
knownTheory_propertyBased[i], inequality)){
1558
return FALSE;
1559
} else if(!(knownTheory_propertyBased[i]) ==
1560
!(invariantValues_propertyBased[i][mainInvariant])) {
1561
hitCount++;
1562
}
1563
}
1564
if(hitCount==objectCount){
1565
fprintf(stderr, "Warning: can not improve on known theory using these objects.\n");
1566
}
1567
return TRUE;
1568
}
1569
1570
void printInvariantValues(FILE *f){
1571
int i, j;
1572
//header row
1573
fprintf(f, " ");
1574
if(theoryProvided){
1575
fprintf(f, "Known theory ");
1576
}
1577
for(j=0; j<invariantCount; j++){
1578
fprintf(f, "Invariant %2d ", j+1);
1579
}
1580
fprintf(f, "\n");
1581
//table
1582
for(i=0; i<objectCount; i++){
1583
fprintf(f, "%3d) ", i+1);
1584
if(theoryProvided){
1585
fprintf(f, "%11.6lf ", knownTheory[i]);
1586
}
1587
for(j=0; j<invariantCount; j++){
1588
fprintf(f, "%11.6lf ", invariantValues[i][j]);
1589
}
1590
fprintf(f, "\n");
1591
}
1592
}
1593
1594
void printInvariantValues_propertyBased(FILE *f){
1595
int i, j;
1596
//header row
1597
fprintf(f, " ");
1598
if(theoryProvided){
1599
fprintf(f, "Known theory ");
1600
}
1601
for(j=0; j<invariantCount; j++){
1602
fprintf(f, "Invariant %2d ", j+1);
1603
}
1604
fprintf(f, "\n");
1605
//table
1606
for(i=0; i<objectCount; i++){
1607
fprintf(f, "%3d) ", i+1);
1608
if(theoryProvided){
1609
if(knownTheory_propertyBased[i] == UNDEFINED){
1610
fprintf(f, " UNDEFINED ");
1611
} else if(knownTheory_propertyBased[i]){
1612
fprintf(f, " TRUE ");
1613
} else {
1614
fprintf(f, " FALSE ");
1615
}
1616
}
1617
for(j=0; j<invariantCount; j++){
1618
if(invariantValues_propertyBased[i][j] == UNDEFINED){
1619
fprintf(f, " UNDEFINED ");
1620
} else if(invariantValues_propertyBased[i][j]){
1621
fprintf(f, " TRUE ");
1622
} else {
1623
fprintf(f, " FALSE ");
1624
}
1625
}
1626
fprintf(f, "\n");
1627
}
1628
}
1629
1630
//===================================================================
1631
// Usage methods
1632
//===================================================================
1633
void help(char *name){
1634
fprintf(stderr, "The program %s constructs expressions based on provided parameters.\n\n", name);
1635
fprintf(stderr, "\e[1mUsage\n=====\e[21m\n");
1636
fprintf(stderr, " %s [options] -u unary binary\n", name);
1637
fprintf(stderr, " Generates expression trees with the given number of unary and\n");
1638
fprintf(stderr, " binary operators.\n");
1639
fprintf(stderr, " %s [options] -l unary binary invariants\n", name);
1640
fprintf(stderr, " Generates labeled expression trees with the given number of unary\n");
1641
fprintf(stderr, " and binary operators and the given number of invariants.\n");
1642
fprintf(stderr, " %s [options] -e unary binary\n", name);
1643
fprintf(stderr, " Generates valid expressions with the given number of unary and\n");
1644
fprintf(stderr, " binary operators.\n");
1645
fprintf(stderr, " %s [options] -c [unary binary]\n", name);
1646
fprintf(stderr, " Use heuristics to make conjectures.\n");
1647
fprintf(stderr, "\n\n");
1648
fprintf(stderr, "\e[1mValid options\n=============\e[21m\n");
1649
fprintf(stderr, "\e[1m* Generated types\e[21m (exactly one of these four should be used)\n");
1650
fprintf(stderr, " -u, --unlabeled\n");
1651
fprintf(stderr, " Generate unlabeled expression trees.\n");
1652
fprintf(stderr, " -l, --labeled\n");
1653
fprintf(stderr, " Generate labeled expression trees.\n");
1654
fprintf(stderr, " -e, --expressions\n");
1655
fprintf(stderr, " Generate true expressions.\n");
1656
fprintf(stderr, " -c, --conjecture\n");
1657
fprintf(stderr, " Use heuristics to make conjectures.\n");
1658
fprintf(stderr, "\n");
1659
fprintf(stderr, "\e[1m* Parameters\e[21m\n");
1660
fprintf(stderr, " --unary n\n");
1661
fprintf(stderr, " The number of unary operators used during the generation of labeled\n");
1662
fprintf(stderr, " expression trees. This value is ignored when generating valid\n");
1663
fprintf(stderr, " expressions.\n");
1664
fprintf(stderr, " --commutative n\n");
1665
fprintf(stderr, " The number of commutative binary operators used during the generation\n");
1666
fprintf(stderr, " of labeled expression trees. This value is ignored when generating valid\n");
1667
fprintf(stderr, " expressions.\n");
1668
fprintf(stderr, " --non-commutative n\n");
1669
fprintf(stderr, " The number of non-commutative binary operators used during the\n");
1670
fprintf(stderr, " generation of labeled expression trees. This value is ignored when\n");
1671
fprintf(stderr, " generating valid expressions.\n");
1672
fprintf(stderr, " --allow-main-invariant\n");
1673
fprintf(stderr, " Allow the main invariant to appear in the generated expressions.\n");
1674
fprintf(stderr, " --all-operators\n");
1675
fprintf(stderr, " Use all the available operators. This flag will only be used when\n");
1676
fprintf(stderr, " generating expressions or when in conjecturing mode. The result is\n");
1677
fprintf(stderr, " that no operators are read from the input.\n");
1678
fprintf(stderr, " -t, --theory\n");
1679
fprintf(stderr, " Known theory will be supplied. When using this flag, you need to\n");
1680
fprintf(stderr, " give the best known value for each object: after specifying the\n");
1681
fprintf(stderr, " number objects, invariants and the main invariant (and possibly\n");
1682
fprintf(stderr, " the invariant names), and before specifying the invariant values.\n");
1683
fprintf(stderr, " It is verified whether this known theory is indeed consistent with\n");
1684
fprintf(stderr, " the selected main invariant.\n");
1685
fprintf(stderr, " --leq\n");
1686
fprintf(stderr, " Use the comparator <= when constructing conjectures. The conjectures will\n");
1687
fprintf(stderr, " be of the form 'main invariant <= f(invariants)'. This is the default\n");
1688
fprintf(stderr, " comparator.\n");
1689
fprintf(stderr, " --less\n");
1690
fprintf(stderr, " Use the comparator < when constructing conjectures. The conjectures will\n");
1691
fprintf(stderr, " be of the form 'main invariant < f(invariants)'.\n");
1692
fprintf(stderr, " --geq\n");
1693
fprintf(stderr, " Use the comparator >= when constructing conjectures. The conjectures will\n");
1694
fprintf(stderr, " be of the form 'main invariant >= f(invariants)'.\n");
1695
fprintf(stderr, " --greater\n");
1696
fprintf(stderr, " Use the comparator > when constructing conjectures. The conjectures will\n");
1697
fprintf(stderr, " be of the form 'main invariant > f(invariants)'.\n");
1698
fprintf(stderr, " -p, --property\n");
1699
fprintf(stderr, " Make property based conjecture instead of the default invariant based\n");
1700
fprintf(stderr, " conjectures.\n");
1701
fprintf(stderr, " --sufficient\n");
1702
fprintf(stderr, " Create sufficient conditions when constructing property based\n");
1703
fprintf(stderr, " conjectures. The conjectures will be of the form 'main property <- \n");
1704
fprintf(stderr, " f(properties)'. This is the default for property based conjectures.\n");
1705
fprintf(stderr, " --necessary\n");
1706
fprintf(stderr, " Create necessary conditions when constructing property based conjectures.\n");
1707
fprintf(stderr, " The conjectures will be of the form 'main property -> f(properties)'.\n");
1708
fprintf(stderr, "\n");
1709
fprintf(stderr, "\e[1m* Heuristics\e[21m\n");
1710
fprintf(stderr, " --dalmatian\n");
1711
fprintf(stderr, " Use the dalmatian heuristic to make conjectures.\n");
1712
fprintf(stderr, " --grinvin\n");
1713
fprintf(stderr, " Use the heuristic from Grinvin to make conjectures.\n");
1714
fprintf(stderr, "\n");
1715
fprintf(stderr, "\e[1m* Various options\e[21m\n");
1716
fprintf(stderr, " -h, --help\n");
1717
fprintf(stderr, " Print this help and return.\n");
1718
fprintf(stderr, " -v, --verbose\n");
1719
fprintf(stderr, " Make the program more verbose.\n");
1720
fprintf(stderr, " --example\n");
1721
fprintf(stderr, " Print an example of an input file for the operators. It is advised to\n");
1722
fprintf(stderr, " use this example as a starting point for your own file.\n");
1723
fprintf(stderr, " --limits name\n");
1724
fprintf(stderr, " Print the limit for the given name to stdout. Possible names are: all,\n");
1725
fprintf(stderr, " MAX_OBJECT_COUNT, MAX_INVARIANT_COUNT.\n");
1726
fprintf(stderr, " --time t\n");
1727
fprintf(stderr, " Stops the generation after t seconds. Zero seconds means that the\n");
1728
fprintf(stderr, " generation won't be stopped. The default is 0.\n");
1729
fprintf(stderr, " --operators filename\n");
1730
fprintf(stderr, " Specifies the file containing the operators to be used. Defaults to\n");
1731
fprintf(stderr, " stdin.\n");
1732
fprintf(stderr, " --invariants filename\n");
1733
fprintf(stderr, " Specifies the file containing the invariant values. Defaults to stdin.\n");
1734
fprintf(stderr, " --print-valid-expressions\n");
1735
fprintf(stderr, " Causes all valid expressions that are found to be printed to stderr.\n");
1736
fprintf(stderr, "\n\n");
1737
fprintf(stderr, "\e[1mInput format\n============\e[21m\n");
1738
fprintf(stderr, "The operators that should be used and the invariant values are read from an in-\n");
1739
fprintf(stderr, "put file. By default these are both read from stdin. In this case the operators\n");
1740
fprintf(stderr, "are read first and then the invariants. If the option \e[4m--all-operators\e[24m is speci-\n");
1741
fprintf(stderr, "fied then reading the operators is skipped and all operators are used.\n");
1742
fprintf(stderr, "We will now describe the format of these input files. A general rule is that\n");
1743
fprintf(stderr, "the maximum length of each line is 1024 characters and after each input you can\n");
1744
fprintf(stderr, "add comments (respecting the 1024 character limit).\n\n");
1745
fprintf(stderr, "\e[1m* Operators\e[21m\n");
1746
fprintf(stderr, " The first line gives the number of operators that will follow. After that\n");
1747
fprintf(stderr, " line each line starts with a character followed by whitespace followed by\n");
1748
fprintf(stderr, " a number.\n");
1749
fprintf(stderr, " The character is one of:\n");
1750
fprintf(stderr, " - U: unary operator\n");
1751
fprintf(stderr, " - C: commutative binary operator\n");
1752
fprintf(stderr, " - U: non-commutative binary operator\n");
1753
fprintf(stderr, " The number specifies which operator is meant. An overview of the operators\n");
1754
fprintf(stderr, " can be obtained by running the program with the option \e[4m--example\e[24m. This out-\n");
1755
fprintf(stderr, " puts an exemplary input file which selects all operators.\n\n");
1756
fprintf(stderr, "\e[1m* Invariants\e[21m\n");
1757
fprintf(stderr, " The first line contains the number of objects, the number of invariants and\n");
1758
fprintf(stderr, " the number of the main invariant seperated by spaces. In case you are using\n");
1759
fprintf(stderr, " the option \e[4m--invariant-names\e[24m you first have to specify the invariant names.\n");
1760
fprintf(stderr, " Each invariant name is written on a single line without any comments. The\n");
1761
fprintf(stderr, " whole line is used as the invariant name (white spaces at the beginning and\n");
1762
fprintf(stderr, " end of the line are removed). After that the invariant values follow. One\n");
1763
fprintf(stderr, " invariant value per line in this order: 1st value of 1st object, 2nd value of\n");
1764
fprintf(stderr, " 1st object,..., 1st value of 2nd object,...\n");
1765
fprintf(stderr, " We give an example from graph theory to illustrate the input of invariant\n");
1766
fprintf(stderr, " values. We have 4 invariants: number of vertices, number of edges, maximum\n");
1767
fprintf(stderr, " and minimum degree. We have 3 objects: C3, C5 and K5. So we have these\n");
1768
fprintf(stderr, " invariant values:\n");
1769
fprintf(stderr, " \n");
1770
fprintf(stderr, " #vertices #edges max. degree min. degree\n");
1771
fprintf(stderr, " C3 3 3 2 2\n");
1772
fprintf(stderr, " C5 5 5 2 2\n");
1773
fprintf(stderr, " K5 5 10 4 4\n");
1774
fprintf(stderr, " \n");
1775
fprintf(stderr, " If you want to find upper bounds for the number of edges, then the invariant\n");
1776
fprintf(stderr, " values input file would like like this:\n");
1777
fprintf(stderr, " \e[2m\n");
1778
fprintf(stderr, " 3 4 2\n");
1779
fprintf(stderr, " Number of vertices\n");
1780
fprintf(stderr, " Number of edges\n");
1781
fprintf(stderr, " Maximum degree\n");
1782
fprintf(stderr, " Minimum degree\n");
1783
fprintf(stderr, " 3\n 3\n 2\n 2\n");
1784
fprintf(stderr, " 5\n 5\n 2\n 2\n");
1785
fprintf(stderr, " 5\n 10\n 4\n 4\n");
1786
fprintf(stderr, " \e[22m\n");
1787
fprintf(stderr, " The example above assumes you are using the option \e[4m--invariant-names\e[24m. If this\n");
1788
fprintf(stderr, " is not the case, then you can skip the second until fifth line.\n");
1789
fprintf(stderr, "\n\n");
1790
fprintf(stderr, "\e[1mHeuristics\n==========\e[21m\n");
1791
fprintf(stderr, "This program allows the heuristic used to select bounds to be altered. Currently\n");
1792
fprintf(stderr, "there are two heuristics implemented. We will give a brief description of each\n");
1793
fprintf(stderr, "of the heuristics.\n");
1794
fprintf(stderr, "\e[1m* Dalmatian\e[21m\n");
1795
fprintf(stderr, " The Dalmatian heuristic, developed by Siemion Fajtlowicz, is used in Graffiti\n");
1796
fprintf(stderr, " and Graffiti.pc. It selects bounds based on truth and significance.\n");
1797
fprintf(stderr, " A bound is accepted if it is true for all objects in the considered database\n");
1798
fprintf(stderr, " and if it is tighter than all the other bounds for at least one object in the\n");
1799
fprintf(stderr, " considered database. This implies that there are at most as many bounds as\n");
1800
fprintf(stderr, " there are objects in the considered database.\n");
1801
fprintf(stderr, "\e[1m* Grinvin\e[21m\n");
1802
fprintf(stderr, " This is the heuristic that is used by default in Grinvin. It selects bounds\n");
1803
fprintf(stderr, " based on truth and relative complexity.\n");
1804
fprintf(stderr, " A bound is accepted if it is true for all objects in the considered database\n");
1805
fprintf(stderr, " and if it has the smallest value error. The value error is defined as the sum\n");
1806
fprintf(stderr, " of the squares of the differences between the values and the bounds for all\n");
1807
fprintf(stderr, " objects in the database. This heuristic keeps generating expressions while\n");
1808
fprintf(stderr, " the product of the number of objects in the considered database and two to\n");
1809
fprintf(stderr, " the power number of unary plus twice the number of binary operators is less\n");
1810
fprintf(stderr, " than the best value error up to that point.\n");
1811
fprintf(stderr, "\n\n");
1812
fprintf(stderr, "Please mail \e[4mnico [DOT] vancleemput [AT] gmail [DOT] com\e[24m in case of trouble.\n");
1813
}
1814
1815
void usage(char *name){
1816
fprintf(stderr, "Usage: %s [options]\n", name);
1817
fprintf(stderr, "For more information type: %s -h \n\n", name);
1818
}
1819
1820
/*
1821
* process any command-line options.
1822
*/
1823
int processOptions(int argc, char **argv) {
1824
int c;
1825
char *name = argv[0];
1826
static struct option long_options[] = {
1827
{"unary", required_argument, NULL, 0},
1828
{"commutative", required_argument, NULL, 0},
1829
{"non-commutative", required_argument, NULL, 0},
1830
{"example", no_argument, NULL, 0},
1831
{"time", required_argument, NULL, 0},
1832
{"allow-main-invariant", no_argument, NULL, 0},
1833
{"all-operators", no_argument, NULL, 0},
1834
{"dalmatian", no_argument, NULL, 0},
1835
{"grinvin", no_argument, NULL, 0},
1836
{"invariant-names", no_argument, NULL, 0},
1837
{"operators", required_argument, NULL, 0},
1838
{"invariants", required_argument, NULL, 0},
1839
{"leq", no_argument, NULL, 0},
1840
{"less", no_argument, NULL, 0},
1841
{"geq", no_argument, NULL, 0},
1842
{"greater", no_argument, NULL, 0},
1843
{"limits", required_argument, NULL, 0},
1844
{"allowed-skips", required_argument, NULL, 0},
1845
{"print-valid-expressions", no_argument, NULL, 0},
1846
{"sufficient", no_argument, NULL, 0},
1847
{"necessary", no_argument, NULL, 0},
1848
{"help", no_argument, NULL, 'h'},
1849
{"verbose", no_argument, NULL, 'v'},
1850
{"unlabeled", no_argument, NULL, 'u'},
1851
{"labeled", no_argument, NULL, 'l'},
1852
{"expressions", no_argument, NULL, 'e'},
1853
{"conjecture", no_argument, NULL, 'c'},
1854
{"output", required_argument, NULL, 'o'},
1855
{"property", no_argument, NULL, 'p'},
1856
{"theory", no_argument, NULL, 't'}
1857
};
1858
int option_index = 0;
1859
1860
while ((c = getopt_long(argc, argv, "hvuleco:pt", long_options, &option_index)) != -1) {
1861
switch (c) {
1862
case 0:
1863
//handle long option with no alternative
1864
switch(option_index) {
1865
case 0:
1866
unaryOperatorCount = strtol(optarg, NULL, 10);
1867
break;
1868
case 1:
1869
commBinaryOperatorCount = strtol(optarg, NULL, 10);
1870
break;
1871
case 2:
1872
nonCommBinaryOperatorCount = strtol(optarg, NULL, 10);
1873
break;
1874
case 3:
1875
writeUnaryOperatorExample(stdout);
1876
writeCommutativeBinaryOperatorExample(stdout);
1877
writeNonCommutativeBinaryOperatorExample(stdout);
1878
return EXIT_SUCCESS;
1879
break;
1880
case 4:
1881
timeOut = strtoul(optarg, NULL, 10);
1882
break;
1883
case 5:
1884
allowMainInvariantInExpressions = TRUE;
1885
break;
1886
case 6:
1887
operatorFile = NULL;
1888
closeOperatorFile = FALSE;
1889
break;
1890
case 7:
1891
selectedHeuristic = DALMATIAN_HEURISTIC;
1892
if(propertyBased){
1893
heuristicInit = dalmatianHeuristicInit_propertyBased;
1894
heuristicStopConditionReached = dalmatianHeuristicStopConditionReached_propertyBased;
1895
heuristicPostProcessing = dalmatianHeuristicPostProcessing_propertyBased;
1896
} else {
1897
heuristicInit = dalmatianHeuristicInit;
1898
heuristicStopConditionReached = dalmatianHeuristicStopConditionReached;
1899
heuristicPostProcessing = dalmatianHeuristicPostProcessing;
1900
}
1901
break;
1902
case 8:
1903
selectedHeuristic = GRINVIN_HEURISTIC;
1904
heuristicInit = grinvinHeuristicInit;
1905
heuristicStopConditionReached = grinvinHeuristicStopConditionReached;
1906
heuristicPostProcessing = grinvinHeuristicPostProcessing;
1907
break;
1908
case 9:
1909
useInvariantNames = TRUE;
1910
break;
1911
case 10:
1912
operatorFile = fopen(optarg, "r");
1913
closeOperatorFile = TRUE;
1914
break;
1915
case 11:
1916
invariantsFile = fopen(optarg, "r");
1917
closeInvariantsFile = TRUE;
1918
break;
1919
case 12:
1920
inequality = LEQ;
1921
break;
1922
case 13:
1923
inequality = LESS;
1924
break;
1925
case 14:
1926
inequality = GEQ;
1927
break;
1928
case 15:
1929
inequality = GREATER;
1930
break;
1931
case 16:
1932
if(strcmp(optarg, "all")==0){
1933
fprintf(stdout, "MAX_OBJECT_COUNT: %d\n", MAX_OBJECT_COUNT);
1934
fprintf(stdout, "MAX_INVARIANT_COUNT: %d\n", MAX_INVARIANT_COUNT);
1935
} else if(strcmp(optarg, "MAX_OBJECT_COUNT")==0){
1936
fprintf(stdout, "%d\n", MAX_OBJECT_COUNT);
1937
} else if(strcmp(optarg, "MAX_INVARIANT_COUNT")==0){
1938
fprintf(stdout, "%d\n", MAX_INVARIANT_COUNT);
1939
} else {
1940
fprintf(stderr, "Unknown limit: %s\n", optarg);
1941
return EXIT_FAILURE;
1942
}
1943
return EXIT_SUCCESS;
1944
break;
1945
case 17:
1946
allowedPercentageOfSkips = strtof(optarg, NULL);
1947
break;
1948
case 18:
1949
printValidExpressions = TRUE;
1950
break;
1951
case 19:
1952
inequality = SUFFICIENT;
1953
break;
1954
case 20:
1955
inequality = NECESSARY;
1956
break;
1957
default:
1958
fprintf(stderr, "Illegal option index %d.\n", option_index);
1959
usage(name);
1960
return EXIT_FAILURE;
1961
}
1962
break;
1963
case 'h':
1964
help(name);
1965
return EXIT_SUCCESS;
1966
case 'v':
1967
verbose = TRUE;
1968
break;
1969
case 'u':
1970
onlyUnlabeled = TRUE;
1971
break;
1972
case 'l':
1973
onlyLabeled = TRUE;
1974
break;
1975
case 'e':
1976
generateExpressions = TRUE;
1977
break;
1978
case 'c':
1979
doConjecturing = TRUE;
1980
break;
1981
case 'o':
1982
switch(optarg[0]) {
1983
case 's':
1984
case 'h':
1985
outputType = optarg[0];
1986
break;
1987
default:
1988
fprintf(stderr, "Illegal output type %s.\n", optarg);
1989
usage(name);
1990
return EXIT_FAILURE;
1991
}
1992
break;
1993
case 'p':
1994
propertyBased = TRUE;
1995
//heuristic needs to be chosen after switching to property based conjecturing
1996
selectedHeuristic = NO_HEURISTIC;
1997
unaryOperatorCount = 1;
1998
/*
1999
* 1: not
2000
*/
2001
commBinaryOperatorCount = 3;
2002
/*
2003
* 1: and
2004
* 2: or
2005
* 3: xor
2006
*/
2007
nonCommBinaryOperatorCount = 1;
2008
/*
2009
* 1: implication
2010
*/
2011
break;
2012
case 't':
2013
theoryProvided = TRUE;
2014
break;
2015
case '?':
2016
usage(name);
2017
return EXIT_FAILURE;
2018
default:
2019
fprintf(stderr, "Illegal option %c.\n", c);
2020
usage(name);
2021
return EXIT_FAILURE;
2022
}
2023
}
2024
2025
if(onlyLabeled + onlyUnlabeled +
2026
generateExpressions + doConjecturing != TRUE){
2027
fprintf(stderr, "Please select one type to be generated.\n");
2028
usage(name);
2029
return EXIT_FAILURE;
2030
}
2031
2032
if(doConjecturing && selectedHeuristic==NO_HEURISTIC){
2033
fprintf(stderr, "Please select a heuristic to make conjectures.\n");
2034
usage(name);
2035
return EXIT_FAILURE;
2036
}
2037
2038
// check the non-option arguments
2039
if ((onlyUnlabeled || generateExpressions) && argc - optind != 2) {
2040
usage(name);
2041
return EXIT_FAILURE;
2042
}
2043
2044
if (onlyLabeled && argc - optind != 3) {
2045
usage(name);
2046
return EXIT_FAILURE;
2047
}
2048
2049
if (doConjecturing && !((argc == optind) || (argc - optind == 2))) {
2050
usage(name);
2051
return EXIT_FAILURE;
2052
}
2053
2054
// check comparator for property-based conjectures
2055
if (propertyBased &&
2056
!((inequality == SUFFICIENT) || (inequality == NECESSARY))){
2057
fprintf(stderr, "For property-based conjectures you can only use --sufficient or --necessary.\n");
2058
usage(name);
2059
return EXIT_FAILURE;
2060
}
2061
2062
2063
return -1;
2064
}
2065
2066
int main(int argc, char *argv[]) {
2067
2068
operatorFile = stdin;
2069
invariantsFile = stdin;
2070
2071
int po = processOptions(argc, argv);
2072
if(po != -1) return po;
2073
2074
int unary = 0;
2075
int binary = 0;
2076
if(!doConjecturing){
2077
unary = strtol(argv[optind], NULL, 10);
2078
binary = strtol(argv[optind+1], NULL, 10);
2079
if(onlyLabeled) {
2080
invariantCount = strtol(argv[optind+2], NULL, 10);
2081
}
2082
} else if(argc - optind == 2) {
2083
unary = strtol(argv[optind], NULL, 10);
2084
binary = strtol(argv[optind+1], NULL, 10);
2085
}
2086
2087
//set the operator labels
2088
if(onlyLabeled) {
2089
int i;
2090
for (i=0; i<unaryOperatorCount; i++) {
2091
unaryOperators[i] = i;
2092
}
2093
for (i=0; i<commBinaryOperatorCount; i++) {
2094
commBinaryOperators[i] = i;
2095
}
2096
for (i=0; i<nonCommBinaryOperatorCount; i++) {
2097
nonCommBinaryOperators[i] = i;
2098
}
2099
} else if (!onlyUnlabeled){
2100
if(operatorFile==NULL){
2101
int i;
2102
for (i=0; i<unaryOperatorCount; i++) {
2103
unaryOperators[i] = i;
2104
}
2105
for (i=0; i<commBinaryOperatorCount; i++) {
2106
commBinaryOperators[i] = i;
2107
}
2108
for (i=0; i<nonCommBinaryOperatorCount; i++) {
2109
nonCommBinaryOperators[i] = i;
2110
}
2111
} else {
2112
readOperators();
2113
}
2114
if(propertyBased){
2115
readInvariantsValues_propertyBased();
2116
if(verbose) printInvariantValues_propertyBased(stderr);
2117
if(!checkKnownTheory_propertyBased()){
2118
BAILOUT("Known theory is not consistent with main invariant")
2119
}
2120
} else {
2121
readInvariantsValues();
2122
if(verbose) printInvariantValues(stderr);
2123
if(!checkKnownTheory()){
2124
BAILOUT("Known theory is not consistent with main invariant")
2125
}
2126
}
2127
}
2128
2129
if(closeOperatorFile){
2130
fclose(operatorFile);
2131
}
2132
if(closeInvariantsFile){
2133
fclose(invariantsFile);
2134
}
2135
2136
//do heuristic initialisation
2137
if(heuristicInit!=NULL){
2138
heuristicInit();
2139
}
2140
2141
//register handlers for signals
2142
signal(SIGALRM, handleAlarmSignal);
2143
signal(SIGINT, handleInterruptSignal);
2144
signal(SIGTERM, handleTerminationSignal);
2145
2146
//if timeOut is non-zero: start alarm
2147
if(timeOut) alarm(timeOut);
2148
2149
//start actual generation process
2150
if(doConjecturing){
2151
conjecture(unary, binary);
2152
} else {
2153
generateTree(unary, binary);
2154
}
2155
2156
//give information about the reason why the program halted
2157
if(heuristicStoppedGeneration){
2158
fprintf(stderr, "Generation process was stopped by the conjecturing heuristic.\n");
2159
} else if(timeOutReached){
2160
fprintf(stderr, "Generation process was stopped because the maximum time was reached.\n");
2161
} else if(userInterrupted){
2162
fprintf(stderr, "Generation process was interrupted by user.\n");
2163
} else if(terminationSignalReceived){
2164
fprintf(stderr, "Generation process was killed.\n");
2165
}
2166
2167
//print some statistics
2168
if(onlyUnlabeled){
2169
fprintf(stderr, "Found %lu unlabeled trees.\n", treeCount);
2170
} else if(onlyLabeled) {
2171
fprintf(stderr, "Found %lu unlabeled trees.\n", treeCount);
2172
fprintf(stderr, "Found %lu labeled trees.\n", labeledTreeCount);
2173
} else if(generateExpressions || doConjecturing) {
2174
fprintf(stderr, "Found %lu unlabeled trees.\n", treeCount);
2175
fprintf(stderr, "Found %lu labeled trees.\n", labeledTreeCount);
2176
fprintf(stderr, "Found %lu valid expressions.\n", validExpressionsCount);
2177
}
2178
2179
//do some heuristic-specific post-processing like outputting the conjectures
2180
if(heuristicPostProcessing!=NULL){
2181
heuristicPostProcessing();
2182
}
2183
2184
return 0;
2185
}
2186
2187