# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by ml2!quinlan on Mon Jan 22 09:32:46 EST 1996 # Contents: =README= MANUAL Makefile ackermann.d c4tofoil.c constants.c crx.d # crx.data crx.names crx.test defns.i determinate.c evaluatelit.c # extern.i finddef.c global.c input.c interpret.c join.c literal.c main.c # member.d member.explain ncm.d order.c output.c prune.c qs44.d search.c # sort.d state.c utility.c echo x - =README= sed 's/^@//' > "=README=" <<'@//E*O*F =README=//' FOIL 6.4 -------- FOIL6 is a fairly comprehensive (and overdue) rewrite of FOIL5.2. The code is now more compact, better documented, and faster for most tasks. The language has changed to ANSI C. In the process of rewriting, several small changes have been made to the algorithm. Some of these correct minor glitches (such as restoring the number of weak literals after search is restarted). Others change the behaviour of FOIL: for instance, the checks before literal evaluation have been strengthened and more pruning heuristics introduced. You are therefore advised not to discard FOIL5.2 until you are satisfied that FOIL6 behaves properly on your tasks. Here is a quick summary of notable intentional changes. Of course, others (aka bugs) might have crept in during the rewrite -- please report any that you find. * Pruning heuristics strengthened. Even though these are risk-free, the behavious of FOIL6 can differ from that of FOIL5.2, which sometimes evaluated literals that could not be used in the definition. Generally, FOIL6 prunes more than FOIL5.2 but this is not uniformly the case. * Encoding cost of clauses changed. FOIL5.2 did not `charge' for determinate literals, but included them in the reordering credit. FOIL6 still does not charge for determinate literals, but excludes them when calculating reordering credit. * Calculation of encoding cost of continuous literals altered. The calculation is approximate, using the number of tuples rather than the number of distinct values as in FOIL5.2. * Number of variables changeable with -V option and default value (52) lower than previous built-in value (104). * Allowable number of weak literals now changeable with -w option with default value (3) same as previous built-in value. * Sampling option renamed -s. * Sampling corrected to generate the right number of negative tuples. * New option -N to allow A<>B, A<>constant while still excluding negated literals on user-defined relations. * Continuous types declared as "X: continuous." rather than the cryptic "X:@ ." This change has also been made in c4tofoil. * Variables of the same continuous type can be compared with =, <>. * Output verbosity levels changed. The old default level 1 contained more information that the current default (also level 1); the new level 2 is similar to the old level 1 and so on. Some verbose output has been reformatted. * Number of weak literals in succession correctly recovered after a backup. * Options for uniform coding, booting with determinate literals from previous clause, and recursive checking of test cases suspended pending some rethinking. Look for their replacements (and others) in later releases (we hope). * Theory constants applicable only to their own type, rather than to any compatible type. * Only highest-gain thresholds of continuous attributes considered for saving as best clause encountered during search. FOIL5.2 monitored all literals in this respect, even though only the best threshold was considered for saving as a backup. GENERAL ------- The file "MANUAL" contains an explanation of the form of the input and the options. The executable version of the program, foil6, may be made with the command "make foilgt" (or "make foil" for the slower version for debugging). A small example input file, "member.d", is provided to demonstrate the program, and may be used with the command "foil6 -n -v3 < member.d". The file member.explain discusses the input and output for this small task. Several other example files (*.d) are also provided for your use. The names of these should be sufficiently mnemonic to enable recognition from the literature. In addition to the example input files, the program c4tofoil.c for converting files from the format used by C4.5 to that used by FOIL is also included. An example file (the credit data) has been provided, with a names file augmented as required to demonstrate the use of this additional program. For further details on use of the program, see its header. FOIL has a mixed authorship. The original versions were produced by Ross Quinlan; Mike Cameron-Jones then generated versions 3 to 5.2. FOIL6 was produced by Ross, incorporating many of the algorithms and routines developed by Mike (and with Mike identifying numerous glitches in the recoding). The utility c4tofoil was produced entirely by Mike. We would appreciate it if you could mail Mike when you have ftp'ed a copy of FOIL6 so that we can keep track of its whereabouts. Comments and bug reports are most welcome. Ross Quinlan (quinlan@cs.su.oz.au) Mike Cameron-Jones (mcj@cs.su.oz.au) Subsidiary notes for release 6.1 -------------------------------- Principal changes for this release are: * A special constant to denote "out of closed world" has been introduced. See MANUAL for the explanatory reference. * A time limit (default 100 seconds) has been set for evaluation of all possible literals for one relation. The idea is to truncate some very long (and often pointless) searches. * Potential literals are screened to rule out those requiring the same value for different arguments when the corresponding relation never has equal arguments in those positions. * Relations are ordered differently. This may cause problems on some datasets. * Pruning has been weakened to allow more complete search for saveable literals. * The meaning of the maximum alternatives option (-l) has been changed by one; -l 4 now means "best plus four alternatives". * When deciding whether to replace a clause with the best saved clause, the criterion is clause coding length rather than number of literals. * The problems encountered with some Sun compilers should have been fixed. (The difficulty was caused by a statement of the form A[x++] = B; where some compilers increment x before evaluating B.) * Time is now measured by getrusage() rather than clock(). This has the advantage of eliminating wraparound on long runs, but might require the addition of BSD libraries if you do not run BSD Unix. * Various minor errors/omissions have been rectified. Subsidiary notes for release 6.1a --------------------------------- Changes for this additional release are: * The program to convert from c4.5 to FOIL format has been corrected and modified. * A bug in the printing of simplified clauses has been fixed. * There are now limits on the total number of backups per clause (equal to the maximum number of checkpoints, -t option, default 20). * The Quicksort routine has been modified to divide on the middle element rather than the last. Subsidiary notes for release 6.2 -------------------------------- Changes for this release are: * Repetitious literals excluded. A literal that would repeat a literal that already appears in the clause, with perhaps a change of free variables, is excluded. * Better clause simplification. Implicit equalities are Vi=Vj or Vi=c established by the relations are now placed into the clause before pruning. * The MDL coding was changed to take account of sampling, if used; the coding now behaves as if all - tuples (not just a sample) were defined. * Several small bugs have been fixed (e.g. don't try to recover if a saved clause is available; check for duplicated constants in a type). Subsidiary notes for release 6.3 -------------------------------- Changes for this release are: * When simplified clauses are printed at the end of a run, unbound variables in negated literals are now printed as '_n' where n is a small integer. (This also fixed a bug in the printing, but not the interpretation, of simplified clauses.) * A few more small bugs have been identified and fixed. Subsidiary notes for release 6.4 -------------------------------- Changes for this release are: * Minor efficiency improvements and a couple of bug fixes. The most noticeable bug was that literals with bound continuous variables were not being considered. @//E*O*F =README=// chmod u=rw,g=,o= =README= echo x - MANUAL sed 's/^@//' > "MANUAL" <<'@//E*O*F MANUAL//' NAME foil6 - produce Horn clauses from relational data SYNOPSIS foil6 [ -n ] [ -N ] [ -v verb ] [ -V vars ] [ -s frac ] [ -m maxt ] [ -d depth ] [ -w weaklits ] [ -a accur ] [ -l alter ] [ -t chkpt ] [ -f gain ] [ -g max ] DESCRIPTION FOIL is a program that reads extensional specifications of a set of relations and produces Horn clause definitions of one or more of them. INPUT ***** Input to the program consists of three sections: * specification of types blank line * extensional definitions of relations blank line | these are * test cases for learned definitions | optional Types ----- Each discrete type specification consists of the type name followed by a colon, then a series of constants separated by commas and terminated with a period. This may occupy several lines and the same constant can appear in many types. There are three kinds of discrete types: * ordered types (type name preceded by '*') The constants have a natural order and appear in this order in the type definition, smallest constant first. * unordered types (type name preceded by '#') The constants do not have any natural order. * possibly ordered types FOIL will attempt to discover an ordering of the constants that may be useful for recursive definitions. Each continuous type specification consists of the type name followed by ": continuous." on one line. The constants corresponding to a continuous type are the usual integers and real numbers -- any string that can be converted to a float by C's atof() should work when specifying a value in a tuple. Constants --------- A non-numeric constant consist of any string of characters with the exception that any occurrence of certain delimiter characters (left and right parenthesis, period, comma, semicolon) must be prefixed by the escape character '\'. A "theory" constant that can appear in a definition should be preceded by '*'. Two one-character constants have a special meaning and should not be used otherwise: * '?' indicates a missing or unknown value (see Cameron-Jones and Quinlan, 1993b) * '^' indicates an out-of-closed-world value (see Quinlan and Cameron-Jones, 1994) Relations --------- All relations are defined in terms of the set of positive tuples of constants for which the relation is true, and optionally the set of negative tuples of constants for which it is false. If only positive tuples are given, all other constant tuples of the correct types are considered to be negative. Each relation is defined by a header and one or two sets of constant tuples. The header can be specified as follows: name(type, type, ... , type) key/key/.../key The header of all relations other than target relations begins with '*'. The header consists of relation name, argument types and optional keys. Keys limit the ways the relation may be used and consist of one character for each type. The character '#' indicates that the corresponding argument in a literal must be bound; the character '-' indicates that the argument can be bound or unbound. Each key thus gives a permissible way of accessing the relation. If no keys appear, all possible combinations of bound and unbound arguments are allowed. Following the header line are a series of lines containing constant tuples: positive tuple positive tuple . . . ; | these negative tuple | are negative tuple | optional . . . | . Each tuple consists of constants separated by commas and must appear on a single line. The character ';' separates positive tuples from negative tuples, which are optional. Tests ----- The optional test relations may be given to test the learned Horn clause definitions. The additional input consists of a blank line (indicating start of test relation specification) relation name test tuples . relation name test tuples . and so on Each test tuple consists of a constant tuple followed by ": +" if it is belongs to the relation and ": -" if it does not. The definition interpreter is simple; right-hand sides of the clauses are checked with reference to the given tuples, not to the definitions of the relations that may have been learned. OPTIONS ******* Options and their meanings are: -n Negative literals are not considered. This may be useful in domains where negated literals wouldn't make sense, or if learned definitions must be Horn clauses. -N This is similar, but permits negated equality literals A<>B and A<>constant. -vverb Set verbosity level [0, 1, 2, 3, or 4; default 1] The program produces rather voluminous trace output controlled by this variable. The default value of 1 gives a fair amount of detail; 0 produces very little output; 3 gives a blow-by-blow account of what the system is doing; 4 gives details of tuples in training sets etc. -Vvars Set the maximum number of variables that can be used during the search for a definition. [default: 52] -sfrac In some predicates of high arity, the closed world assumption will generate very many negative tuples. This option causes only a randomly-selected neg% of negative tuples to be used. Note that this option has no effect if negative tuples are given explicitly. -mmaxt Set the maximum number of tuples; the default is 100000. If the default setting results in warnings that literals are being excluded due to the tuple limit, expanding the limit may be useful (but time-consuming). -ddepth Set the maximum variable depth [default 4]. This limits the possible depth of variables in literals. -wwklts Set the maximum number of weak (zero-gain) literals that can appear in sequence [default: 4]. A batch of determinate literals counts as one literal in this respect. -aaccur Set the minimum accuracy of any clause [default 80%] FOIL will not accept any clause with an accuracy lower than this. -lalter Set the maximum number of alternatives to any literal [default 5]. This limits the amount of backup from any one point. -tchkpt Set the maximum number of checkpoints at any one time [default 20]. -fgain Any alternative literal must have at least gain% of the best literal gain [default 80%]. -gmax Determinate literals are automatically included, unless there is a literal which has at least max% of the maximum possible gain. (The maximum possible gain is achieved by a literal that is satisfied by all + tuples, but no - tuples, in the current training set.) Obviously, if max is zero, no determinate literals are included unless there are no other literals. SEE ALSO Quinlan, J.R. (1990), "Learning Logical Definitions from Relations", Machine Learning 5, 239-266. Quinlan, J.R. (1991), "Determinate Literals in Inductive Logic Programming", Proceedings 12th International Joint Conference on Artificial Intelligence, 746-750, Morgan Kaufmann. Quinlan, J.R. and Cameron-Jones, R.M. (1993), "FOIL: a midterm report", 3-20, Proceedings European Conference on Machine Learning, Springer Verlag. Cameron-Jones, R.M. and Quinlan, J.R. (1993a), "Avoiding Pitfalls When Learning Recursive Theories", Proceedings IJCAI 93, 1050-1055, Morgan Kaufmann. Cameron-Jones, R.M. and Quinlan, J.R., (1993b), "First Order Learning, Zeroth Order Data", Sixth Australian Joint Conference on Artificial Intelligence, World Scientific. Quinlan, J.R. and Cameron-Jones, R.M., (1994), "Living in a Closed World", draft available by anonymous ftp from ftp.cs.su.oz.au (file pub/q+cj.closed.ps). @//E*O*F MANUAL// chmod u=rw,g=,o= MANUAL echo x - Makefile sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//' # Vanilla makefile for distribution # You may need to set local c compiler options CFLAGS = -g @.SUFFIXES: .o .c .l .ln @.c.o: Makefile defns.i extern.i # lint -c $< cc $(CFLAGS) -c $< @.c.ln: lint -c $< SRC = global.c main.c input.c output.c state.c\ literal.c evaluatelit.c search.c determinate.c order.c\ join.c utility.c finddef.c interpret.c prune.c constants.c OBJ = global.o main.o input.o output.o state.o\ literal.o evaluatelit.o search.o determinate.o order.o\ join.o utility.o finddef.o interpret.o prune.o constants.o LINT = global.ln main.ln input.ln output.ln state.ln\ literal.ln evaluatelit.ln search.ln determinate.ln order.ln\ join.ln utility.ln finddef.ln interpret.ln prune.ln constants.ln foil: $(OBJ) Makefile # lint -x $(LINT) -lm >,nittygritty cc -o foil6 $(OBJ) -lm foilgt: $(SRC) defns.i Makefile cat defns.i $(SRC) >.temp egrep -v '"defns.i"|"extern.i"' .temp >foilgt.c cc -O3 -o foil6 foilgt.c -lm rm .temp foilgt.c $(OBJ): defns.i extern.i @//E*O*F Makefile// chmod u=rw,g=,o= Makefile echo x - ackermann.d sed 's/^@//' > "ackermann.d" <<'@//E*O*F ackermann.d//' *N: *0,*1,2,3,4,5,6,7,8,9,10, 11,12,13,14,15,16,17,18,19,20. Ackermann(N,N,N) ##- 0,0,1 0,1,2 0,2,3 0,3,4 0,4,5 0,5,6 0,6,7 0,7,8 0,8,9 0,9,10 0,10,11 0,11,12 0,12,13 0,13,14 0,14,15 0,15,16 0,16,17 0,17,18 0,18,19 0,19,20 1,0,2 1,1,3 1,2,4 1,3,5 1,4,6 1,5,7 1,6,8 1,7,9 1,8,10 1,9,11 1,10,12 1,11,13 1,12,14 1,13,15 1,14,16 1,15,17 1,16,18 1,17,19 1,18,20 2,0,3 2,1,5 2,2,7 2,3,9 2,4,11 2,5,13 2,6,15 2,7,17 2,8,19 3,0,5 3,1,13 4,0,13 @. *succ(N,N) 0,1 1,2 2,3 3,4 4,5 5,6 6,7 7,8 8,9 9,10 10,11 11,12 12,13 13,14 14,15 15,16 16,17 17,18 18,19 19,20 @. @//E*O*F ackermann.d// chmod u=rw,g=,o= ackermann.d echo x - c4tofoil.c sed 's/^@//' > "c4tofoil.c" <<'@//E*O*F c4tofoil.c//' /*****************************************************************************/ /* */ /* Program to convert files from the standard C4.5 input format to a form */ /* that can be used by FOIL */ /* */ /* The relation to be found by FOIL will be of the form - */ /* is first class named in the .names file */ /* */ /* Hence changing the order of the class names will cause FOIL to find other */ /* relations from the same data */ /* */ /* Compilation and use: */ /* cc -o cf c4tofoil.c (produce executable cf) */ /* cf -f filestem (take filestem.names and filestem.data (and filestem.test */ /* if present) and produce filestem.d for FOIL) */ /* option -v produces some extra output on the standard output */ /* */ /* (Any error messages are currently printed on the standard output stream) */ /* */ /* Modification required to filestem.names: */ /* Each line containing attribute information should have information */ /* specifying the type - this is added as a C4.5 comment thus... */ /* */ /* (attribute info for C4.5) | type: typename */ /* */ /* where typename is the name of the type of this attribute. Each typename */ /* shall start with a letter (upper or lower case) and no typename shall be */ /* the prefix of another typename. */ /* (The latter restriction is required as the output for FOIL distinguishes */ /* between constants of different types by prefixing them with their */ /* typename). */ /* */ /* For example: */ /* aardvarkish: true, false. | type: Boolean */ /* */ /* Note that values of discrete attributes which occur in the data file */ /* become theory constants for FOIL. (However those that occur in the test */ /* file but not data file, are just constants, not theory constants). */ /* */ /*****************************************************************************/ #include #include #include #define MAXNAMELENGTH 10000 /* Vast possible name length */ #define SkipComment while ( ( (c = getc(fp)) != '\n' ) && (c!=EOF) ) typedef struct _att_info *att_info; /* Attribute information */ struct _att_info { char *name; int ignore; /* !0 if to be ignored */ int discrete; /* !0 if discrete */ int discrete_n; /* the max number of values if "discrete N", else 0 */ int n_values; /* values stored for discrete attributes */ char **values; int *value_occurs_tr; /* number of occurrences in training of value */ char *type_name; int type_number; /* number of the corresponding type */ }; typedef struct _type_info *type_info; /* Type information */ struct _type_info { char *name; int n_atts; /* number of attributes of this type */ int *atts; /* attributes of this type */ int discrete; /* !0 if discrete */ int n_values; /* values stored for discrete types */ char **values; int *value_occurs_tr; /* number of occurrences in training of value */ }; int terminator; /* Character(/EOF) which caused previous scan to end */ char *name; /* Current name being processed */ char *copy_string(char *s); int get_next_name(FILE *fp, int skip, int embed); void get_type_name(att_info attribute, FILE *fp); /*****************************************************************************/ /* main - monolithic program to read the C4.5-style files and produce the */ /* FOIL-style one. */ /*****************************************************************************/ main(int argc, char *argv[]) { extern char *optarg; extern int optind; int o; int verbosity=0; char *filestem=NULL, *filename; FILE *fp, *tp; char **class_names=NULL; int n_class_names; char ***cases; int n_cases; char ***testing_cases; int n_testing_cases; att_info *attributes, attribute; int n_attributes; type_info *types, type; int n_types; int i, j, k; int c; /* Initialise the name char array */ name = (char *) malloc(MAXNAMELENGTH*sizeof(char)); /* Option handling */ while ( (o=getopt(argc,argv,"vf:")) != -1 ) { switch (o) { case 'f': filestem = copy_string(optarg); break; case 'v': verbosity++; break; case '?': printf("Option error in c4 to FOIL conversion\n"); exit(1); } } if(!filestem) { printf("Must enter filestem: -f filestem\n"); exit(1); } /* Extract the class and attribute/type information from the .names file */ filename = (char*) malloc((strlen(filestem)+7)*sizeof(char)); sprintf(filename,"%s.names",filestem); fp = fopen(filename,"r"); if(!fp) { printf("Can't open %s\n", filename); exit(1); } if(verbosity) printf("Reading from %s\n", filename); /* Get class names */ n_class_names = 0; class_names = (char**) malloc(11*sizeof(char*)); do { if(!get_next_name(fp,1,1)) { printf("Problem while reading class names\n"); exit(1); } if(n_class_names&&!(n_class_names%10)) class_names = (char**) realloc((void*)class_names, (n_class_names+11)*sizeof(char*)); class_names[n_class_names++] = copy_string(name); }while(terminator==','); if(verbosity) { printf("Have read class names:"); for(i=0;iname = copy_string(name); if(!get_next_name(fp,0,1)) { printf("Information missing for attribute %s\n", name); exit(1); } if(!strcmp(name,"ignore")) { attribute->ignore = 1; attribute->discrete = 0; if(terminator!='\n') SkipComment; } else if(!strcmp(name,"continuous")) { attribute->ignore = 0; attribute->discrete = 0; attribute->discrete_n = 0; attribute->n_values = 0; attribute->values = NULL; get_type_name(attribute,fp); } else if(!strncmp(name,"discrete",8)) { attribute->ignore = 0; attribute->discrete = 1; attribute->discrete_n = atoi(name+8); attribute->n_values = 0; attribute->values=(char**)malloc(attribute->discrete_n* sizeof(char*)); if(attribute->discrete_n && (attribute->values==NULL)) { printf("Problem allocating space for values of %s\n", attribute->name); exit(1); } get_type_name(attribute,fp); } else /* Presume that this is discrete with specified values */ { attribute->ignore = 0; attribute->discrete = 1; attribute->discrete_n = 0; attribute->n_values = 0; attribute->values = (char**)malloc(11*sizeof(char*)); do { if(attribute->n_values&&!(attribute->n_values%10)) attribute->values = (char**) realloc( (void*)attribute->values, (attribute->n_values+11)*sizeof(char*)); attribute->values[attribute->n_values++] = copy_string(name); if(terminator!=',') break; } while(get_next_name(fp,0,1)); get_type_name(attribute,fp); } n_attributes++; } fclose(fp); /* Read the .data file, extracting constant occurrence info */ for(i=0;idiscrete) if(attribute->n_values) attribute->value_occurs_tr = (int*) calloc((size_t)attribute->n_values,sizeof(int)); else attribute->value_occurs_tr = (int*) calloc((size_t)attribute->discrete_n,sizeof(int)); } sprintf(filename,"%s.data",filestem); fp = fopen(filename,"r"); if(!fp) { printf("Can't open %s\n", filename); exit(1); } if(verbosity) printf("Reading from %s\n", filename); cases = (char***)malloc(101*sizeof(char**)); n_cases = 0; while(get_next_name(fp,1,attributes[0]->discrete)) { if(n_cases&&!(n_cases%100)) cases = (char***) realloc((void*)cases, (n_cases+101)*sizeof(char**)); cases[n_cases] = (char**)malloc((n_attributes+1)*sizeof(char*)); i = 0; do { attribute = attributes[i]; if(attribute->ignore) { } else if(!strcmp(name,"?")) { cases[n_cases][i] = NULL; } else if(attribute->discrete) { for(j=0;jn_values;j++) { if(!strcmp(name,attribute->values[j])) break; } if(j==attribute->n_values) /* value not seen before */ { if(j>=attribute->discrete_n) { printf("%s has extra value %s in data file\n", attribute->name, name); exit(1); } else /* add it in */ { attribute->values[j] = copy_string(name); attribute->n_values++; } } attribute->value_occurs_tr[j]++; cases[n_cases][i] = attribute->values[j]; } else /* continuous attribute with value */ { cases[n_cases][i] = copy_string(name); } i++; } while(get_next_name(fp,1,(i==n_attributes) ? 1 : attributes[i]->discrete) &&(idiscrete)) { if(n_testing_cases&&!(n_testing_cases%100)) testing_cases = (char***) realloc((void*)testing_cases, (n_testing_cases+101)*sizeof(char**)); testing_cases[n_testing_cases] = (char**)malloc((n_attributes+1)* sizeof(char*)); i = 0; do { attribute = attributes[i]; if(attribute->ignore) { } else if(!strcmp(name,"?")) { testing_cases[n_testing_cases][i] = NULL; } else if(attribute->discrete) { for(j=0;jn_values;j++) { if(!strcmp(name,attribute->values[j])) break; } if(j==attribute->n_values) /* value not seen before */ { if(j>=attribute->discrete_n) { printf("%s has extra value %s in data file\n", attribute->name, name); exit(1); } else /* add it in */ { attribute->values[j] = copy_string(name); attribute->n_values++; } } testing_cases[n_testing_cases][i]=attribute->values[j]; } else /* continuous attribute with value */ { testing_cases[n_testing_cases][i] = copy_string(name); } i++; } while(get_next_name(fp,1,(i==n_attributes)? 1 : attributes[i]->discrete) &&(iignore) continue; for(j=0;jname,attribute->type_name)) break; } attribute->type_number = j; if(j==n_types) /* New type */ { if(n_types&&!(n_types%10)) types = (type_info*) realloc((void*)types, (n_types+11)*sizeof(type_info)); types[n_types] = (type_info)malloc(sizeof(struct _type_info)); types[n_types]->name = attribute->type_name; types[n_types]->discrete = attribute->discrete; types[n_types]->n_atts = 0; types[n_types]->atts = (int*)malloc(11*sizeof(int)); types[n_types]->n_values = 0; if(types[n_types]->discrete) { types[n_types]->values = (char**)malloc(11*sizeof(char*)); types[n_types]->value_occurs_tr =(int*)malloc(11*sizeof(int*)); } else { types[n_types]->values = NULL; } n_types++; } type = types[j]; if(type->n_atts&&!(type->n_atts%10)) type->atts = (int*) realloc((void*)type->atts, (type->n_atts+11)*sizeof(int)); type->atts[type->n_atts++] = i; if(type->discrete!=attribute->discrete) { printf("Type %s declared to be both discrete and continuous\n", type->name); exit(1); } if(type->discrete) { for(j=0;jn_values;j++) { for(k=0;kn_values;k++) { if(!strcmp(attribute->values[j],type->values[k])) break; } if(k==type->n_values) /* New value for this type */ { if(type->n_values&&!(type->n_values%10)) { type->values = (char**) realloc((void*)type->values, (type->n_values+11)*sizeof(char*)); type->value_occurs_tr =(int*)realloc( (void*)type->value_occurs_tr, (type->n_values+11)*sizeof(int*)); } type->values[k] = attribute->values[j]; type->value_occurs_tr[k] = 0; type->n_values++; } type->value_occurs_tr[k] += attribute->value_occurs_tr[j]; } } } /* Check the discrete type names to ensure that none is the prefix of another */ for(i=0;idiscrete) continue; for(j=i+1;jdiscrete) continue; if((int)strlen(types[i]->name)>(int)strlen(types[j]->name)) { if(!strncmp(types[i]->name,types[j]->name, strlen(types[j]->name))) { printf("Type name %s is prefix of type name %s\n", types[j]->name, types[i]->name); exit(1); } } else { if(!strncmp(types[j]->name,types[i]->name, strlen(types[i]->name))) { printf("Type name %s is prefix of type name %s\n", types[i]->name, types[j]->name); exit(1); } } } } /* Output type info on std out */ if(verbosity) { printf("Type information from names file:\n\n"); for(i=0;iname); if(type->discrete) printf("\tdiscrete\n"); else printf("\tcontinuous\n"); printf("\tattributes:\n"); for(j=0;jn_atts;j++) printf("\t\t%s\n",attributes[type->atts[j]]->name); printf("\tvalues:\n"); for(j=0;jn_values;j++) printf("\t\t%s\n",type->values[j]); } } /* Now write out to the .d file for FOIL */ sprintf(filename,"%s.d",filestem); tp = fopen(filename,"w"); if(verbosity) printf("Writing to %s\n", filename); /* First the types complete with constants - note that in the .d file each discrete constant name is augmented by being preceded by its type name to prevent FOIL equating two constants of different types */ for(i=0;idiscrete) { fprintf(tp,"#%s: ",type->name); k = 0; for(j=0;jn_values;j++) { if(k) fprintf(tp,", "); if(type->value_occurs_tr[j]) fprintf(tp,"*"); /* Theory Constant */ fprintf(tp,"%s%s",type->name, type->values[j]); k++; } if(!k) fprintf(tp,"\n"); /* empty type */ fprintf(tp,".\n"); } else fprintf(tp,"%s: continuous.\n",type->name); } fprintf(tp,"\n"); /* Now the sole relation - is_first_named_class() */ fprintf(tp,"is_%s(", class_names[0]); k = 0; for(i=0;iignore) continue; if(k) fprintf(tp,","); fprintf(tp,"%s",attribute->type_name); k++; } if(!k) { printf("All attributes ignored\n"); exit(1); } fprintf(tp,")\n"); /* Now the positive training cases */ for(i=0;iignore) continue; if(k) fprintf(tp,","); if(!cases[i][j]) /* Missing Value */ { fprintf(tp,"?"); } else if(attribute->discrete) { fprintf(tp,"%s%s",attribute->type_name,cases[i][j]); } else /* attribute is continuous */ { fprintf(tp,"%s",cases[i][j]); } k++; } fprintf(tp,"\n"); } /* Now the negative training cases */ fprintf(tp,";\n"); for(i=0;iignore) continue; if(k) fprintf(tp,","); if(!cases[i][j]) /* Missing Value */ { fprintf(tp,"?"); } else if(attribute->discrete) { fprintf(tp,"%s%s",attribute->type_name,cases[i][j]); } else /* attribute is continuous */ { fprintf(tp,"%s",cases[i][j]); } k++; } fprintf(tp,"\n"); } fprintf(tp,".\n"); /* Now the test cases */ if(!fp) { fclose(tp); exit(0); } fprintf(tp,"\nis_%s\n", class_names[0]); for(i=0;iignore) continue; if(k) fprintf(tp,","); if(!testing_cases[i][j]) /* Missing Value */ { fprintf(tp,"?"); } else if(attribute->discrete) { fprintf(tp,"%s%s",attribute->type_name,testing_cases[i][j]); } else /* attribute is continuous */ { fprintf(tp,"%s",testing_cases[i][j]); } k++; } if(testing_cases[i][n_attributes]==class_names[0]) fprintf(tp,":+\n"); else fprintf(tp,":-\n"); } fprintf(tp,".\n"); fclose(fp); fclose(tp); return 0; /* Changed from exit(0) */ } /*****************************************************************************/ /* copy_string(s) - return a copy of the string s */ /*****************************************************************************/ char *copy_string(char *s) { char *tmp; tmp = (char*)malloc((strlen(s)+1)*sizeof(char)); return strcpy(tmp,s); } /*****************************************************************************/ /* get_next_name(fp,skip,embed) - read next name from file *fp into name */ /* Modified version from FOIL's ReadName */ /* skip is !0 if trailing comment to be skipped */ /* embed is !0 if need to escape an embedded period */ /*****************************************************************************/ #define Space(c) (c == ' ' || c == '\t' || c == '\n') int get_next_name(FILE *fp, int skip, int embed) /* --------- */ { char *Sp = name; int c; /* Skip to first non-space character */ while ( ( c = getc(fp) ) == '|' || Space(c) ) if ( c == '|' ) SkipComment; /* Return 0 if no names to read */ if ( c == EOF ) { return 0; } /* Read in characters up to the next delimiter */ while ( c != ',' && c != '\n' && c != '|' && c != EOF && c != ':') { if ( c == '.' ) { if(c=getc(fp)) { if( Space(c) || c=='|' || c==EOF ) { c = '.'; break; } } else { c = '.'; break; } if(embed) *Sp++ = '\\'; /* Need to escape embedded . */ *Sp++ = '.'; } if ( c == '\\' ) { *Sp++ = (char) c; /* Perpetuate embedded characters for FOIL */ c = getc(fp); } *Sp++ = (char) c; if ( c == ' ' ) while ( ( c = getc(fp) ) == ' ' ); else c = getc(fp); } terminator = c; /* Skip trailing comment? */ if(skip && (c == '|')) { SkipComment; } /* Strip trailing spaces */ while ( Space(*(Sp-1)) ) Sp--; *Sp++ = '\0'; return 1; } /*****************************************************************************/ /* get_type_name(attribute,fp) - get the type name for attribute from fp */ /*****************************************************************************/ void get_type_name(att_info attribute, FILE *fp) { while(terminator!='|'&&terminator!='\n'&&terminator!=EOF) { terminator = getc(fp); } if(terminator=='|'&&get_next_name(fp,1,1)&&!strcmp(name,"type") &&get_next_name(fp,1,1)) { attribute->type_name = copy_string(name); } else { printf("Attribute %s lacks type info\n", attribute->name); exit(1); } return; } @//E*O*F c4tofoil.c// chmod u=rw,g=,o= c4tofoil.c echo x - constants.c sed 's/^@//' > "constants.c" <<'@//E*O*F constants.c//' /******************************************************************************/ /* */ /* Routines concerned with discovering a plausible ordering of the */ /* constants of each type. There are three phases: */ /* * finding possible orderings on pairs of relation arguments */ /* * finding a partial ordering that satisfies as many of these */ /* as possible */ /* * selecting a constant ordering consistent with the partial */ /* ordering */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" Boolean **Table=Nil; /* partial order for target type */ int TTN, /* target type number */ NC, /* size of target type */ *TTCollSeq, /* collation sequence */ NArgOrders = 0, /* number of possible arg orders */ MaxConsistent; /* max consistent arg orders */ ArgOrder *ArgOrderList = Nil; /* Find ordering for constants of each type */ void OrderConstants() /* -------------- */ { int i, j; Boolean **PO; Tuple *NLT; ForEach(TTN, 1, MaxType) { if ( Type[TTN]->FixedPolarity ) continue; NC = Type[TTN]->NValues; TTCollSeq = Type[TTN]->CollSeq; Verbose(3) printf("\nOrdering constants of type %s\n",Type[TTN]->Name); if ( ! Table ) Table = AllocatePartOrd(MaxConst); FindArgumentOrders(); if ( NArgOrders == 0 ) { Type[TTN]->Ordered = false; Verbose(3) printf("\t\tunordered\n"); continue; } else { Type[TTN]->Ordered = true; } /* Assemble in Table the partial order consistent with the maximum number of arg orders */ MaxConsistent = 0; PO = AllocatePartOrd(NC); ClearPartOrd(PO); Verbose(3) printf("\tFinding maximal consistent set\n"); FindConsistentSubset(0, 0, PO); FreePartOrd(PO, NC); /* Sort constants on number of entries in partial order; resolve ties in favour of the initial constant order */ NLT = Alloc(NC, Tuple); ForEach(i, 0, NC-1) { NLT[i] = Alloc(2, Const); NLT[i][0] = Type[TTN]->Value[i]; FP(NLT[i][1]) = CountEntries(i+1) + i / (float) NC; } Quicksort(NLT, 0, NC-1, 1); /* Change collation sequence and print message */ Verbose(3) printf("\tFinal order:\n\t\t"); ForEach(i, 0, NC-1) { j = NLT[i][0]; Type[TTN]->CollSeq[j] = i+1; Verbose(3) printf("%s ", ConstName[j]); pfree(NLT[i]); } Verbose(3) putchar('\n'); pfree(NLT); } if ( Table ) FreePartOrd(Table, MaxConst); ForEach(i, 0, NArgOrders-1) { pfree(ArgOrderList[i]); } pfree(ArgOrderList); } /* Find potential orderings between pairs of arguments of each relation for type TTN */ void FindArgumentOrders() /* ------------------ */ { int i; Relation R; ForEach(i, 0, MaxRel) { R = RelnOrder[i]; if ( Predefined(R) || R->Arity < 2 ) continue; ExamineArgumentPairs(R, true, R->Pos); if ( R->Neg ) { ExamineArgumentPairs(R, false, R->Neg); } } } /* Find potential orderings between pairs of arguments of R where relevant to the type under investigation */ void ExamineArgumentPairs(Relation R, Boolean Sign, Tuple *TP) /* -------------------- */ { int FirstArg, SecondArg; Verbose(3) printf("\tChecking arguments of %s%s\n", Sign ? "" : "~", R->Name); ForEach(FirstArg, 1, R->Arity-1) { if ( ! Compatible[R->Type[FirstArg]][TTN] ) continue; ForEach(SecondArg, FirstArg+1, R->Arity) { if ( ! Compatible[R->Type[SecondArg]][TTN] ) continue; Verbose(3) printf("\t\targuments %d,%d ", FirstArg, SecondArg); ClearPartOrd(Table); if ( ConsistentClosure(Table, TP, FirstArg, SecondArg) ) { Verbose(3) printf("are consistent\n"); AddArgOrder(R, Sign, FirstArg, SecondArg); } else { Verbose(3) printf("are not consistent\n"); } } } } /* Investigate args A and B of a set of tuples TP. See whether each pair of constants is consistent with TP; if so, add and form closure */ Boolean ConsistentClosure(Boolean **PO, Tuple *TP, Var A, Var B) /* ----------------- */ { Const K, L; int i, j; while( *TP ) { K = (*TP)[A]; L = (*TP)[B]; TP++; if ( K == MISSING_DISC || K == OUT_OF_RANGE || L == MISSING_DISC || L == OUT_OF_RANGE ) continue; /* Not consistent if either constant missing from type or if current pair in conflict with existing table */ if ( (i = TTCollSeq[K]) == 0 || (j = TTCollSeq[L]) == 0 || ! AddPair(PO, i, j) ) { return false; } } return true; } /* Note partial order between A and B; add to table if not already there and generate closure. Return false if the table is no longer consistent */ Boolean AddPair(Boolean **PO, int A, int B) /* ------- */ { int i, j; if ( PO[A][B] ) return true; /* already there */ else if ( A == B || PO[B][A] ) return false; /* not consistent */ ForEach(i, 1, NC) { if ( i == A || PO[i][A] ) { ForEach(j, 1, NC) { if ( j == B || PO[B][j] ) { if ( PO[j][i] ) return false; PO[i][j] = true; } } } } return true; } void AddArgOrder(Relation R, Boolean Sign, int A1, int A2) /* ----------- */ { ArgOrder AO; if ( NArgOrders % 100 == 0 ) { ArgOrderList = Realloc(ArgOrderList, NArgOrders+100, ArgOrder); } ArgOrderList[NArgOrders++] = AO = Alloc(1, struct _arg_ord_rec); AO->Rel = R; AO->Sign = Sign; AO->A1 = A1; AO->A2 = A2; AO->In = 0; } /* Routines for constant partial order tables */ Boolean **AllocatePartOrd(int Size) /* --------------- */ { Boolean **PO; int i; PO = Alloc(Size+1, Boolean *); ForEach(i, 1, Size) { PO[i] = Alloc(Size+1, Boolean); } return PO; } void FreePartOrd(Boolean **PO, int Size) /* ----------- */ { int i; ForEach(i, 1, Size) { pfree(PO[i]); } pfree(PO); } void ClearPartOrd(Boolean **PO) /* ------------ */ { int i; ForEach(i, 1, NC) { memset(PO[i], false, NC+1); } } void CopyPartOrd(Boolean **To, Boolean **From) /* ----------- */ { int i; ForEach(i, 1, NC) { memcpy(To[i], From[i], (NC+1)*sizeof(Boolean)); } } void FindConsistentSubset(int Included, int TryNext, Boolean **PO) /* -------------------- */ { Boolean **CopyPO; ArgOrder AO; Tuple *Entries; int i; if ( Included > MaxConsistent ) { /* Note best consistent partial order so far */ CopyPartOrd(Table, PO); MaxConsistent = Included; Verbose(3) { printf("\t\tbest so far"); ForEach(i, 0, NArgOrders-1) { AO = ArgOrderList[i]; if ( AO->In ) { printf(" %s%s:", AO->Sign ? "" : "~", AO->Rel->Name); if ( AO->In == 1 ) { printf("%d>%d", AO->A1, AO->A2); } else { printf("%d>%d", AO->A2, AO->A1); } } } putchar('\n'); } } if ( TryNext >= NArgOrders || Included + (NArgOrders - TryNext) <= MaxConsistent ) { return; } AO = ArgOrderList[TryNext]; Entries = AO->Sign ? AO->Rel->Pos : AO->Rel->Neg; CopyPO = AllocatePartOrd(NC); CopyPartOrd(CopyPO, PO); if ( ConsistentClosure(PO, Entries, AO->A1, AO->A2) ) { AO->In = 1; FindConsistentSubset(Included+1, TryNext+1, PO); } /* Do not have to try both polarities of first argument ordering */ if ( Included > 0 ) { CopyPartOrd(PO, CopyPO); if ( ConsistentClosure(PO, Entries, AO->A2, AO->A1) ) { AO->In = -1; FindConsistentSubset(Included+1, TryNext+1, PO); } } CopyPartOrd(PO, CopyPO); AO->In = 0; FindConsistentSubset(Included, TryNext+1, PO); FreePartOrd(CopyPO, NC); } int CountEntries(int K) /* ------------ */ { int i, Sum=0; ForEach(i, 1, NC) { if ( Table[K][i] ) Sum++; } return Sum; } @//E*O*F constants.c// chmod u=rw,g=,o= constants.c echo x - crx.d sed 's/^@//' > "crx.d" <<'@//E*O*F crx.d//' #A: *Ab, *Aa. B: continuous. #C: *Cu, *Cy, *Cl, Ct. #D: *Dg, *Dp, *Dgg. #E: *Ec, *Ed, *Ecc, *Ei, *Ej, *Ek, *Em, *Er, *Eq, *Ew, *Ex, *Ee, *Eaa, *Eff, *Ev, *Eh, *Ebb, *En, *Ez, *Edd, *Eo. #F: *Ft, *Ff. #G: *Gg, *Gp, *Gs. H: continuous. is_+(A,B,B,C,D,E,E,B,F,F,B,F,G,H,H) Ab,30.83,0,Cu,Dg,Ew,Ev,1.25,Ft,Ft,01,Ff,Gg,00202,0 Aa,58.67,4.46,Cu,Dg,Eq,Eh,3.04,Ft,Ft,06,Ff,Gg,00043,560 Aa,24.50,0.5,Cu,Dg,Eq,Eh,1.5,Ft,Ff,0,Ff,Gg,00280,824 Ab,27.83,1.54,Cu,Dg,Ew,Ev,3.75,Ft,Ft,05,Ft,Gg,00100,3 Ab,20.17,5.625,Cu,Dg,Ew,Ev,1.71,Ft,Ff,0,Ff,Gs,00120,0 Ab,32.08,4,Cu,Dg,Em,Ev,2.5,Ft,Ff,0,Ft,Gg,00360,0 Ab,33.17,1.04,Cu,Dg,Er,Eh,6.5,Ft,Ff,0,Ft,Gg,00164,31285 Aa,22.92,11.585,Cu,Dg,Ecc,Ev,0.04,Ft,Ff,0,Ff,Gg,00080,1349 Ab,54.42,0.5,Cy,Dp,Ek,Eh,3.96,Ft,Ff,0,Ff,Gg,00180,314 Ab,42.50,4.915,Cy,Dp,Ew,Ev,3.165,Ft,Ff,0,Ft,Gg,00052,1442 Ab,22.08,0.83,Cu,Dg,Ec,Eh,2.165,Ff,Ff,0,Ft,Gg,00128,0 Ab,29.92,1.835,Cu,Dg,Ec,Eh,4.335,Ft,Ff,0,Ff,Gg,00260,200 Aa,38.25,6,Cu,Dg,Ek,Ev,1,Ft,Ff,0,Ft,Gg,00000,0 Ab,48.08,6.04,Cu,Dg,Ek,Ev,0.04,Ff,Ff,0,Ff,Gg,00000,2690 Aa,45.83,10.5,Cu,Dg,Eq,Ev,5,Ft,Ft,07,Ft,Gg,00000,0 Ab,36.67,4.415,Cy,Dp,Ek,Ev,0.25,Ft,Ft,10,Ft,Gg,00320,0 Ab,28.25,0.875,Cu,Dg,Em,Ev,0.96,Ft,Ft,03,Ft,Gg,00396,0 Aa,23.25,5.875,Cu,Dg,Eq,Ev,3.17,Ft,Ft,10,Ff,Gg,00120,245 Ab,21.83,0.25,Cu,Dg,Ed,Eh,0.665,Ft,Ff,0,Ft,Gg,00000,0 Aa,19.17,8.585,Cu,Dg,Ecc,Eh,0.75,Ft,Ft,07,Ff,Gg,00096,0 Ab,25.00,11.25,Cu,Dg,Ec,Ev,2.5,Ft,Ft,17,Ff,Gg,00200,1208 Ab,23.25,1,Cu,Dg,Ec,Ev,0.835,Ft,Ff,0,Ff,Gs,00300,0 Aa,47.75,8,Cu,Dg,Ec,Ev,7.875,Ft,Ft,06,Ft,Gg,00000,1260 Aa,27.42,14.5,Cu,Dg,Ex,Eh,3.085,Ft,Ft,01,Ff,Gg,00120,11 Aa,41.17,6.5,Cu,Dg,Eq,Ev,0.5,Ft,Ft,03,Ft,Gg,00145,0 Aa,15.83,0.585,Cu,Dg,Ec,Eh,1.5,Ft,Ft,02,Ff,Gg,00100,0 Aa,47.00,13,Cu,Dg,Ei,Ebb,5.165,Ft,Ft,09,Ft,Gg,00000,0 Ab,56.58,18.5,Cu,Dg,Ed,Ebb,15,Ft,Ft,17,Ft,Gg,00000,0 Ab,57.42,8.5,Cu,Dg,Ee,Eh,7,Ft,Ft,03,Ff,Gg,00000,0 Ab,42.08,1.04,Cu,Dg,Ew,Ev,5,Ft,Ft,06,Ft,Gg,00500,10000 Ab,29.25,14.79,Cu,Dg,Eaa,Ev,5.04,Ft,Ft,05,Ft,Gg,00168,0 Ab,42.00,9.79,Cu,Dg,Ex,Eh,7.96,Ft,Ft,08,Ff,Gg,00000,0 Ab,49.50,7.585,Cu,Dg,Ei,Ebb,7.585,Ft,Ft,15,Ft,Gg,00000,5000 Aa,36.75,5.125,Cu,Dg,Ee,Ev,5,Ft,Ff,0,Ft,Gg,00000,4000 Aa,22.58,10.75,Cu,Dg,Eq,Ev,0.415,Ft,Ft,05,Ft,Gg,00000,560 Ab,27.83,1.5,Cu,Dg,Ew,Ev,2,Ft,Ft,11,Ft,Gg,00434,35 Ab,27.25,1.585,Cu,Dg,Ecc,Eh,1.835,Ft,Ft,12,Ft,Gg,00583,713 Aa,23.00,11.75,Cu,Dg,Ex,Eh,0.5,Ft,Ft,02,Ft,Gg,00300,551 Ab,27.75,0.585,Cy,Dp,Ecc,Ev,0.25,Ft,Ft,02,Ff,Gg,00260,500 Ab,54.58,9.415,Cu,Dg,Eff,Eff,14.415,Ft,Ft,11,Ft,Gg,00030,300 Ab,34.17,9.17,Cu,Dg,Ec,Ev,4.5,Ft,Ft,12,Ft,Gg,00000,221 Ab,28.92,15,Cu,Dg,Ec,Eh,5.335,Ft,Ft,11,Ff,Gg,00000,2283 Ab,29.67,1.415,Cu,Dg,Ew,Eh,0.75,Ft,Ft,01,Ff,Gg,00240,100 Ab,39.58,13.915,Cu,Dg,Ew,Ev,8.625,Ft,Ft,06,Ft,Gg,00070,0 Ab,56.42,28,Cy,Dp,Ec,Ev,28.5,Ft,Ft,40,Ff,Gg,00000,15 Ab,54.33,6.75,Cu,Dg,Ec,Eh,2.625,Ft,Ft,11,Ft,Gg,00000,284 Aa,41.00,2.04,Cy,Dp,Eq,Eh,0.125,Ft,Ft,23,Ft,Gg,00455,1236 Ab,31.92,4.46,Cu,Dg,Ecc,Eh,6.04,Ft,Ft,03,Ff,Gg,00311,300 Ab,41.50,1.54,Cu,Dg,Ei,Ebb,3.5,Ff,Ff,0,Ff,Gg,00216,0 Ab,23.92,0.665,Cu,Dg,Ec,Ev,0.165,Ff,Ff,0,Ff,Gg,00100,0 Aa,25.75,0.5,Cu,Dg,Ec,Eh,0.875,Ft,Ff,0,Ft,Gg,00491,0 Ab,26.00,1,Cu,Dg,Eq,Ev,1.75,Ft,Ff,0,Ft,Gg,00280,0 Ab,37.42,2.04,Cu,Dg,Ew,Ev,0.04,Ft,Ff,0,Ft,Gg,00400,5800 Ab,34.92,2.5,Cu,Dg,Ew,Ev,0,Ft,Ff,0,Ft,Gg,00239,200 Ab,34.25,3,Cu,Dg,Ecc,Eh,7.415,Ft,Ff,0,Ft,Gg,00000,0 Ab,23.33,11.625,Cy,Dp,Ew,Ev,0.835,Ft,Ff,0,Ft,Gg,00160,300 Ab,23.17,0,Cu,Dg,Ecc,Ev,0.085,Ft,Ff,0,Ff,Gg,00000,0 Ab,44.33,0.5,Cu,Dg,Ei,Eh,5,Ft,Ff,0,Ft,Gg,00320,0 Ab,35.17,4.5,Cu,Dg,Ex,Eh,5.75,Ff,Ff,0,Ft,Gs,00711,0 Ab,43.25,3,Cu,Dg,Eq,Eh,6,Ft,Ft,11,Ff,Gg,00080,0 Ab,56.75,12.25,Cu,Dg,Em,Ev,1.25,Ft,Ft,04,Ft,Gg,00200,0 Ab,31.67,16.165,Cu,Dg,Ed,Ev,3,Ft,Ft,09,Ff,Gg,00250,730 Aa,23.42,0.79,Cy,Dp,Eq,Ev,1.5,Ft,Ft,02,Ft,Gg,00080,400 Aa,20.42,0.835,Cu,Dg,Eq,Ev,1.585,Ft,Ft,01,Ff,Gg,00000,0 Ab,26.67,4.25,Cu,Dg,Ecc,Ev,4.29,Ft,Ft,01,Ft,Gg,00120,0 Ab,34.17,1.54,Cu,Dg,Ecc,Ev,1.54,Ft,Ft,01,Ft,Gg,00520,50000 Aa,36.00,1,Cu,Dg,Ec,Ev,2,Ft,Ft,11,Ff,Gg,00000,456 Ab,25.50,0.375,Cu,Dg,Em,Ev,0.25,Ft,Ft,03,Ff,Gg,00260,15108 Ab,19.42,6.5,Cu,Dg,Ew,Eh,1.46,Ft,Ft,07,Ff,Gg,00080,2954 Ab,35.17,25.125,Cu,Dg,Ex,Eh,1.625,Ft,Ft,01,Ft,Gg,00515,500 Ab,52.50,6.5,Cu,Dg,Ek,Ev,6.29,Ft,Ft,15,Ff,Gg,00000,11202 Ab,57.83,7.04,Cu,Dg,Em,Ev,14,Ft,Ft,06,Ft,Gg,00360,1332 Aa,20.75,10.335,Cu,Dg,Ecc,Eh,0.335,Ft,Ft,01,Ft,Gg,00080,50 Ab,39.92,6.21,Cu,Dg,Eq,Ev,0.04,Ft,Ft,01,Ff,Gg,00200,300 Ab,25.67,12.5,Cu,Dg,Ecc,Ev,1.21,Ft,Ft,67,Ft,Gg,00140,258 Aa,24.75,12.5,Cu,Dg,Eaa,Ev,1.5,Ft,Ft,12,Ft,Gg,00120,567 Aa,44.17,6.665,Cu,Dg,Eq,Ev,7.375,Ft,Ft,03,Ft,Gg,00000,0 Aa,23.50,9,Cu,Dg,Eq,Ev,8.5,Ft,Ft,05,Ft,Gg,00120,0 Ab,34.92,5,Cu,Dg,Ex,Eh,7.5,Ft,Ft,06,Ft,Gg,00000,1000 Ab,47.67,2.5,Cu,Dg,Em,Ebb,2.5,Ft,Ft,12,Ft,Gg,00410,2510 Ab,22.75,11,Cu,Dg,Eq,Ev,2.5,Ft,Ft,07,Ft,Gg,00100,809 Ab,34.42,4.25,Cu,Dg,Ei,Ebb,3.25,Ft,Ft,02,Ff,Gg,00274,610 Aa,28.42,3.5,Cu,Dg,Ew,Ev,0.835,Ft,Ff,0,Ff,Gs,00280,0 Ab,67.75,5.5,Cu,Dg,Ee,Ez,13,Ft,Ft,01,Ft,Gg,00000,0 Ab,20.42,1.835,Cu,Dg,Ec,Ev,2.25,Ft,Ft,01,Ff,Gg,00100,150 Aa,47.42,8,Cu,Dg,Ee,Ebb,6.5,Ft,Ft,06,Ff,Gg,00375,51100 Ab,36.25,5,Cu,Dg,Ec,Ebb,2.5,Ft,Ft,06,Ff,Gg,00000,367 Ab,32.67,5.5,Cu,Dg,Eq,Eh,5.5,Ft,Ft,12,Ft,Gg,00408,1000 Ab,48.58,6.5,Cu,Dg,Eq,Eh,6,Ft,Ff,0,Ft,Gg,00350,0 Ab,39.92,0.54,Cy,Dp,Eaa,Ev,0.5,Ft,Ft,03,Ff,Gg,00200,1000 Ab,33.58,2.75,Cu,Dg,Em,Ev,4.25,Ft,Ft,06,Ff,Gg,00204,0 Aa,18.83,9.5,Cu,Dg,Ew,Ev,1.625,Ft,Ft,06,Ft,Gg,00040,600 Aa,26.92,13.5,Cu,Dg,Eq,Eh,5,Ft,Ft,02,Ff,Gg,00000,5000 Aa,31.25,3.75,Cu,Dg,Ecc,Eh,0.625,Ft,Ft,09,Ft,Gg,00181,0 Aa,56.50,16,Cu,Dg,Ej,Eff,0,Ft,Ft,15,Ff,Gg,00000,247 Ab,43.00,0.29,Cy,Dp,Ecc,Eh,1.75,Ft,Ft,08,Ff,Gg,00100,375 Ab,22.33,11,Cu,Dg,Ew,Ev,2,Ft,Ft,01,Ff,Gg,00080,278 Ab,27.25,1.665,Cu,Dg,Ecc,Eh,5.085,Ft,Ft,09,Ff,Gg,00399,827 Ab,32.83,2.5,Cu,Dg,Ecc,Eh,2.75,Ft,Ft,06,Ff,Gg,00160,2072 Ab,23.25,1.5,Cu,Dg,Eq,Ev,2.375,Ft,Ft,03,Ft,Gg,00000,582 Aa,40.33,7.54,Cy,Dp,Eq,Eh,8,Ft,Ft,14,Ff,Gg,00000,2300 Aa,30.50,6.5,Cu,Dg,Ec,Ebb,4,Ft,Ft,07,Ft,Gg,00000,3065 Aa,52.83,15,Cu,Dg,Ec,Ev,5.5,Ft,Ft,14,Ff,Gg,00000,2200 Aa,46.67,0.46,Cu,Dg,Ecc,Eh,0.415,Ft,Ft,11,Ft,Gg,00440,6 Aa,58.33,10,Cu,Dg,Eq,Ev,4,Ft,Ft,14,Ff,Gg,00000,1602 Ab,37.33,6.5,Cu,Dg,Em,Eh,4.25,Ft,Ft,12,Ft,Gg,00093,0 Ab,23.08,2.5,Cu,Dg,Ec,Ev,1.085,Ft,Ft,11,Ft,Gg,00060,2184 Ab,32.75,1.5,Cu,Dg,Ecc,Eh,5.5,Ft,Ft,03,Ft,Gg,00000,0 Aa,21.67,11.5,Cy,Dp,Ej,Ej,0,Ft,Ft,11,Ft,Gg,00000,0 Aa,28.50,3.04,Cy,Dp,Ex,Eh,2.54,Ft,Ft,01,Ff,Gg,00070,0 Aa,68.67,15,Cu,Dg,Ee,Ez,0,Ft,Ft,14,Ff,Gg,00000,3376 Ab,28.00,2,Cu,Dg,Ek,Eh,4.165,Ft,Ft,02,Ft,Gg,00181,0 Ab,34.08,0.08,Cy,Dp,Em,Ebb,0.04,Ft,Ft,01,Ft,Gg,00280,2000 Ab,27.67,2,Cu,Dg,Ex,Eh,1,Ft,Ft,04,Ff,Gg,00140,7544 Ab,44.00,2,Cu,Dg,Em,Ev,1.75,Ft,Ft,02,Ft,Gg,00000,15 Ab,25.08,1.71,Cu,Dg,Ex,Ev,1.665,Ft,Ft,01,Ft,Gg,00395,20 Ab,32.00,1.75,Cy,Dp,Ee,Eh,0.04,Ft,Ff,0,Ft,Gg,00393,0 Aa,60.58,16.5,Cu,Dg,Eq,Ev,11,Ft,Ff,0,Ft,Gg,00021,10561 Aa,40.83,10,Cu,Dg,Eq,Eh,1.75,Ft,Ff,0,Ff,Gg,00029,837 Ab,19.33,9.5,Cu,Dg,Eq,Ev,1,Ft,Ff,0,Ft,Gg,00060,400 Aa,32.33,0.54,Cu,Dg,Ecc,Ev,0.04,Ft,Ff,0,Ff,Gg,00440,11177 Ab,36.67,3.25,Cu,Dg,Eq,Eh,9,Ft,Ff,0,Ft,Gg,00102,639 Ab,37.50,1.125,Cy,Dp,Ed,Ev,1.5,Ff,Ff,0,Ft,Gg,00431,0 Aa,25.08,2.54,Cy,Dp,Eaa,Ev,0.25,Ft,Ff,0,Ft,Gg,00370,0 Ab,41.33,0,Cu,Dg,Ec,Ebb,15,Ft,Ff,0,Ff,Gg,00000,0 Ab,56.00,12.5,Cu,Dg,Ek,Eh,8,Ft,Ff,0,Ft,Gg,00024,2028 Aa,49.83,13.585,Cu,Dg,Ek,Eh,8.5,Ft,Ff,0,Ft,Gg,00000,0 Ab,22.67,10.5,Cu,Dg,Eq,Eh,1.335,Ft,Ff,0,Ff,Gg,00100,0 Ab,27.00,1.5,Cy,Dp,Ew,Ev,0.375,Ft,Ff,0,Ft,Gg,00260,1065 Ab,25.00,12.5,Cu,Dg,Eaa,Ev,3,Ft,Ff,0,Ft,Gs,00020,0 Aa,26.08,8.665,Cu,Dg,Eaa,Ev,1.415,Ft,Ff,0,Ff,Gg,00160,150 Aa,18.42,9.25,Cu,Dg,Eq,Ev,1.21,Ft,Ft,04,Ff,Gg,00060,540 Ab,20.17,8.17,Cu,Dg,Eaa,Ev,1.96,Ft,Ft,14,Ff,Gg,00060,158 Ab,47.67,0.29,Cu,Dg,Ec,Ebb,15,Ft,Ft,20,Ff,Gg,00000,15000 Aa,21.25,2.335,Cu,Dg,Ei,Ebb,0.5,Ft,Ft,04,Ff,Gs,00080,0 Aa,20.67,3,Cu,Dg,Eq,Ev,0.165,Ft,Ft,03,Ff,Gg,00100,6 Aa,57.08,19.5,Cu,Dg,Ec,Ev,5.5,Ft,Ft,07,Ff,Gg,00000,3000 Aa,22.42,5.665,Cu,Dg,Eq,Ev,2.585,Ft,Ft,07,Ff,Gg,00129,3257 Ab,48.75,8.5,Cu,Dg,Ec,Eh,12.5,Ft,Ft,09,Ff,Gg,00181,1655 Ab,40.00,6.5,Cu,Dg,Eaa,Ebb,3.5,Ft,Ft,01,Ff,Gg,00000,500 Ab,40.58,5,Cu,Dg,Ec,Ev,5,Ft,Ft,07,Ff,Gg,00000,3065 Aa,28.67,1.04,Cu,Dg,Ec,Ev,2.5,Ft,Ft,05,Ft,Gg,00300,1430 Aa,33.08,4.625,Cu,Dg,Eq,Eh,1.625,Ft,Ft,02,Ff,Gg,00000,0 Ab,21.33,10.5,Cu,Dg,Ec,Ev,3,Ft,Ff,0,Ft,Gg,00000,0 Ab,42.00,0.205,Cu,Dg,Ei,Eh,5.125,Ft,Ff,0,Ff,Gg,00400,0 Ab,41.75,0.96,Cu,Dg,Ex,Ev,2.5,Ft,Ff,0,Ff,Gg,00510,600 Ab,22.67,1.585,Cy,Dp,Ew,Ev,3.085,Ft,Ft,06,Ff,Gg,00080,0 Ab,34.50,4.04,Cy,Dp,Ei,Ebb,8.5,Ft,Ft,07,Ft,Gg,00195,0 Ab,28.25,5.04,Cy,Dp,Ec,Ebb,1.5,Ft,Ft,08,Ft,Gg,00144,7 Ab,33.17,3.165,Cy,Dp,Ex,Ev,3.165,Ft,Ft,03,Ft,Gg,00380,0 Ab,48.17,7.625,Cu,Dg,Ew,Eh,15.5,Ft,Ft,12,Ff,Gg,00000,790 Ab,27.58,2.04,Cy,Dp,Eaa,Ev,2,Ft,Ft,03,Ft,Gg,00370,560 Ab,22.58,10.04,Cu,Dg,Ex,Ev,0.04,Ft,Ft,09,Ff,Gg,00060,396 Aa,24.08,0.5,Cu,Dg,Eq,Eh,1.25,Ft,Ft,01,Ff,Gg,00000,678 Aa,41.33,1,Cu,Dg,Ei,Ebb,2.25,Ft,Ff,0,Ft,Gg,00000,300 Ab,24.83,2.75,Cu,Dg,Ec,Ev,2.25,Ft,Ft,06,Ff,Gg,?,600 Aa,20.75,10.25,Cu,Dg,Eq,Ev,0.71,Ft,Ft,02,Ft,Gg,00049,0 Ab,36.33,2.125,Cy,Dp,Ew,Ev,0.085,Ft,Ft,01,Ff,Gg,00050,1187 Aa,35.42,12,Cu,Dg,Eq,Eh,14,Ft,Ft,08,Ff,Gg,00000,6590 Aa,71.58,0,?,?,?,?,0,Ff,Ff,0,Ff,Gp,?,0 Ab,28.67,9.335,Cu,Dg,Eq,Eh,5.665,Ft,Ft,06,Ff,Gg,00381,168 Ab,35.17,2.5,Cu,Dg,Ek,Ev,4.5,Ft,Ft,07,Ff,Gg,00150,1270 Ab,39.50,4.25,Cu,Dg,Ec,Ebb,6.5,Ft,Ft,16,Ff,Gg,00117,1210 Ab,39.33,5.875,Cu,Dg,Ecc,Eh,10,Ft,Ft,14,Ft,Gg,00399,0 Ab,24.33,6.625,Cy,Dp,Ed,Ev,5.5,Ft,Ff,0,Ft,Gs,00100,0 Ab,60.08,14.5,Cu,Dg,Eff,Eff,18,Ft,Ft,15,Ft,Gg,00000,1000 Ab,23.08,11.5,Cu,Dg,Ei,Ev,3.5,Ft,Ft,09,Ff,Gg,00056,742 Ab,26.67,2.71,Cy,Dp,Ecc,Ev,5.25,Ft,Ft,01,Ff,Gg,00211,0 Ab,48.17,3.5,Cu,Dg,Eaa,Ev,3.5,Ft,Ff,0,Ff,Gs,00230,0 Ab,41.17,4.04,Cu,Dg,Ecc,Eh,7,Ft,Ft,08,Ff,Gg,00320,0 Ab,55.92,11.5,Cu,Dg,Eff,Eff,5,Ft,Ft,05,Ff,Gg,00000,8851 Ab,53.92,9.625,Cu,Dg,Ee,Ev,8.665,Ft,Ft,05,Ff,Gg,00000,0 Aa,18.92,9.25,Cy,Dp,Ec,Ev,1,Ft,Ft,04,Ft,Gg,00080,500 Aa,50.08,12.54,Cu,Dg,Eaa,Ev,2.29,Ft,Ft,03,Ft,Gg,00156,0 Ab,65.42,11,Cu,Dg,Ee,Ez,20,Ft,Ft,07,Ft,Gg,00022,0 Aa,17.58,9,Cu,Dg,Eaa,Ev,1.375,Ft,Ff,0,Ft,Gg,00000,0 Aa,18.83,9.54,Cu,Dg,Eaa,Ev,0.085,Ft,Ff,0,Ff,Gg,00100,0 Aa,37.75,5.5,Cu,Dg,Eq,Ev,0.125,Ft,Ff,0,Ft,Gg,00228,0 Ab,23.25,4,Cu,Dg,Ec,Ebb,0.25,Ft,Ff,0,Ft,Gg,00160,0 Ab,18.08,5.5,Cu,Dg,Ek,Ev,0.5,Ft,Ff,0,Ff,Gg,00080,0 Aa,22.50,8.46,Cy,Dp,Ex,Ev,2.46,Ff,Ff,0,Ff,Gg,00164,0 Ab,19.67,0.375,Cu,Dg,Eq,Ev,2,Ft,Ft,02,Ft,Gg,00080,0 Ab,22.08,11,Cu,Dg,Ecc,Ev,0.665,Ft,Ff,0,Ff,Gg,00100,0 Ab,25.17,3.5,Cu,Dg,Ecc,Ev,0.625,Ft,Ft,07,Ff,Gg,00000,7059 Aa,47.42,3,Cu,Dg,Ex,Ev,13.875,Ft,Ft,02,Ft,Gg,00519,1704 Ab,33.50,1.75,Cu,Dg,Ex,Eh,4.5,Ft,Ft,04,Ft,Gg,00253,857 Ab,27.67,13.75,Cu,Dg,Ew,Ev,5.75,Ft,Ff,0,Ft,Gg,00487,500 Aa,58.42,21,Cu,Dg,Ei,Ebb,10,Ft,Ft,13,Ff,Gg,00000,6700 Aa,20.67,1.835,Cu,Dg,Eq,Ev,2.085,Ft,Ft,05,Ff,Gg,00220,2503 Ab,26.17,0.25,Cu,Dg,Ei,Ebb,0,Ft,Ff,0,Ft,Gg,00000,0 Ab,21.33,7.5,Cu,Dg,Eaa,Ev,1.415,Ft,Ft,01,Ff,Gg,00080,9800 Ab,42.83,4.625,Cu,Dg,Eq,Ev,4.58,Ft,Ff,0,Ff,Gs,00000,0 Ab,38.17,10.125,Cu,Dg,Ex,Ev,2.5,Ft,Ft,06,Ff,Gg,00520,196 Ab,20.50,10,Cy,Dp,Ec,Ev,2.5,Ft,Ff,0,Ff,Gs,00040,0 Ab,48.25,25.085,Cu,Dg,Ew,Ev,1.75,Ft,Ft,03,Ff,Gg,00120,14 Ab,28.33,5,Cu,Dg,Ew,Ev,11,Ft,Ff,0,Ft,Gg,00070,0 Aa,18.75,7.5,Cu,Dg,Eq,Ev,2.71,Ft,Ft,05,Ff,Gg,?,26726 Ab,18.50,2,Cu,Dg,Ei,Ev,1.5,Ft,Ft,02,Ff,Gg,00120,300 Ab,33.17,3.04,Cy,Dp,Ec,Eh,2.04,Ft,Ft,01,Ft,Gg,00180,18027 Ab,45.00,8.5,Cu,Dg,Ecc,Eh,14,Ft,Ft,01,Ft,Gg,00088,2000 Aa,19.67,0.21,Cu,Dg,Eq,Eh,0.29,Ft,Ft,11,Ff,Gg,00080,99 ?,24.50,12.75,Cu,Dg,Ec,Ebb,4.75,Ft,Ft,02,Ff,Gg,00073,444 Ab,21.83,11,Cu,Dg,Ex,Ev,0.29,Ft,Ft,06,Ff,Gg,00121,0 Ab,40.25,21.5,Cu,Dg,Ee,Ez,20,Ft,Ft,11,Ff,Gg,00000,1200 Ab,41.42,5,Cu,Dg,Eq,Eh,5,Ft,Ft,06,Ft,Gg,00470,0 Aa,17.83,11,Cu,Dg,Ex,Eh,1,Ft,Ft,11,Ff,Gg,00000,3000 Ab,23.17,11.125,Cu,Dg,Ex,Eh,0.46,Ft,Ft,01,Ff,Gg,00100,0 Ab,59.67,1.54,Cu,Dg,Eq,Ev,0.125,Ft,Ff,0,Ft,Gg,00260,0 Ab,18.00,0.165,Cu,Dg,Eq,En,0.21,Ff,Ff,0,Ff,Gg,00200,40 Ab,37.58,0,?,?,?,?,0,Ff,Ff,0,Ff,Gp,?,0 Ab,17.50,22,Cl,Dgg,Eff,Eo,0,Ff,Ff,0,Ft,Gp,00450,100000 Ab,19.17,0,Cy,Dp,Em,Ebb,0,Ff,Ff,0,Ft,Gs,00500,1 Ab,36.75,0.125,Cy,Dp,Ec,Ev,1.5,Ff,Ff,0,Ft,Gg,00232,113 Ab,21.25,1.5,Cu,Dg,Ew,Ev,1.5,Ff,Ff,0,Ff,Gg,00150,8 Aa,18.08,0.375,Cl,Dgg,Ecc,Eff,10,Ff,Ff,0,Ft,Gs,00300,0 Aa,33.67,0.375,Cu,Dg,Ecc,Ev,0.375,Ff,Ff,0,Ff,Gg,00300,44 Ab,48.58,0.205,Cy,Dp,Ek,Ev,0.25,Ft,Ft,11,Ff,Gg,00380,2732 ; Ab,32.33,7.5,Cu,Dg,Ee,Ebb,1.585,Ft,Ff,0,Ft,Gs,00420,0 Ab,34.83,4,Cu,Dg,Ed,Ebb,12.5,Ft,Ff,0,Ft,Gg,?,0 Aa,38.58,5,Cu,Dg,Ecc,Ev,13.5,Ft,Ff,0,Ft,Gg,00980,0 Ab,44.25,0.5,Cu,Dg,Em,Ev,10.75,Ft,Ff,0,Ff,Gs,00400,0 Ab,44.83,7,Cy,Dp,Ec,Ev,1.625,Ff,Ff,0,Ff,Gg,00160,2 Ab,20.67,5.29,Cu,Dg,Eq,Ev,0.375,Ft,Ft,01,Ff,Gg,00160,0 Ab,34.08,6.5,Cu,Dg,Eaa,Ev,0.125,Ft,Ff,0,Ft,Gg,00443,0 Aa,19.17,0.585,Cy,Dp,Eaa,Ev,0.585,Ft,Ff,0,Ft,Gg,00160,0 Ab,21.67,1.165,Cy,Dp,Ek,Ev,2.5,Ft,Ft,01,Ff,Gg,00180,20 Ab,21.50,9.75,Cu,Dg,Ec,Ev,0.25,Ft,Ff,0,Ff,Gg,00140,0 Ab,49.58,19,Cu,Dg,Eff,Eff,0,Ft,Ft,01,Ff,Gg,00094,0 Aa,27.67,1.5,Cu,Dg,Em,Ev,2,Ft,Ff,0,Ff,Gs,00368,0 Ab,39.83,0.5,Cu,Dg,Em,Ev,0.25,Ft,Ff,0,Ff,Gs,00288,0 Aa,?,3.5,Cu,Dg,Ed,Ev,3,Ft,Ff,0,Ft,Gg,00300,0 Ab,27.25,0.625,Cu,Dg,Eaa,Ev,0.455,Ft,Ff,0,Ft,Gg,00200,0 Ab,37.17,4,Cu,Dg,Ec,Ebb,5,Ft,Ff,0,Ft,Gs,00280,0 Ab,?,0.375,Cu,Dg,Ed,Ev,0.875,Ft,Ff,0,Ft,Gs,00928,0 Ab,25.67,2.21,Cy,Dp,Eaa,Ev,4,Ft,Ff,0,Ff,Gg,00188,0 Ab,34.00,4.5,Cu,Dg,Eaa,Ev,1,Ft,Ff,0,Ft,Gg,00240,0 Aa,49.00,1.5,Cu,Dg,Ej,Ej,0,Ft,Ff,0,Ft,Gg,00100,27 Ab,62.50,12.75,Cy,Dp,Ec,Eh,5,Ft,Ff,0,Ff,Gg,00112,0 Ab,31.42,15.5,Cu,Dg,Ec,Ev,0.5,Ft,Ff,0,Ff,Gg,00120,0 Ab,?,5,Cy,Dp,Eaa,Ev,8.5,Ft,Ff,0,Ff,Gg,00000,0 Ab,52.33,1.375,Cy,Dp,Ec,Eh,9.46,Ft,Ff,0,Ft,Gg,00200,100 Ab,28.75,1.5,Cy,Dp,Ec,Ev,1.5,Ft,Ff,0,Ft,Gg,00000,225 Aa,28.58,3.54,Cu,Dg,Ei,Ebb,0.5,Ft,Ff,0,Ft,Gg,00171,0 Ab,23.00,0.625,Cy,Dp,Eaa,Ev,0.125,Ft,Ff,0,Ff,Gg,00180,1 Ab,?,0.5,Cu,Dg,Ec,Ebb,0.835,Ft,Ff,0,Ft,Gs,00320,0 Aa,22.50,11,Cy,Dp,Eq,Ev,3,Ft,Ff,0,Ft,Gg,00268,0 Aa,28.50,1,Cu,Dg,Eq,Ev,1,Ft,Ft,02,Ft,Gg,00167,500 Ab,37.50,1.75,Cy,Dp,Ec,Ebb,0.25,Ft,Ff,0,Ft,Gg,00164,400 Ab,35.25,16.5,Cy,Dp,Ec,Ev,4,Ft,Ff,0,Ff,Gg,00080,0 Ab,18.67,5,Cu,Dg,Eq,Ev,0.375,Ft,Ft,02,Ff,Gg,00000,38 Ab,25.00,12,Cu,Dg,Ek,Ev,2.25,Ft,Ft,02,Ft,Gg,00120,5 Ab,27.83,4,Cy,Dp,Ei,Eh,5.75,Ft,Ft,02,Ft,Gg,00075,0 Ab,54.83,15.5,Cu,Dg,Ee,Ez,0,Ft,Ft,20,Ff,Gg,00152,130 Ab,28.75,1.165,Cu,Dg,Ek,Ev,0.5,Ft,Ff,0,Ff,Gs,00280,0 Aa,25.00,11,Cy,Dp,Eaa,Ev,4.5,Ft,Ff,0,Ff,Gg,00120,0 Ab,40.92,2.25,Cy,Dp,Ex,Eh,10,Ft,Ff,0,Ft,Gg,00176,0 Aa,19.75,0.75,Cu,Dg,Ec,Ev,0.795,Ft,Ft,05,Ft,Gg,00140,5 Ab,29.17,3.5,Cu,Dg,Ew,Ev,3.5,Ft,Ft,03,Ft,Gg,00329,0 Aa,24.50,1.04,Cy,Dp,Eff,Eff,0.5,Ft,Ft,03,Ff,Gg,00180,147 Ab,24.58,12.5,Cu,Dg,Ew,Ev,0.875,Ft,Ff,0,Ft,Gg,00260,0 Aa,33.75,0.75,Cu,Dg,Ek,Ebb,1,Ft,Ft,03,Ft,Gg,00212,0 Ab,20.67,1.25,Cy,Dp,Ec,Eh,1.375,Ft,Ft,03,Ft,Gg,00140,210 Aa,25.42,1.125,Cu,Dg,Eq,Ev,1.29,Ft,Ft,02,Ff,Gg,00200,0 Ab,37.75,7,Cu,Dg,Eq,Eh,11.5,Ft,Ft,07,Ft,Gg,00300,5 Ab,?,0.625,Cu,Dg,Ek,Ev,0.25,Ff,Ff,0,Ff,Gg,00380,2010 Ab,18.17,10.25,Cu,Dg,Ec,Eh,1.085,Ff,Ff,0,Ff,Gg,00320,13 Ab,20.00,11.045,Cu,Dg,Ec,Ev,2,Ff,Ff,0,Ft,Gg,00136,0 Ab,20.00,0,Cu,Dg,Ed,Ev,0.5,Ff,Ff,0,Ff,Gg,00144,0 Aa,20.75,9.54,Cu,Dg,Ei,Ev,0.04,Ff,Ff,0,Ff,Gg,00200,1000 Aa,24.50,1.75,Cy,Dp,Ec,Ev,0.165,Ff,Ff,0,Ff,Gg,00132,0 Ab,32.75,2.335,Cu,Dg,Ed,Eh,5.75,Ff,Ff,0,Ft,Gg,00292,0 Aa,52.17,0,Cy,Dp,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00000,0 Aa,48.17,1.335,Cu,Dg,Ei,Eo,0.335,Ff,Ff,0,Ff,Gg,00000,120 Aa,20.42,10.5,Cy,Dp,Ex,Eh,0,Ff,Ff,0,Ft,Gg,00154,32 Ab,50.75,0.585,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00145,0 Ab,17.08,0.085,Cy,Dp,Ec,Ev,0.04,Ff,Ff,0,Ff,Gg,00140,722 Ab,18.33,1.21,Cy,Dp,Ee,Edd,0,Ff,Ff,0,Ff,Gg,00100,0 Aa,32.00,6,Cu,Dg,Ed,Ev,1.25,Ff,Ff,0,Ff,Gg,00272,0 Ab,32.33,2.5,Cu,Dg,Ec,Ev,1.25,Ff,Ff,0,Ft,Gg,00280,0 Ab,18.08,6.75,Cy,Dp,Em,Ev,0.04,Ff,Ff,0,Ff,Gg,00140,0 Ab,38.25,10.125,Cy,Dp,Ek,Ev,0.125,Ff,Ff,0,Ff,Gg,00160,0 Ab,30.67,2.5,Cu,Dg,Ecc,Eh,2.25,Ff,Ff,0,Ft,Gs,00340,0 Ab,18.58,5.71,Cu,Dg,Ed,Ev,0.54,Ff,Ff,0,Ff,Gg,00120,0 Aa,19.17,5.415,Cu,Dg,Ei,Eh,0.29,Ff,Ff,0,Ff,Gg,00080,484 Aa,18.17,10,Cy,Dp,Eq,Eh,0.165,Ff,Ff,0,Ff,Gg,00340,0 Ab,24.58,13.5,Cy,Dp,Eff,Eff,0,Ff,Ff,0,Ff,Gg,?,0 Ab,16.25,0.835,Cu,Dg,Em,Ev,0.085,Ft,Ff,0,Ff,Gs,00200,0 Ab,21.17,0.875,Cy,Dp,Ec,Eh,0.25,Ff,Ff,0,Ff,Gg,00280,204 Ab,23.92,0.585,Cy,Dp,Ecc,Eh,0.125,Ff,Ff,0,Ff,Gg,00240,1 Ab,17.67,4.46,Cu,Dg,Ec,Ev,0.25,Ff,Ff,0,Ff,Gs,00080,0 Aa,16.50,1.25,Cu,Dg,Eq,Ev,0.25,Ff,Ft,01,Ff,Gg,00108,98 Ab,23.25,12.625,Cu,Dg,Ec,Ev,0.125,Ff,Ft,02,Ff,Gg,00000,5552 Ab,17.58,10,Cu,Dg,Ew,Eh,0.165,Ff,Ft,01,Ff,Gg,00120,1 Aa,?,1.5,Cu,Dg,Eff,Eff,0,Ff,Ft,02,Ft,Gg,00200,105 Ab,29.50,0.58,Cu,Dg,Ew,Ev,0.29,Ff,Ft,01,Ff,Gg,00340,2803 Ab,18.83,0.415,Cy,Dp,Ec,Ev,0.165,Ff,Ft,01,Ff,Gg,00200,1 Aa,21.75,1.75,Cy,Dp,Ej,Ej,0,Ff,Ff,0,Ff,Gg,00160,0 Ab,23.00,0.75,Cu,Dg,Em,Ev,0.5,Ff,Ff,0,Ft,Gs,00320,0 Aa,18.25,10,Cu,Dg,Ew,Ev,1,Ff,Ft,01,Ff,Gg,00120,1 Ab,25.42,0.54,Cu,Dg,Ew,Ev,0.165,Ff,Ft,01,Ff,Gg,00272,444 Ab,35.75,2.415,Cu,Dg,Ew,Ev,0.125,Ff,Ft,02,Ff,Gg,00220,1 Aa,16.08,0.335,Cu,Dg,Eff,Eff,0,Ff,Ft,01,Ff,Gg,00160,126 Aa,31.92,3.125,Cu,Dg,Eff,Eff,3.04,Ff,Ft,02,Ft,Gg,00200,4 Ab,69.17,9,Cu,Dg,Eff,Eff,4,Ff,Ft,01,Ff,Gg,00070,6 Ab,32.92,2.5,Cu,Dg,Eaa,Ev,1.75,Ff,Ft,02,Ft,Gg,00720,0 Ab,16.33,2.75,Cu,Dg,Eaa,Ev,0.665,Ff,Ft,01,Ff,Gg,00080,21 Ab,22.17,12.125,Cu,Dg,Ec,Ev,3.335,Ff,Ft,02,Ft,Gg,00180,173 Aa,57.58,2,Cu,Dg,Eff,Eff,6.5,Ff,Ft,01,Ff,Gg,00000,10 Ab,18.25,0.165,Cu,Dg,Ed,Ev,0.25,Ff,Ff,0,Ft,Gs,00280,0 Ab,23.42,1,Cu,Dg,Ec,Ev,0.5,Ff,Ff,0,Ft,Gs,00280,0 Aa,15.92,2.875,Cu,Dg,Eq,Ev,0.085,Ff,Ff,0,Ff,Gg,00120,0 Aa,24.75,13.665,Cu,Dg,Eq,Eh,1.5,Ff,Ff,0,Ff,Gg,00280,1 Ab,48.75,26.335,Cy,Dp,Eff,Eff,0,Ft,Ff,0,Ft,Gg,00000,0 Ab,23.50,2.75,Cu,Dg,Eff,Eff,4.5,Ff,Ff,0,Ff,Gg,00160,25 Ab,18.58,10.29,Cu,Dg,Eff,Eff,0.415,Ff,Ff,0,Ff,Gg,00080,0 Ab,27.75,1.29,Cu,Dg,Ek,Eh,0.25,Ff,Ff,0,Ft,Gs,00140,0 Aa,31.75,3,Cy,Dp,Ej,Ej,0,Ff,Ff,0,Ff,Gg,00160,20 Aa,24.83,4.5,Cu,Dg,Ew,Ev,1,Ff,Ff,0,Ft,Gg,00360,6 Ab,19.00,1.75,Cy,Dp,Ec,Ev,2.335,Ff,Ff,0,Ft,Gg,00112,6 Aa,16.33,0.21,Cu,Dg,Eaa,Ev,0.125,Ff,Ff,0,Ff,Gg,00200,1 Aa,18.58,10,Cu,Dg,Ed,Ev,0.415,Ff,Ff,0,Ff,Gg,00080,42 Ab,16.25,0,Cy,Dp,Eaa,Ev,0.25,Ff,Ff,0,Ff,Gg,00060,0 Ab,23.00,0.75,Cu,Dg,Em,Ev,0.5,Ft,Ff,0,Ft,Gs,00320,0 Ab,21.17,0.25,Cy,Dp,Ec,Eh,0.25,Ff,Ff,0,Ff,Gg,00280,204 Ab,33.67,1.25,Cu,Dg,Ew,Ev,1.165,Ff,Ff,0,Ff,Gg,00120,0 Aa,29.50,1.085,Cy,Dp,Ex,Ev,1,Ff,Ff,0,Ff,Gg,00280,13 Ab,30.17,1.085,Cy,Dp,Ec,Ev,0.04,Ff,Ff,0,Ff,Gg,00170,179 ?,40.83,3.5,Cu,Dg,Ei,Ebb,0.5,Ff,Ff,0,Ff,Gs,01160,0 Ab,34.83,2.5,Cy,Dp,Ew,Ev,3,Ff,Ff,0,Ff,Gs,00200,0 Ab,?,4,Cy,Dp,Ei,Ev,0.085,Ff,Ff,0,Ft,Gg,00411,0 Ab,20.42,0,?,?,?,?,0,Ff,Ff,0,Ff,Gp,?,0 Aa,33.25,2.5,Cy,Dp,Ec,Ev,2.5,Ff,Ff,0,Ft,Gg,00000,2 Ab,34.08,2.5,Cu,Dg,Ec,Ev,1,Ff,Ff,0,Ff,Gg,00460,16 Aa,25.25,12.5,Cu,Dg,Ed,Ev,1,Ff,Ff,0,Ft,Gg,00180,1062 Ab,34.75,2.5,Cu,Dg,Ecc,Ebb,0.5,Ff,Ff,0,Ff,Gg,00348,0 Ab,27.67,0.75,Cu,Dg,Eq,Eh,0.165,Ff,Ff,0,Ft,Gg,00220,251 Ab,47.33,6.5,Cu,Dg,Ec,Ev,1,Ff,Ff,0,Ft,Gg,00000,228 Aa,34.83,1.25,Cy,Dp,Ei,Eh,0.5,Ff,Ff,0,Ft,Gg,00160,0 Aa,33.25,3,Cy,Dp,Eaa,Ev,2,Ff,Ff,0,Ff,Gg,00180,0 Ab,28.00,3,Cu,Dg,Ew,Ev,0.75,Ff,Ff,0,Ft,Gg,00300,67 Aa,39.08,4,Cu,Dg,Ec,Ev,3,Ff,Ff,0,Ff,Gg,00480,0 Ab,42.75,4.085,Cu,Dg,Eaa,Ev,0.04,Ff,Ff,0,Ff,Gg,00108,100 Ab,26.92,2.25,Cu,Dg,Ei,Ebb,0.5,Ff,Ff,0,Ft,Gg,00640,4000 Ab,33.75,2.75,Cu,Dg,Ei,Ebb,0,Ff,Ff,0,Ff,Gg,00180,0 Ab,38.92,1.75,Cu,Dg,Ek,Ev,0.5,Ff,Ff,0,Ft,Gg,00300,2 Ab,62.75,7,Cu,Dg,Ee,Ez,0,Ff,Ff,0,Ff,Gg,00000,12 ?,32.25,1.5,Cu,Dg,Ec,Ev,0.25,Ff,Ff,0,Ft,Gg,00372,122 Ab,26.75,4.5,Cy,Dp,Ec,Ebb,2.5,Ff,Ff,0,Ff,Gg,00200,1210 Ab,63.33,0.54,Cu,Dg,Ec,Ev,0.585,Ft,Ft,03,Ft,Gg,00180,0 Ab,27.83,1.5,Cu,Dg,Ew,Ev,2.25,Ff,Ft,01,Ft,Gg,00100,3 Aa,26.17,2,Cu,Dg,Ej,Ej,0,Ff,Ff,0,Ft,Gg,00276,1 Ab,22.17,0.585,Cy,Dp,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00100,0 Ab,22.50,11.5,Cy,Dp,Em,Ev,1.5,Ff,Ff,0,Ft,Gg,00000,4000 Ab,30.75,1.585,Cu,Dg,Ed,Ev,0.585,Ff,Ff,0,Ft,Gs,00000,0 Ab,36.67,2,Cu,Dg,Ei,Ev,0.25,Ff,Ff,0,Ft,Gg,00221,0 Aa,16.00,0.165,Cu,Dg,Eaa,Ev,1,Ff,Ft,02,Ft,Gg,00320,1 Ab,41.17,1.335,Cu,Dg,Ed,Ev,0.165,Ff,Ff,0,Ff,Gg,00168,0 Aa,19.50,0.165,Cu,Dg,Eq,Ev,0.04,Ff,Ff,0,Ft,Gg,00380,0 Ab,32.42,3,Cu,Dg,Ed,Ev,0.165,Ff,Ff,0,Ft,Gg,00120,0 Aa,36.75,4.71,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00160,0 Aa,30.25,5.5,Cu,Dg,Ek,Ev,5.5,Ff,Ff,0,Ft,Gs,00100,0 Ab,23.08,2.5,Cu,Dg,Eff,Eff,0.085,Ff,Ff,0,Ft,Gg,00100,4208 Ab,26.83,0.54,Cu,Dg,Ek,Eff,0,Ff,Ff,0,Ff,Gg,00100,0 Ab,16.92,0.335,Cy,Dp,Ek,Ev,0.29,Ff,Ff,0,Ff,Gs,00200,0 Ab,24.42,2,Cu,Dg,Ee,Edd,0.165,Ff,Ft,02,Ff,Gg,00320,1300 Ab,42.83,1.25,Cu,Dg,Em,Ev,13.875,Ff,Ft,01,Ft,Gg,00352,112 Aa,22.75,6.165,Cu,Dg,Eaa,Ev,0.165,Ff,Ff,0,Ff,Gg,00220,1000 Ab,39.42,1.71,Cy,Dp,Em,Ev,0.165,Ff,Ff,0,Ff,Gs,00400,0 Aa,23.58,11.5,Cy,Dp,Ek,Eh,3,Ff,Ff,0,Ft,Gg,00020,16 Ab,21.42,0.75,Cy,Dp,Er,En,0.75,Ff,Ff,0,Ft,Gg,00132,2 Ab,33.00,2.5,Cy,Dp,Ew,Ev,7,Ff,Ff,0,Ft,Gg,00280,0 Ab,26.33,13,Cu,Dg,Ee,Edd,0,Ff,Ff,0,Ft,Gg,00140,1110 Aa,45.00,4.585,Cu,Dg,Ek,Eh,1,Ff,Ff,0,Ft,Gs,00240,0 Ab,26.25,1.54,Cu,Dg,Ew,Ev,0.125,Ff,Ff,0,Ff,Gg,00100,0 ?,28.17,0.585,Cu,Dg,Eaa,Ev,0.04,Ff,Ff,0,Ff,Gg,00260,1004 Aa,20.83,0.5,Cy,Dp,Ee,Edd,1,Ff,Ff,0,Ff,Gg,00260,0 Ab,28.67,14.5,Cu,Dg,Ed,Ev,0.125,Ff,Ff,0,Ff,Gg,00000,286 Ab,20.67,0.835,Cy,Dp,Ec,Ev,2,Ff,Ff,0,Ft,Gs,00240,0 Ab,34.42,1.335,Cu,Dg,Ei,Ebb,0.125,Ff,Ff,0,Ft,Gg,00440,4500 Ab,33.58,0.25,Cu,Dg,Ei,Ebb,4,Ff,Ff,0,Ft,Gs,00420,0 Ab,43.17,5,Cu,Dg,Ei,Ebb,2.25,Ff,Ff,0,Ft,Gg,00141,0 Aa,22.67,7,Cu,Dg,Ec,Ev,0.165,Ff,Ff,0,Ff,Gg,00160,0 Aa,24.33,2.5,Cy,Dp,Ei,Ebb,4.5,Ff,Ff,0,Ff,Gg,00200,456 Aa,56.83,4.25,Cy,Dp,Eff,Eff,5,Ff,Ff,0,Ft,Gg,00000,4 Ab,22.08,11.46,Cu,Dg,Ek,Ev,1.585,Ff,Ff,0,Ft,Gg,00100,1212 Ab,34.00,5.5,Cy,Dp,Ec,Ev,1.5,Ff,Ff,0,Ft,Gg,00060,0 Ab,22.58,1.5,Cy,Dp,Eaa,Ev,0.54,Ff,Ff,0,Ft,Gg,00120,67 Ab,21.17,0,Cu,Dg,Ec,Ev,0.5,Ff,Ff,0,Ft,Gs,00000,0 Ab,26.67,14.585,Cu,Dg,Ei,Ebb,0,Ff,Ff,0,Ft,Gg,00178,0 Ab,22.92,0.17,Cu,Dg,Em,Ev,0.085,Ff,Ff,0,Ff,Gs,00000,0 Ab,15.17,7,Cu,Dg,Ee,Ev,1,Ff,Ff,0,Ff,Gg,00600,0 Ab,39.92,5,Cu,Dg,Ei,Ebb,0.21,Ff,Ff,0,Ff,Gg,00550,0 Ab,27.42,12.5,Cu,Dg,Eaa,Ebb,0.25,Ff,Ff,0,Ft,Gg,00720,0 Ab,24.75,0.54,Cu,Dg,Em,Ev,1,Ff,Ff,0,Ft,Gg,00120,1 Ab,41.17,1.25,Cy,Dp,Ew,Ev,0.25,Ff,Ff,0,Ff,Gg,00000,195 Aa,33.08,1.625,Cu,Dg,Ed,Ev,0.54,Ff,Ff,0,Ft,Gg,00000,0 Ab,29.83,2.04,Cy,Dp,Ex,Eh,0.04,Ff,Ff,0,Ff,Gg,00128,1 Aa,23.58,0.585,Cy,Dp,Eff,Eff,0.125,Ff,Ff,0,Ff,Gg,00120,87 Ab,26.17,12.5,Cy,Dp,Ek,Eh,1.25,Ff,Ff,0,Ft,Gg,00000,17 Ab,31.00,2.085,Cu,Dg,Ec,Ev,0.085,Ff,Ff,0,Ff,Gg,00300,0 Ab,20.75,5.085,Cy,Dp,Ej,Ev,0.29,Ff,Ff,0,Ff,Gg,00140,184 Ab,28.92,0.375,Cu,Dg,Ec,Ev,0.29,Ff,Ff,0,Ff,Gg,00220,140 Aa,51.92,6.5,Cu,Dg,Ei,Ebb,3.085,Ff,Ff,0,Ft,Gg,00073,0 Aa,22.67,0.335,Cu,Dg,Eq,Ev,0.75,Ff,Ff,0,Ff,Gs,00160,0 Ab,34.00,5.085,Cy,Dp,Ei,Ebb,1.085,Ff,Ff,0,Ft,Gg,00480,0 Aa,69.50,6,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gs,00000,0 Aa,40.33,8.125,Cy,Dp,Ek,Ev,0.165,Ff,Ft,02,Ff,Gg,?,18 Aa,19.58,0.665,Cy,Dp,Ec,Ev,1,Ff,Ft,01,Ff,Gg,02000,2 Ab,16.00,3.125,Cu,Dg,Ew,Ev,0.085,Ff,Ft,01,Ff,Gg,00000,6 Ab,17.08,0.25,Cu,Dg,Eq,Ev,0.335,Ff,Ft,04,Ff,Gg,00160,8 Ab,31.25,2.835,Cu,Dg,Eff,Eff,0,Ff,Ft,05,Ff,Gg,00176,146 Ab,25.17,3,Cu,Dg,Ec,Ev,1.25,Ff,Ft,01,Ff,Gg,00000,22 Aa,22.67,0.79,Cu,Dg,Ei,Ev,0.085,Ff,Ff,0,Ff,Gg,00144,0 Ab,40.58,1.5,Cu,Dg,Ei,Ebb,0,Ff,Ff,0,Ff,Gs,00300,0 Ab,22.25,0.46,Cu,Dg,Ek,Ev,0.125,Ff,Ff,0,Ft,Gg,00280,55 Aa,22.25,1.25,Cy,Dp,Eff,Eff,3.25,Ff,Ff,0,Ff,Gg,00280,0 Ab,22.50,0.125,Cy,Dp,Ek,Ev,0.125,Ff,Ff,0,Ff,Gg,00200,70 Ab,23.58,1.79,Cu,Dg,Ec,Ev,0.54,Ff,Ff,0,Ft,Gg,00136,1 Ab,38.42,0.705,Cu,Dg,Ec,Ev,0.375,Ff,Ft,02,Ff,Gg,00225,500 Aa,26.58,2.54,Cy,Dp,Eff,Eff,0,Ff,Ff,0,Ft,Gg,00180,60 Ab,35.00,2.5,Cu,Dg,Ei,Ev,1,Ff,Ff,0,Ft,Gg,00210,0 Ab,20.42,1.085,Cu,Dg,Eq,Ev,1.5,Ff,Ff,0,Ff,Gg,00108,7 Ab,29.42,1.25,Cu,Dg,Ew,Ev,1.75,Ff,Ff,0,Ff,Gg,00200,0 Ab,26.17,0.835,Cu,Dg,Ecc,Ev,1.165,Ff,Ff,0,Ff,Gg,00100,0 Ab,33.67,2.165,Cu,Dg,Ec,Ev,1.5,Ff,Ff,0,Ff,Gp,00120,0 Ab,24.58,1.25,Cu,Dg,Ec,Ev,0.25,Ff,Ff,0,Ff,Gg,00110,0 Aa,27.67,2.04,Cu,Dg,Ew,Ev,0.25,Ff,Ff,0,Ft,Gg,00180,50 Ab,37.50,0.835,Cu,Dg,Ee,Ev,0.04,Ff,Ff,0,Ff,Gg,00120,5 Ab,49.17,2.29,Cu,Dg,Eff,Eff,0.29,Ff,Ff,0,Ff,Gg,00200,3 Ab,33.58,0.335,Cy,Dp,Ecc,Ev,0.085,Ff,Ff,0,Ff,Gg,00180,0 Ab,51.83,3,Cy,Dp,Eff,Eff,1.5,Ff,Ff,0,Ff,Gg,00180,4 Ab,22.92,3.165,Cy,Dp,Ec,Ev,0.165,Ff,Ff,0,Ff,Gg,00160,1058 Ab,21.83,1.54,Cu,Dg,Ek,Ev,0.085,Ff,Ff,0,Ft,Gg,00356,0 Ab,25.25,1,Cu,Dg,Eaa,Ev,0.5,Ff,Ff,0,Ff,Gg,00200,0 Ab,58.58,2.71,Cu,Dg,Ec,Ev,2.415,Ff,Ff,0,Ft,Gg,00320,0 Ab,19.00,0,Cy,Dp,Eff,Eff,0,Ff,Ft,04,Ff,Gg,00045,1 Ab,19.58,0.585,Cu,Dg,Eff,Eff,0,Ff,Ft,03,Ff,Gg,00350,769 Aa,53.33,0.165,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ft,Gs,00062,27 Aa,27.17,1.25,Cu,Dg,Eff,Eff,0,Ff,Ft,01,Ff,Gg,00092,300 Ab,25.92,0.875,Cu,Dg,Ek,Ev,0.375,Ff,Ft,02,Ft,Gg,00174,3 Ab,23.08,0,Cu,Dg,Ek,Ev,1,Ff,Ft,11,Ff,Gs,00000,0 Ab,39.58,5,Cu,Dg,Eff,Eff,0,Ff,Ft,02,Ff,Gg,00017,1 Ab,30.58,2.71,Cy,Dp,Em,Ev,0.125,Ff,Ff,0,Ft,Gs,00080,0 Ab,17.25,3,Cu,Dg,Ek,Ev,0.04,Ff,Ff,0,Ft,Gg,00160,40 Aa,17.67,0,Cy,Dp,Ej,Eff,0,Ff,Ff,0,Ff,Gg,00086,0 Aa,?,11.25,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gg,?,5200 Ab,16.50,0.125,Cu,Dg,Ec,Ev,0.165,Ff,Ff,0,Ff,Gg,00132,0 Aa,27.33,1.665,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00340,1 Ab,31.25,1.125,Cu,Dg,Eff,Eff,0,Ff,Ft,01,Ff,Gg,00096,19 Ab,20.00,7,Cu,Dg,Ec,Ev,0.5,Ff,Ff,0,Ff,Gg,00000,0 Ab,?,3,Cy,Dp,Ei,Ebb,7,Ff,Ff,0,Ff,Gg,00000,1 Ab,39.50,1.625,Cu,Dg,Ec,Ev,1.5,Ff,Ff,0,Ff,Gg,00000,316 Ab,36.50,4.25,Cu,Dg,Eq,Ev,3.5,Ff,Ff,0,Ff,Gg,00454,50 ?,29.75,0.665,Cu,Dg,Ew,Ev,0.25,Ff,Ff,0,Ft,Gg,00300,0 Ab,52.42,1.5,Cu,Dg,Ed,Ev,3.75,Ff,Ff,0,Ft,Gg,00000,350 Ab,36.17,18.125,Cu,Dg,Ew,Ev,0.085,Ff,Ff,0,Ff,Gg,00320,3552 Ab,34.58,0,?,?,?,?,0,Ff,Ff,0,Ff,Gp,?,0 Ab,29.67,0.75,Cy,Dp,Ec,Ev,0.04,Ff,Ff,0,Ff,Gg,00240,0 Ab,36.17,5.5,Cu,Dg,Ei,Ebb,5,Ff,Ff,0,Ff,Gg,00210,687 Ab,25.67,0.29,Cy,Dp,Ec,Ev,1.5,Ff,Ff,0,Ft,Gg,00160,0 Aa,24.50,2.415,Cy,Dp,Ec,Ev,0,Ff,Ff,0,Ff,Gg,00120,0 Ab,24.08,0.875,Cu,Dg,Em,Ev,0.085,Ff,Ft,04,Ff,Gg,00254,1950 Ab,21.92,0.5,Cu,Dg,Ec,Ev,0.125,Ff,Ff,0,Ff,Gg,00360,0 Aa,36.58,0.29,Cu,Dg,Eff,Eff,0,Ff,Ft,10,Ff,Gg,00200,18 Aa,23.00,1.835,Cu,Dg,Ej,Ej,0,Ff,Ft,01,Ff,Gg,00200,53 Aa,27.58,3,Cu,Dg,Em,Ev,2.79,Ff,Ft,01,Ft,Gg,00280,10 Ab,31.08,3.085,Cu,Dg,Ec,Ev,2.5,Ff,Ft,02,Ft,Gg,00160,41 Aa,30.42,1.375,Cu,Dg,Ew,Eh,0.04,Ff,Ft,03,Ff,Gg,00000,33 Ab,22.08,2.335,Cu,Dg,Ek,Ev,0.75,Ff,Ff,0,Ff,Gg,00180,0 Ab,16.33,4.085,Cu,Dg,Ei,Eh,0.415,Ff,Ff,0,Ft,Gg,00120,0 Aa,21.92,11.665,Cu,Dg,Ek,Eh,0.085,Ff,Ff,0,Ff,Gg,00320,5 Ab,21.08,4.125,Cy,Dp,Ei,Eh,0.04,Ff,Ff,0,Ff,Gg,00140,100 Ab,17.42,6.5,Cu,Dg,Ei,Ev,0.125,Ff,Ff,0,Ff,Gg,00060,100 Ab,19.17,4,Cy,Dp,Ei,Ev,1,Ff,Ff,0,Ft,Gg,00360,1000 Ab,20.67,0.415,Cu,Dg,Ec,Ev,0.125,Ff,Ff,0,Ff,Gg,00000,44 Ab,26.75,2,Cu,Dg,Ed,Ev,0.75,Ff,Ff,0,Ft,Gg,00080,0 Ab,23.58,0.835,Cu,Dg,Ei,Eh,0.085,Ff,Ff,0,Ft,Gg,00220,5 Ab,39.17,2.5,Cy,Dp,Ei,Eh,10,Ff,Ff,0,Ft,Gs,00200,0 Ab,22.75,11.5,Cu,Dg,Ei,Ev,0.415,Ff,Ff,0,Ff,Gg,00000,0 ?,26.50,2.71,Cy,Dp,?,?,0.085,Ff,Ff,0,Ff,Gs,00080,0 Aa,16.92,0.5,Cu,Dg,Ei,Ev,0.165,Ff,Ft,06,Ft,Gg,00240,35 Ab,23.50,3.165,Cy,Dp,Ek,Ev,0.415,Ff,Ft,01,Ft,Gg,00280,80 Aa,17.33,9.5,Cu,Dg,Eaa,Ev,1.75,Ff,Ft,10,Ft,Gg,00000,10 Ab,23.75,0.415,Cy,Dp,Ec,Ev,0.04,Ff,Ft,02,Ff,Gg,00128,6 Ab,34.67,1.08,Cu,Dg,Em,Ev,1.165,Ff,Ff,0,Ff,Gs,00028,0 Ab,74.83,19,Cy,Dp,Eff,Eff,0.04,Ff,Ft,02,Ff,Gg,00000,351 Ab,28.17,0.125,Cy,Dp,Ek,Ev,0.085,Ff,Ff,0,Ff,Gg,00216,2100 Ab,24.50,13.335,Cy,Dp,Eaa,Ev,0.04,Ff,Ff,0,Ft,Gg,00120,475 Ab,18.83,3.54,Cy,Dp,Eff,Eff,0,Ff,Ff,0,Ft,Gg,00180,1 ?,45.33,1,Cu,Dg,Eq,Ev,0.125,Ff,Ff,0,Ft,Gg,00263,0 @. is_+ Aa,47.25,0.75,Cu,Dg,Eq,Eh,2.75,Ft,Ft,01,Ff,Gg,00333,892:+ Ab,24.17,0.875,Cu,Dg,Eq,Ev,4.625,Ft,Ft,02,Ft,Gg,00520,2000:+ Ab,39.25,9.5,Cu,Dg,Em,Ev,6.5,Ft,Ft,14,Ff,Gg,00240,4607:+ Aa,20.50,11.835,Cu,Dg,Ec,Eh,6,Ft,Ff,0,Ff,Gg,00340,0:+ Aa,18.83,4.415,Cy,Dp,Ec,Eh,3,Ft,Ff,0,Ff,Gg,00240,0:+ Ab,19.17,9.5,Cu,Dg,Ew,Ev,1.5,Ft,Ff,0,Ff,Gg,00120,2206:+ Aa,25.00,0.875,Cu,Dg,Ex,Eh,1.04,Ft,Ff,0,Ft,Gg,00160,5860:+ Ab,20.17,9.25,Cu,Dg,Ec,Ev,1.665,Ft,Ft,03,Ft,Gg,00040,28:+ Ab,25.75,0.5,Cu,Dg,Ec,Ev,1.46,Ft,Ft,05,Ft,Gg,00312,0:+ Ab,20.42,7,Cu,Dg,Ec,Ev,1.625,Ft,Ft,03,Ff,Gg,00200,1391:+ Ab,?,4,Cu,Dg,Ex,Ev,5,Ft,Ft,03,Ft,Gg,00290,2279:+ Ab,39.00,5,Cu,Dg,Ecc,Ev,3.5,Ft,Ft,10,Ft,Gg,00000,0:+ Aa,64.08,0.165,Cu,Dg,Eff,Eff,0,Ft,Ft,01,Ff,Gg,00232,100:+ Ab,28.25,5.125,Cu,Dg,Ex,Ev,4.75,Ft,Ft,02,Ff,Gg,00420,7:+ Aa,28.75,3.75,Cu,Dg,Ec,Ev,1.085,Ft,Ft,01,Ft,Gg,00371,0:+ Ab,31.33,19.5,Cu,Dg,Ec,Ev,7,Ft,Ft,16,Ff,Gg,00000,5000:+ Aa,18.92,9,Cu,Dg,Eaa,Ev,0.75,Ft,Ft,02,Ff,Gg,00088,591:+ Aa,24.75,3,Cu,Dg,Eq,Eh,1.835,Ft,Ft,19,Ff,Gg,00000,500:+ Aa,30.67,12,Cu,Dg,Ec,Ev,2,Ft,Ft,01,Ff,Gg,00220,19:+ Ab,21.00,4.79,Cy,Dp,Ew,Ev,2.25,Ft,Ft,01,Ft,Gg,00080,300:+ Ab,13.75,4,Cy,Dp,Ew,Ev,1.75,Ft,Ft,02,Ft,Gg,00120,1000:+ Aa,46.00,4,Cu,Dg,Ej,Ej,0,Ft,Ff,0,Ff,Gg,00100,960:+ Aa,44.33,0,Cu,Dg,Ec,Ev,2.5,Ft,Ff,0,Ff,Gg,00000,0:+ Ab,20.25,9.96,Cu,Dg,Ee,Edd,0,Ft,Ff,0,Ff,Gg,00000,0:+ Ab,22.67,2.54,Cy,Dp,Ec,Eh,2.585,Ft,Ff,0,Ff,Gg,00000,0:+ Ab,?,10.5,Cu,Dg,Ex,Ev,6.5,Ft,Ff,0,Ff,Gg,00000,0:+ Aa,60.92,5,Cu,Dg,Eaa,Ev,4,Ft,Ft,04,Ff,Gg,00000,99:+ Ab,16.08,0.75,Cu,Dg,Ec,Ev,1.75,Ft,Ft,05,Ft,Gg,00352,690:+ Aa,28.17,0.375,Cu,Dg,Eq,Ev,0.585,Ft,Ft,04,Ff,Gg,00080,0:+ Ab,39.17,1.71,Cu,Dg,Ex,Ev,0.125,Ft,Ft,05,Ft,Gg,00480,0:+ ?,20.42,7.5,Cu,Dg,Ek,Ev,1.5,Ft,Ft,01,Ff,Gg,00160,234:+ Aa,30.00,5.29,Cu,Dg,Ee,Edd,2.25,Ft,Ft,05,Ft,Gg,00099,500:+ Ab,22.83,3,Cu,Dg,Em,Ev,1.29,Ft,Ft,01,Ff,Gg,00260,800:+ Aa,22.50,8.5,Cu,Dg,Eq,Ev,1.75,Ft,Ft,10,Ff,Gg,00080,990:- Aa,28.58,1.665,Cu,Dg,Eq,Ev,2.415,Ft,Ff,0,Ft,Gg,00440,0:- Ab,45.17,1.5,Cu,Dg,Ec,Ev,2.5,Ft,Ff,0,Ft,Gg,00140,0:- Ab,41.58,1.75,Cu,Dg,Ek,Ev,0.21,Ft,Ff,0,Ff,Gg,00160,0:- Aa,57.08,0.335,Cu,Dg,Ei,Ebb,1,Ft,Ff,0,Ft,Gg,00252,2197:- Aa,55.75,7.08,Cu,Dg,Ek,Eh,6.75,Ft,Ft,03,Ft,Gg,00100,50:- Ab,43.25,25.21,Cu,Dg,Eq,Eh,0.21,Ft,Ft,01,Ff,Gg,00760,90:- Aa,25.33,2.085,Cu,Dg,Ec,Eh,2.75,Ft,Ff,0,Ft,Gg,00360,1:- Aa,24.58,0.67,Cu,Dg,Eaa,Eh,1.75,Ft,Ff,0,Ff,Gg,00400,0:- Ab,43.17,2.25,Cu,Dg,Ei,Ebb,0.75,Ft,Ff,0,Ff,Gg,00560,0:- Ab,40.92,0.835,Cu,Dg,Eff,Eff,0,Ft,Ff,0,Ff,Gg,00130,1:- Ab,31.83,2.5,Cu,Dg,Eaa,Ev,7.5,Ft,Ff,0,Ft,Gg,00523,0:- Aa,33.92,1.585,Cy,Dp,Eff,Eff,0,Ft,Ff,0,Ff,Gg,00320,0:- Aa,24.92,1.25,Cu,Dg,Eff,Eff,0,Ft,Ff,0,Ff,Gg,00080,0:- Ab,35.25,3.165,Cu,Dg,Ex,Eh,3.75,Ft,Ff,0,Ft,Gg,00680,0:- Ab,34.25,1.75,Cu,Dg,Ew,Ebb,0.25,Ft,Ff,0,Ft,Gg,00163,0:- Ab,80.25,5.5,Cu,Dg,?,?,0.54,Ft,Ff,0,Ff,Gg,00000,340:- Ab,19.42,1.5,Cy,Dp,Ecc,Ev,2,Ft,Ff,0,Ft,Gg,00100,20:- Ab,42.75,3,Cu,Dg,Ei,Ebb,1,Ft,Ff,0,Ff,Gg,00000,200:- Ab,19.67,10,Cy,Dp,Ek,Eh,0.835,Ft,Ff,0,Ft,Gg,00140,0:- Ab,36.33,3.79,Cu,Dg,Ew,Ev,1.165,Ft,Ff,0,Ft,Gg,00200,0:- Ab,30.08,1.04,Cy,Dp,Ei,Ebb,0.5,Ft,Ft,10,Ft,Gg,00132,28:- Ab,44.25,11,Cy,Dp,Ed,Ev,1.5,Ft,Ff,0,Ff,Gs,00000,0:- Ab,23.58,0.46,Cy,Dp,Ew,Ev,2.625,Ft,Ft,06,Ft,Gg,00208,347:- Ab,23.92,1.5,Cu,Dg,Ed,Eh,1.875,Ft,Ft,06,Ff,Gg,00200,327:+ Ab,33.17,1,Cu,Dg,Ex,Ev,0.75,Ft,Ft,07,Ft,Gg,00340,4071:+ Ab,48.33,12,Cu,Dg,Em,Ev,16,Ft,Ff,0,Ff,Gs,00110,0:+ Ab,76.75,22.29,Cu,Dg,Ee,Ez,12.75,Ft,Ft,01,Ft,Gg,00000,109:+ Ab,51.33,10,Cu,Dg,Ei,Ebb,0,Ft,Ft,11,Ff,Gg,00000,1249:+ Ab,34.75,15,Cu,Dg,Er,En,5.375,Ft,Ft,09,Ft,Gg,00000,134:+ Ab,38.58,3.335,Cu,Dg,Ew,Ev,4,Ft,Ft,14,Ff,Gg,00383,1344:+ Aa,22.42,11.25,Cy,Dp,Ex,Eh,0.75,Ft,Ft,04,Ff,Gg,00000,321:+ Ab,41.92,0.42,Cu,Dg,Ec,Eh,0.21,Ft,Ft,06,Ff,Gg,00220,948:+ Ab,29.58,4.5,Cu,Dg,Ew,Ev,7.5,Ft,Ft,02,Ft,Gg,00330,0:+ Aa,32.17,1.46,Cu,Dg,Ew,Ev,1.085,Ft,Ft,16,Ff,Gg,00120,2079:+ Ab,51.42,0.04,Cu,Dg,Ex,Eh,0.04,Ft,Ff,0,Ff,Gg,00000,3000:+ Aa,22.83,2.29,Cu,Dg,Eq,Eh,2.29,Ft,Ft,07,Ft,Gg,00140,2384:+ Aa,25.00,12.33,Cu,Dg,Ecc,Eh,3.5,Ft,Ft,06,Ff,Gg,00400,458:+ Ab,26.75,1.125,Cu,Dg,Ex,Eh,1.25,Ft,Ff,0,Ff,Gg,00000,5298:+ Ab,23.33,1.5,Cu,Dg,Ec,Eh,1.415,Ft,Ff,0,Ff,Gg,00422,200:+ Ab,24.42,12.335,Cu,Dg,Eq,Eh,1.585,Ft,Ff,0,Ft,Gg,00120,0:+ Ab,42.17,5.04,Cu,Dg,Eq,Eh,12.75,Ft,Ff,0,Ft,Gg,00092,0:+ Aa,20.83,3,Cu,Dg,Eaa,Ev,0.04,Ft,Ff,0,Ff,Gg,00100,0:+ Ab,23.08,11.5,Cu,Dg,Ew,Eh,2.125,Ft,Ft,11,Ft,Gg,00290,284:+ Aa,25.17,2.875,Cu,Dg,Ex,Eh,0.875,Ft,Ff,0,Ff,Gg,00360,0:+ Ab,43.08,0.375,Cy,Dp,Ec,Ev,0.375,Ft,Ft,08,Ft,Gg,00300,162:+ Aa,35.75,0.915,Cu,Dg,Eaa,Ev,0.75,Ft,Ft,04,Ff,Gg,00000,1583:+ Ab,59.50,2.75,Cu,Dg,Ew,Ev,1.75,Ft,Ft,05,Ft,Gg,00060,58:+ Ab,21.00,3,Cy,Dp,Ed,Ev,1.085,Ft,Ft,08,Ft,Gg,00160,1:+ Ab,21.92,0.54,Cy,Dp,Ex,Ev,0.04,Ft,Ft,01,Ft,Gg,00840,59:+ Aa,65.17,14,Cu,Dg,Eff,Eff,0,Ft,Ft,11,Ft,Gg,00000,1400:+ Aa,20.33,10,Cu,Dg,Ec,Eh,1,Ft,Ft,04,Ff,Gg,00050,1465:+ Ab,32.25,0.165,Cy,Dp,Ec,Eh,3.25,Ft,Ft,01,Ft,Gg,00432,8000:+ Ab,30.17,0.5,Cu,Dg,Ec,Ev,1.75,Ft,Ft,11,Ff,Gg,00032,540:+ Ab,25.17,6,Cu,Dg,Ec,Ev,1,Ft,Ft,03,Ff,Gg,00000,0:+ Ab,39.17,1.625,Cu,Dg,Ec,Ev,1.5,Ft,Ft,10,Ff,Gg,00186,4700:+ Ab,39.08,6,Cu,Dg,Em,Ev,1.29,Ft,Ft,05,Ft,Gg,00108,1097:+ Ab,31.67,0.83,Cu,Dg,Ex,Ev,1.335,Ft,Ft,08,Ft,Gg,00303,3290:+ Ab,41.00,0.04,Cu,Dg,Ee,Ev,0.04,Ff,Ft,01,Ff,Gs,00560,0:+ Ab,48.50,4.25,Cu,Dg,Em,Ev,0.125,Ft,Ff,0,Ft,Gg,00225,0:+ Ab,32.67,9,Cy,Dp,Ew,Eh,5.25,Ft,Ff,0,Ft,Gg,00154,0:+ Aa,28.08,15,Cy,Dp,Ee,Ez,0,Ft,Ff,0,Ff,Gg,00000,13212:+ Ab,73.42,17.75,Cu,Dg,Eff,Eff,0,Ft,Ff,0,Ft,Gg,00000,0:+ Ab,64.08,20,Cu,Dg,Ex,Eh,17.5,Ft,Ft,09,Ft,Gg,00000,1000:+ Ab,51.58,15,Cu,Dg,Ec,Ev,8.5,Ft,Ft,09,Ff,Gg,00000,0:+ Ab,26.67,1.75,Cy,Dp,Ec,Ev,1,Ft,Ft,05,Ft,Gg,00160,5777:+ Ab,25.33,0.58,Cu,Dg,Ec,Ev,0.29,Ft,Ft,07,Ft,Gg,00096,5124:+ Ab,30.17,6.5,Cu,Dg,Ecc,Ev,3.125,Ft,Ft,08,Ff,Gg,00330,1200:+ Ab,27.00,0.75,Cu,Dg,Ec,Eh,4.25,Ft,Ft,03,Ft,Gg,00312,150:+ Ab,23.17,0,?,?,?,?,0,Ff,Ff,0,Ff,Gp,?,0:+ Ab,34.17,5.25,Cu,Dg,Ew,Ev,0.085,Ff,Ff,0,Ft,Gg,00290,6:+ Ab,38.67,0.21,Cu,Dg,Ek,Ev,0.085,Ft,Ff,0,Ft,Gg,00280,0:+ Ab,25.75,0.75,Cu,Dg,Ec,Ebb,0.25,Ft,Ff,0,Ff,Gg,00349,23:+ Aa,46.08,3,Cu,Dg,Ec,Ev,2.375,Ft,Ft,08,Ft,Gg,00396,4159:+ Aa,21.50,6,Cu,Dg,Eaa,Ev,2.5,Ft,Ft,03,Ff,Gg,00080,918:+ ?,20.08,0.125,Cu,Dg,Eq,Ev,1,Ff,Ft,01,Ff,Gg,00240,768:+ Ab,20.50,2.415,Cu,Dg,Ec,Ev,2,Ft,Ft,11,Ft,Gg,00200,3000:+ Aa,29.50,0.46,Cu,Dg,Ek,Ev,0.54,Ft,Ft,04,Ff,Gg,00380,500:+ ?,42.25,1.75,Cy,Dp,?,?,0,Ff,Ff,0,Ft,Gg,00150,1:- Ab,29.83,1.25,Cy,Dp,Ek,Ev,0.25,Ff,Ff,0,Ff,Gg,00224,0:- Ab,20.08,0.25,Cu,Dg,Eq,Ev,0.125,Ff,Ff,0,Ff,Gg,00200,0:- Ab,23.42,0.585,Cu,Dg,Ec,Eh,0.085,Ft,Ff,0,Ff,Gg,00180,0:- Aa,29.58,1.75,Cy,Dp,Ek,Ev,1.25,Ff,Ff,0,Ft,Gg,00280,0:- Ab,16.17,0.04,Cu,Dg,Ec,Ev,0.04,Ff,Ff,0,Ff,Gg,00000,0:+ Ab,32.33,3.5,Cu,Dg,Ek,Ev,0.5,Ff,Ff,0,Ft,Gg,00232,0:- Ab,?,0.04,Cy,Dp,Ed,Ev,4.25,Ff,Ff,0,Ft,Gg,00460,0:- Ab,47.83,4.165,Cu,Dg,Ex,Ebb,0.085,Ff,Ff,0,Ft,Gg,00520,0:- Ab,20.00,1.25,Cy,Dp,Ek,Ev,0.125,Ff,Ff,0,Ff,Gg,00140,4:- Ab,27.58,3.25,Cy,Dp,Eq,Eh,5.085,Ff,Ft,02,Ft,Gg,00369,1:- Ab,22.00,0.79,Cu,Dg,Ew,Ev,0.29,Ff,Ft,01,Ff,Gg,00420,283:- Ab,19.33,10.915,Cu,Dg,Ec,Ebb,0.585,Ff,Ft,02,Ft,Gg,00200,7:- Aa,38.33,4.415,Cu,Dg,Ec,Ev,0.125,Ff,Ff,0,Ff,Gg,00160,0:- Ab,29.42,1.25,Cu,Dg,Ec,Eh,0.25,Ff,Ft,02,Ft,Gg,00400,108:- Ab,22.67,0.75,Cu,Dg,Ei,Ev,1.585,Ff,Ft,01,Ft,Gg,00400,9:- Ab,32.25,14,Cy,Dp,Eff,Eff,0,Ff,Ft,02,Ff,Gg,00160,1:- Ab,29.58,4.75,Cu,Dg,Em,Ev,2,Ff,Ft,01,Ft,Gg,00460,68:- Ab,18.42,10.415,Cy,Dp,Eaa,Ev,0.125,Ft,Ff,0,Ff,Gg,00120,375:- Ab,22.17,2.25,Cu,Dg,Ei,Ev,0.125,Ff,Ff,0,Ff,Gg,00160,10:- Ab,22.67,0.165,Cu,Dg,Ec,Ej,2.25,Ff,Ff,0,Ft,Gs,00000,0:+ Aa,25.58,0,?,?,?,?,0,Ff,Ff,0,Ff,Gp,?,0:+ Ab,18.83,0,Cu,Dg,Eq,Ev,0.665,Ff,Ff,0,Ff,Gg,00160,1:- Ab,21.58,0.79,Cy,Dp,Ecc,Ev,0.665,Ff,Ff,0,Ff,Gg,00160,0:- Ab,23.75,12,Cu,Dg,Ec,Ev,2.085,Ff,Ff,0,Ff,Gs,00080,0:- Ab,22.00,7.835,Cy,Dp,Ei,Ebb,0.165,Ff,Ff,0,Ft,Gg,?,0:- Ab,36.08,2.54,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00000,1000:- Ab,29.25,13,Cu,Dg,Ed,Eh,0.5,Ff,Ff,0,Ff,Gg,00228,0:- Aa,19.58,0.665,Cu,Dg,Ew,Ev,1.665,Ff,Ff,0,Ff,Gg,00220,5:- Aa,22.92,1.25,Cu,Dg,Eq,Ev,0.25,Ff,Ff,0,Ft,Gg,00120,809:- Aa,27.25,0.29,Cu,Dg,Em,Eh,0.125,Ff,Ft,01,Ft,Gg,00272,108:- Aa,38.75,1.5,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00076,0:- Ab,32.42,2.165,Cy,Dp,Ek,Eff,0,Ff,Ff,0,Ff,Gg,00120,0:- Aa,23.75,0.71,Cu,Dg,Ew,Ev,0.25,Ff,Ft,01,Ft,Gg,00240,4:- Ab,18.17,2.46,Cu,Dg,Ec,En,0.96,Ff,Ft,02,Ft,Gg,00160,587:- Ab,40.92,0.5,Cy,Dp,Em,Ev,0.5,Ff,Ff,0,Ft,Gg,00130,0:- Ab,19.50,9.585,Cu,Dg,Eaa,Ev,0.79,Ff,Ff,0,Ff,Gg,00080,350:- Ab,28.58,3.625,Cu,Dg,Eaa,Ev,0.25,Ff,Ff,0,Ft,Gg,00100,0:- Ab,35.58,0.75,Cu,Dg,Ek,Ev,1.5,Ff,Ff,0,Ft,Gg,00231,0:- Ab,34.17,2.75,Cu,Dg,Ei,Ebb,2.5,Ff,Ff,0,Ft,Gg,00232,200:- ?,33.17,2.25,Cy,Dp,Ecc,Ev,3.5,Ff,Ff,0,Ft,Gg,00200,141:- Ab,31.58,0.75,Cy,Dp,Eaa,Ev,3.5,Ff,Ff,0,Ft,Gg,00320,0:- Aa,52.50,7,Cu,Dg,Eaa,Eh,3,Ff,Ff,0,Ff,Gg,00000,0:- Ab,36.17,0.42,Cy,Dp,Ew,Ev,0.29,Ff,Ff,0,Ft,Gg,00309,2:- Ab,37.33,2.665,Cu,Dg,Ecc,Ev,0.165,Ff,Ff,0,Ft,Gg,00000,501:- Aa,20.83,8.5,Cu,Dg,Ec,Ev,0.165,Ff,Ff,0,Ff,Gg,00000,351:- Ab,24.08,9,Cu,Dg,Eaa,Ev,0.25,Ff,Ff,0,Ft,Gg,00000,0:- Ab,25.58,0.335,Cu,Dg,Ek,Eh,3.5,Ff,Ff,0,Ft,Gg,00340,0:- Aa,35.17,3.75,Cu,Dg,Eff,Eff,0,Ff,Ft,06,Ff,Gg,00000,200:- Ab,48.08,3.75,Cu,Dg,Ei,Ebb,1,Ff,Ff,0,Ff,Gg,00100,2:- Aa,15.83,7.625,Cu,Dg,Eq,Ev,0.125,Ff,Ft,01,Ft,Gg,00000,160:- Aa,22.50,0.415,Cu,Dg,Ei,Ev,0.335,Ff,Ff,0,Ft,Gs,00144,0:- Ab,21.50,11.5,Cu,Dg,Ei,Ev,0.5,Ft,Ff,0,Ft,Gg,00100,68:- Aa,23.58,0.83,Cu,Dg,Eq,Ev,0.415,Ff,Ft,01,Ft,Gg,00200,11:- Aa,21.08,5,Cy,Dp,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00000,0:- Ab,25.67,3.25,Cu,Dg,Ec,Eh,2.29,Ff,Ft,01,Ft,Gg,00416,21:- Aa,38.92,1.665,Cu,Dg,Eaa,Ev,0.25,Ff,Ff,0,Ff,Gg,00000,390:- Aa,15.75,0.375,Cu,Dg,Ec,Ev,1,Ff,Ff,0,Ff,Gg,00120,18:- Aa,28.58,3.75,Cu,Dg,Ec,Ev,0.25,Ff,Ft,01,Ft,Gg,00040,154:- Ab,22.25,9,Cu,Dg,Eaa,Ev,0.085,Ff,Ff,0,Ff,Gg,00000,0:- Ab,29.83,3.5,Cu,Dg,Ec,Ev,0.165,Ff,Ff,0,Ff,Gg,00216,0:- Aa,23.50,1.5,Cu,Dg,Ew,Ev,0.875,Ff,Ff,0,Ft,Gg,00160,0:- Ab,32.08,4,Cy,Dp,Ecc,Ev,1.5,Ff,Ff,0,Ft,Gg,00120,0:- Ab,31.08,1.5,Cy,Dp,Ew,Ev,0.04,Ff,Ff,0,Ff,Gs,00160,0:- Ab,31.83,0.04,Cy,Dp,Em,Ev,0.04,Ff,Ff,0,Ff,Gg,00000,0:- Aa,21.75,11.75,Cu,Dg,Ec,Ev,0.25,Ff,Ff,0,Ft,Gg,00180,0:- Aa,17.92,0.54,Cu,Dg,Ec,Ev,1.75,Ff,Ft,01,Ft,Gg,00080,5:- Ab,30.33,0.5,Cu,Dg,Ed,Eh,0.085,Ff,Ff,0,Ft,Gs,00252,0:- Ab,51.83,2.04,Cy,Dp,Eff,Eff,1.5,Ff,Ff,0,Ff,Gg,00120,1:- Ab,47.17,5.835,Cu,Dg,Ew,Ev,5.5,Ff,Ff,0,Ff,Gg,00465,150:- Ab,25.83,12.835,Cu,Dg,Ecc,Ev,0.5,Ff,Ff,0,Ff,Gg,00000,2:- Aa,50.25,0.835,Cu,Dg,Eaa,Ev,0.5,Ff,Ff,0,Ft,Gg,00240,117:- ?,29.50,2,Cy,Dp,Ee,Eh,2,Ff,Ff,0,Ff,Gg,00256,17:- Aa,37.33,2.5,Cu,Dg,Ei,Eh,0.21,Ff,Ff,0,Ff,Gg,00260,246:- Aa,41.58,1.04,Cu,Dg,Eaa,Ev,0.665,Ff,Ff,0,Ff,Gg,00240,237:- Aa,30.58,10.665,Cu,Dg,Eq,Eh,0.085,Ff,Ft,12,Ft,Gg,00129,3:- Ab,19.42,7.25,Cu,Dg,Em,Ev,0.04,Ff,Ft,01,Ff,Gg,00100,1:- Aa,17.92,10.21,Cu,Dg,Eff,Eff,0,Ff,Ff,0,Ff,Gg,00000,50:- Aa,20.08,1.25,Cu,Dg,Ec,Ev,0,Ff,Ff,0,Ff,Gg,00000,0:- Ab,19.50,0.29,Cu,Dg,Ek,Ev,0.29,Ff,Ff,0,Ff,Gg,00280,364:- Ab,27.83,1,Cy,Dp,Ed,Eh,3,Ff,Ff,0,Ff,Gg,00176,537:- Ab,17.08,3.29,Cu,Dg,Ei,Ev,0.335,Ff,Ff,0,Ft,Gg,00140,2:- Ab,36.42,0.75,Cy,Dp,Ed,Ev,0.585,Ff,Ff,0,Ff,Gg,00240,3:- Ab,40.58,3.29,Cu,Dg,Em,Ev,3.5,Ff,Ff,0,Ft,Gs,00400,0:- Ab,21.08,10.085,Cy,Dp,Ee,Eh,1.25,Ff,Ff,0,Ff,Gg,00260,0:- Aa,22.67,0.75,Cu,Dg,Ec,Ev,2,Ff,Ft,02,Ft,Gg,00200,394:- Aa,25.25,13.5,Cy,Dp,Eff,Eff,2,Ff,Ft,01,Ft,Gg,00200,1:- Ab,17.92,0.205,Cu,Dg,Eaa,Ev,0.04,Ff,Ff,0,Ff,Gg,00280,750:- Ab,35.00,3.375,Cu,Dg,Ec,Eh,8.29,Ff,Ff,0,Ft,Gg,00000,0:- @. @//E*O*F crx.d// chmod u=rw,g=,o= crx.d echo x - crx.data sed 's/^@//' > "crx.data" <<'@//E*O*F crx.data//' b,30.83,0,u,g,w,v,1.25,t,t,01,f,g,00202,0,+ a,58.67,4.46,u,g,q,h,3.04,t,t,06,f,g,00043,560,+ a,24.50,0.5,u,g,q,h,1.5,t,f,0,f,g,00280,824,+ b,27.83,1.54,u,g,w,v,3.75,t,t,05,t,g,00100,3,+ b,20.17,5.625,u,g,w,v,1.71,t,f,0,f,s,00120,0,+ b,32.08,4,u,g,m,v,2.5,t,f,0,t,g,00360,0,+ b,33.17,1.04,u,g,r,h,6.5,t,f,0,t,g,00164,31285,+ a,22.92,11.585,u,g,cc,v,0.04,t,f,0,f,g,00080,1349,+ b,54.42,0.5,y,p,k,h,3.96,t,f,0,f,g,00180,314,+ b,42.50,4.915,y,p,w,v,3.165,t,f,0,t,g,00052,1442,+ b,22.08,0.83,u,g,c,h,2.165,f,f,0,t,g,00128,0,+ b,29.92,1.835,u,g,c,h,4.335,t,f,0,f,g,00260,200,+ a,38.25,6,u,g,k,v,1,t,f,0,t,g,00000,0,+ b,48.08,6.04,u,g,k,v,0.04,f,f,0,f,g,00000,2690,+ a,45.83,10.5,u,g,q,v,5,t,t,07,t,g,00000,0,+ b,36.67,4.415,y,p,k,v,0.25,t,t,10,t,g,00320,0,+ b,28.25,0.875,u,g,m,v,0.96,t,t,03,t,g,00396,0,+ a,23.25,5.875,u,g,q,v,3.17,t,t,10,f,g,00120,245,+ b,21.83,0.25,u,g,d,h,0.665,t,f,0,t,g,00000,0,+ a,19.17,8.585,u,g,cc,h,0.75,t,t,07,f,g,00096,0,+ b,25.00,11.25,u,g,c,v,2.5,t,t,17,f,g,00200,1208,+ b,23.25,1,u,g,c,v,0.835,t,f,0,f,s,00300,0,+ a,47.75,8,u,g,c,v,7.875,t,t,06,t,g,00000,1260,+ a,27.42,14.5,u,g,x,h,3.085,t,t,01,f,g,00120,11,+ a,41.17,6.5,u,g,q,v,0.5,t,t,03,t,g,00145,0,+ a,15.83,0.585,u,g,c,h,1.5,t,t,02,f,g,00100,0,+ a,47.00,13,u,g,i,bb,5.165,t,t,09,t,g,00000,0,+ b,56.58,18.5,u,g,d,bb,15,t,t,17,t,g,00000,0,+ b,57.42,8.5,u,g,e,h,7,t,t,03,f,g,00000,0,+ b,42.08,1.04,u,g,w,v,5,t,t,06,t,g,00500,10000,+ b,29.25,14.79,u,g,aa,v,5.04,t,t,05,t,g,00168,0,+ b,42.00,9.79,u,g,x,h,7.96,t,t,08,f,g,00000,0,+ b,49.50,7.585,u,g,i,bb,7.585,t,t,15,t,g,00000,5000,+ a,36.75,5.125,u,g,e,v,5,t,f,0,t,g,00000,4000,+ a,22.58,10.75,u,g,q,v,0.415,t,t,05,t,g,00000,560,+ b,27.83,1.5,u,g,w,v,2,t,t,11,t,g,00434,35,+ b,27.25,1.585,u,g,cc,h,1.835,t,t,12,t,g,00583,713,+ a,23.00,11.75,u,g,x,h,0.5,t,t,02,t,g,00300,551,+ b,27.75,0.585,y,p,cc,v,0.25,t,t,02,f,g,00260,500,+ b,54.58,9.415,u,g,ff,ff,14.415,t,t,11,t,g,00030,300,+ b,34.17,9.17,u,g,c,v,4.5,t,t,12,t,g,00000,221,+ b,28.92,15,u,g,c,h,5.335,t,t,11,f,g,00000,2283,+ b,29.67,1.415,u,g,w,h,0.75,t,t,01,f,g,00240,100,+ b,39.58,13.915,u,g,w,v,8.625,t,t,06,t,g,00070,0,+ b,56.42,28,y,p,c,v,28.5,t,t,40,f,g,00000,15,+ b,54.33,6.75,u,g,c,h,2.625,t,t,11,t,g,00000,284,+ a,41.00,2.04,y,p,q,h,0.125,t,t,23,t,g,00455,1236,+ b,31.92,4.46,u,g,cc,h,6.04,t,t,03,f,g,00311,300,+ b,41.50,1.54,u,g,i,bb,3.5,f,f,0,f,g,00216,0,+ b,23.92,0.665,u,g,c,v,0.165,f,f,0,f,g,00100,0,+ a,25.75,0.5,u,g,c,h,0.875,t,f,0,t,g,00491,0,+ b,26.00,1,u,g,q,v,1.75,t,f,0,t,g,00280,0,+ b,37.42,2.04,u,g,w,v,0.04,t,f,0,t,g,00400,5800,+ b,34.92,2.5,u,g,w,v,0,t,f,0,t,g,00239,200,+ b,34.25,3,u,g,cc,h,7.415,t,f,0,t,g,00000,0,+ b,23.33,11.625,y,p,w,v,0.835,t,f,0,t,g,00160,300,+ b,23.17,0,u,g,cc,v,0.085,t,f,0,f,g,00000,0,+ b,44.33,0.5,u,g,i,h,5,t,f,0,t,g,00320,0,+ b,35.17,4.5,u,g,x,h,5.75,f,f,0,t,s,00711,0,+ b,43.25,3,u,g,q,h,6,t,t,11,f,g,00080,0,+ b,56.75,12.25,u,g,m,v,1.25,t,t,04,t,g,00200,0,+ b,31.67,16.165,u,g,d,v,3,t,t,09,f,g,00250,730,+ a,23.42,0.79,y,p,q,v,1.5,t,t,02,t,g,00080,400,+ a,20.42,0.835,u,g,q,v,1.585,t,t,01,f,g,00000,0,+ b,26.67,4.25,u,g,cc,v,4.29,t,t,01,t,g,00120,0,+ b,34.17,1.54,u,g,cc,v,1.54,t,t,01,t,g,00520,50000,+ a,36.00,1,u,g,c,v,2,t,t,11,f,g,00000,456,+ b,25.50,0.375,u,g,m,v,0.25,t,t,03,f,g,00260,15108,+ b,19.42,6.5,u,g,w,h,1.46,t,t,07,f,g,00080,2954,+ b,35.17,25.125,u,g,x,h,1.625,t,t,01,t,g,00515,500,+ b,32.33,7.5,u,g,e,bb,1.585,t,f,0,t,s,00420,0,- b,34.83,4,u,g,d,bb,12.5,t,f,0,t,g,?,0,- a,38.58,5,u,g,cc,v,13.5,t,f,0,t,g,00980,0,- b,44.25,0.5,u,g,m,v,10.75,t,f,0,f,s,00400,0,- b,44.83,7,y,p,c,v,1.625,f,f,0,f,g,00160,2,- b,20.67,5.29,u,g,q,v,0.375,t,t,01,f,g,00160,0,- b,34.08,6.5,u,g,aa,v,0.125,t,f,0,t,g,00443,0,- a,19.17,0.585,y,p,aa,v,0.585,t,f,0,t,g,00160,0,- b,21.67,1.165,y,p,k,v,2.5,t,t,01,f,g,00180,20,- b,21.50,9.75,u,g,c,v,0.25,t,f,0,f,g,00140,0,- b,49.58,19,u,g,ff,ff,0,t,t,01,f,g,00094,0,- a,27.67,1.5,u,g,m,v,2,t,f,0,f,s,00368,0,- b,39.83,0.5,u,g,m,v,0.25,t,f,0,f,s,00288,0,- a,?,3.5,u,g,d,v,3,t,f,0,t,g,00300,0,- b,27.25,0.625,u,g,aa,v,0.455,t,f,0,t,g,00200,0,- b,37.17,4,u,g,c,bb,5,t,f,0,t,s,00280,0,- b,?,0.375,u,g,d,v,0.875,t,f,0,t,s,00928,0,- b,25.67,2.21,y,p,aa,v,4,t,f,0,f,g,00188,0,- b,34.00,4.5,u,g,aa,v,1,t,f,0,t,g,00240,0,- a,49.00,1.5,u,g,j,j,0,t,f,0,t,g,00100,27,- b,62.50,12.75,y,p,c,h,5,t,f,0,f,g,00112,0,- b,31.42,15.5,u,g,c,v,0.5,t,f,0,f,g,00120,0,- b,?,5,y,p,aa,v,8.5,t,f,0,f,g,00000,0,- b,52.33,1.375,y,p,c,h,9.46,t,f,0,t,g,00200,100,- b,28.75,1.5,y,p,c,v,1.5,t,f,0,t,g,00000,225,- a,28.58,3.54,u,g,i,bb,0.5,t,f,0,t,g,00171,0,- b,23.00,0.625,y,p,aa,v,0.125,t,f,0,f,g,00180,1,- b,?,0.5,u,g,c,bb,0.835,t,f,0,t,s,00320,0,- a,22.50,11,y,p,q,v,3,t,f,0,t,g,00268,0,- a,28.50,1,u,g,q,v,1,t,t,02,t,g,00167,500,- b,37.50,1.75,y,p,c,bb,0.25,t,f,0,t,g,00164,400,- b,35.25,16.5,y,p,c,v,4,t,f,0,f,g,00080,0,- b,18.67,5,u,g,q,v,0.375,t,t,02,f,g,00000,38,- b,25.00,12,u,g,k,v,2.25,t,t,02,t,g,00120,5,- b,27.83,4,y,p,i,h,5.75,t,t,02,t,g,00075,0,- b,54.83,15.5,u,g,e,z,0,t,t,20,f,g,00152,130,- b,28.75,1.165,u,g,k,v,0.5,t,f,0,f,s,00280,0,- a,25.00,11,y,p,aa,v,4.5,t,f,0,f,g,00120,0,- b,40.92,2.25,y,p,x,h,10,t,f,0,t,g,00176,0,- a,19.75,0.75,u,g,c,v,0.795,t,t,05,t,g,00140,5,- b,29.17,3.5,u,g,w,v,3.5,t,t,03,t,g,00329,0,- a,24.50,1.04,y,p,ff,ff,0.5,t,t,03,f,g,00180,147,- b,24.58,12.5,u,g,w,v,0.875,t,f,0,t,g,00260,0,- a,33.75,0.75,u,g,k,bb,1,t,t,03,t,g,00212,0,- b,20.67,1.25,y,p,c,h,1.375,t,t,03,t,g,00140,210,- a,25.42,1.125,u,g,q,v,1.29,t,t,02,f,g,00200,0,- b,37.75,7,u,g,q,h,11.5,t,t,07,t,g,00300,5,- b,52.50,6.5,u,g,k,v,6.29,t,t,15,f,g,00000,11202,+ b,57.83,7.04,u,g,m,v,14,t,t,06,t,g,00360,1332,+ a,20.75,10.335,u,g,cc,h,0.335,t,t,01,t,g,00080,50,+ b,39.92,6.21,u,g,q,v,0.04,t,t,01,f,g,00200,300,+ b,25.67,12.5,u,g,cc,v,1.21,t,t,67,t,g,00140,258,+ a,24.75,12.5,u,g,aa,v,1.5,t,t,12,t,g,00120,567,+ a,44.17,6.665,u,g,q,v,7.375,t,t,03,t,g,00000,0,+ a,23.50,9,u,g,q,v,8.5,t,t,05,t,g,00120,0,+ b,34.92,5,u,g,x,h,7.5,t,t,06,t,g,00000,1000,+ b,47.67,2.5,u,g,m,bb,2.5,t,t,12,t,g,00410,2510,+ b,22.75,11,u,g,q,v,2.5,t,t,07,t,g,00100,809,+ b,34.42,4.25,u,g,i,bb,3.25,t,t,02,f,g,00274,610,+ a,28.42,3.5,u,g,w,v,0.835,t,f,0,f,s,00280,0,+ b,67.75,5.5,u,g,e,z,13,t,t,01,t,g,00000,0,+ b,20.42,1.835,u,g,c,v,2.25,t,t,01,f,g,00100,150,+ a,47.42,8,u,g,e,bb,6.5,t,t,06,f,g,00375,51100,+ b,36.25,5,u,g,c,bb,2.5,t,t,06,f,g,00000,367,+ b,32.67,5.5,u,g,q,h,5.5,t,t,12,t,g,00408,1000,+ b,48.58,6.5,u,g,q,h,6,t,f,0,t,g,00350,0,+ b,39.92,0.54,y,p,aa,v,0.5,t,t,03,f,g,00200,1000,+ b,33.58,2.75,u,g,m,v,4.25,t,t,06,f,g,00204,0,+ a,18.83,9.5,u,g,w,v,1.625,t,t,06,t,g,00040,600,+ a,26.92,13.5,u,g,q,h,5,t,t,02,f,g,00000,5000,+ a,31.25,3.75,u,g,cc,h,0.625,t,t,09,t,g,00181,0,+ a,56.50,16,u,g,j,ff,0,t,t,15,f,g,00000,247,+ b,43.00,0.29,y,p,cc,h,1.75,t,t,08,f,g,00100,375,+ b,22.33,11,u,g,w,v,2,t,t,01,f,g,00080,278,+ b,27.25,1.665,u,g,cc,h,5.085,t,t,09,f,g,00399,827,+ b,32.83,2.5,u,g,cc,h,2.75,t,t,06,f,g,00160,2072,+ b,23.25,1.5,u,g,q,v,2.375,t,t,03,t,g,00000,582,+ a,40.33,7.54,y,p,q,h,8,t,t,14,f,g,00000,2300,+ a,30.50,6.5,u,g,c,bb,4,t,t,07,t,g,00000,3065,+ a,52.83,15,u,g,c,v,5.5,t,t,14,f,g,00000,2200,+ a,46.67,0.46,u,g,cc,h,0.415,t,t,11,t,g,00440,6,+ a,58.33,10,u,g,q,v,4,t,t,14,f,g,00000,1602,+ b,37.33,6.5,u,g,m,h,4.25,t,t,12,t,g,00093,0,+ b,23.08,2.5,u,g,c,v,1.085,t,t,11,t,g,00060,2184,+ b,32.75,1.5,u,g,cc,h,5.5,t,t,03,t,g,00000,0,+ a,21.67,11.5,y,p,j,j,0,t,t,11,t,g,00000,0,+ a,28.50,3.04,y,p,x,h,2.54,t,t,01,f,g,00070,0,+ a,68.67,15,u,g,e,z,0,t,t,14,f,g,00000,3376,+ b,28.00,2,u,g,k,h,4.165,t,t,02,t,g,00181,0,+ b,34.08,0.08,y,p,m,bb,0.04,t,t,01,t,g,00280,2000,+ b,27.67,2,u,g,x,h,1,t,t,04,f,g,00140,7544,+ b,44.00,2,u,g,m,v,1.75,t,t,02,t,g,00000,15,+ b,25.08,1.71,u,g,x,v,1.665,t,t,01,t,g,00395,20,+ b,32.00,1.75,y,p,e,h,0.04,t,f,0,t,g,00393,0,+ a,60.58,16.5,u,g,q,v,11,t,f,0,t,g,00021,10561,+ a,40.83,10,u,g,q,h,1.75,t,f,0,f,g,00029,837,+ b,19.33,9.5,u,g,q,v,1,t,f,0,t,g,00060,400,+ a,32.33,0.54,u,g,cc,v,0.04,t,f,0,f,g,00440,11177,+ b,36.67,3.25,u,g,q,h,9,t,f,0,t,g,00102,639,+ b,37.50,1.125,y,p,d,v,1.5,f,f,0,t,g,00431,0,+ a,25.08,2.54,y,p,aa,v,0.25,t,f,0,t,g,00370,0,+ b,41.33,0,u,g,c,bb,15,t,f,0,f,g,00000,0,+ b,56.00,12.5,u,g,k,h,8,t,f,0,t,g,00024,2028,+ a,49.83,13.585,u,g,k,h,8.5,t,f,0,t,g,00000,0,+ b,22.67,10.5,u,g,q,h,1.335,t,f,0,f,g,00100,0,+ b,27.00,1.5,y,p,w,v,0.375,t,f,0,t,g,00260,1065,+ b,25.00,12.5,u,g,aa,v,3,t,f,0,t,s,00020,0,+ a,26.08,8.665,u,g,aa,v,1.415,t,f,0,f,g,00160,150,+ a,18.42,9.25,u,g,q,v,1.21,t,t,04,f,g,00060,540,+ b,20.17,8.17,u,g,aa,v,1.96,t,t,14,f,g,00060,158,+ b,47.67,0.29,u,g,c,bb,15,t,t,20,f,g,00000,15000,+ a,21.25,2.335,u,g,i,bb,0.5,t,t,04,f,s,00080,0,+ a,20.67,3,u,g,q,v,0.165,t,t,03,f,g,00100,6,+ a,57.08,19.5,u,g,c,v,5.5,t,t,07,f,g,00000,3000,+ a,22.42,5.665,u,g,q,v,2.585,t,t,07,f,g,00129,3257,+ b,48.75,8.5,u,g,c,h,12.5,t,t,09,f,g,00181,1655,+ b,40.00,6.5,u,g,aa,bb,3.5,t,t,01,f,g,00000,500,+ b,40.58,5,u,g,c,v,5,t,t,07,f,g,00000,3065,+ a,28.67,1.04,u,g,c,v,2.5,t,t,05,t,g,00300,1430,+ a,33.08,4.625,u,g,q,h,1.625,t,t,02,f,g,00000,0,+ b,21.33,10.5,u,g,c,v,3,t,f,0,t,g,00000,0,+ b,42.00,0.205,u,g,i,h,5.125,t,f,0,f,g,00400,0,+ b,41.75,0.96,u,g,x,v,2.5,t,f,0,f,g,00510,600,+ b,22.67,1.585,y,p,w,v,3.085,t,t,06,f,g,00080,0,+ b,34.50,4.04,y,p,i,bb,8.5,t,t,07,t,g,00195,0,+ b,28.25,5.04,y,p,c,bb,1.5,t,t,08,t,g,00144,7,+ b,33.17,3.165,y,p,x,v,3.165,t,t,03,t,g,00380,0,+ b,48.17,7.625,u,g,w,h,15.5,t,t,12,f,g,00000,790,+ b,27.58,2.04,y,p,aa,v,2,t,t,03,t,g,00370,560,+ b,22.58,10.04,u,g,x,v,0.04,t,t,09,f,g,00060,396,+ a,24.08,0.5,u,g,q,h,1.25,t,t,01,f,g,00000,678,+ a,41.33,1,u,g,i,bb,2.25,t,f,0,t,g,00000,300,+ b,24.83,2.75,u,g,c,v,2.25,t,t,06,f,g,?,600,+ a,20.75,10.25,u,g,q,v,0.71,t,t,02,t,g,00049,0,+ b,36.33,2.125,y,p,w,v,0.085,t,t,01,f,g,00050,1187,+ a,35.42,12,u,g,q,h,14,t,t,08,f,g,00000,6590,+ a,71.58,0,?,?,?,?,0,f,f,0,f,p,?,0,+ b,28.67,9.335,u,g,q,h,5.665,t,t,06,f,g,00381,168,+ b,35.17,2.5,u,g,k,v,4.5,t,t,07,f,g,00150,1270,+ b,39.50,4.25,u,g,c,bb,6.5,t,t,16,f,g,00117,1210,+ b,39.33,5.875,u,g,cc,h,10,t,t,14,t,g,00399,0,+ b,24.33,6.625,y,p,d,v,5.5,t,f,0,t,s,00100,0,+ b,60.08,14.5,u,g,ff,ff,18,t,t,15,t,g,00000,1000,+ b,23.08,11.5,u,g,i,v,3.5,t,t,09,f,g,00056,742,+ b,26.67,2.71,y,p,cc,v,5.25,t,t,01,f,g,00211,0,+ b,48.17,3.5,u,g,aa,v,3.5,t,f,0,f,s,00230,0,+ b,41.17,4.04,u,g,cc,h,7,t,t,08,f,g,00320,0,+ b,55.92,11.5,u,g,ff,ff,5,t,t,05,f,g,00000,8851,+ b,53.92,9.625,u,g,e,v,8.665,t,t,05,f,g,00000,0,+ a,18.92,9.25,y,p,c,v,1,t,t,04,t,g,00080,500,+ a,50.08,12.54,u,g,aa,v,2.29,t,t,03,t,g,00156,0,+ b,65.42,11,u,g,e,z,20,t,t,07,t,g,00022,0,+ a,17.58,9,u,g,aa,v,1.375,t,f,0,t,g,00000,0,+ a,18.83,9.54,u,g,aa,v,0.085,t,f,0,f,g,00100,0,+ a,37.75,5.5,u,g,q,v,0.125,t,f,0,t,g,00228,0,+ b,23.25,4,u,g,c,bb,0.25,t,f,0,t,g,00160,0,+ b,18.08,5.5,u,g,k,v,0.5,t,f,0,f,g,00080,0,+ a,22.50,8.46,y,p,x,v,2.46,f,f,0,f,g,00164,0,+ b,19.67,0.375,u,g,q,v,2,t,t,02,t,g,00080,0,+ b,22.08,11,u,g,cc,v,0.665,t,f,0,f,g,00100,0,+ b,25.17,3.5,u,g,cc,v,0.625,t,t,07,f,g,00000,7059,+ a,47.42,3,u,g,x,v,13.875,t,t,02,t,g,00519,1704,+ b,33.50,1.75,u,g,x,h,4.5,t,t,04,t,g,00253,857,+ b,27.67,13.75,u,g,w,v,5.75,t,f,0,t,g,00487,500,+ a,58.42,21,u,g,i,bb,10,t,t,13,f,g,00000,6700,+ a,20.67,1.835,u,g,q,v,2.085,t,t,05,f,g,00220,2503,+ b,26.17,0.25,u,g,i,bb,0,t,f,0,t,g,00000,0,+ b,21.33,7.5,u,g,aa,v,1.415,t,t,01,f,g,00080,9800,+ b,42.83,4.625,u,g,q,v,4.58,t,f,0,f,s,00000,0,+ b,38.17,10.125,u,g,x,v,2.5,t,t,06,f,g,00520,196,+ b,20.50,10,y,p,c,v,2.5,t,f,0,f,s,00040,0,+ b,48.25,25.085,u,g,w,v,1.75,t,t,03,f,g,00120,14,+ b,28.33,5,u,g,w,v,11,t,f,0,t,g,00070,0,+ a,18.75,7.5,u,g,q,v,2.71,t,t,05,f,g,?,26726,+ b,18.50,2,u,g,i,v,1.5,t,t,02,f,g,00120,300,+ b,33.17,3.04,y,p,c,h,2.04,t,t,01,t,g,00180,18027,+ b,45.00,8.5,u,g,cc,h,14,t,t,01,t,g,00088,2000,+ a,19.67,0.21,u,g,q,h,0.29,t,t,11,f,g,00080,99,+ ?,24.50,12.75,u,g,c,bb,4.75,t,t,02,f,g,00073,444,+ b,21.83,11,u,g,x,v,0.29,t,t,06,f,g,00121,0,+ b,40.25,21.5,u,g,e,z,20,t,t,11,f,g,00000,1200,+ b,41.42,5,u,g,q,h,5,t,t,06,t,g,00470,0,+ a,17.83,11,u,g,x,h,1,t,t,11,f,g,00000,3000,+ b,23.17,11.125,u,g,x,h,0.46,t,t,01,f,g,00100,0,+ b,?,0.625,u,g,k,v,0.25,f,f,0,f,g,00380,2010,- b,18.17,10.25,u,g,c,h,1.085,f,f,0,f,g,00320,13,- b,20.00,11.045,u,g,c,v,2,f,f,0,t,g,00136,0,- b,20.00,0,u,g,d,v,0.5,f,f,0,f,g,00144,0,- a,20.75,9.54,u,g,i,v,0.04,f,f,0,f,g,00200,1000,- a,24.50,1.75,y,p,c,v,0.165,f,f,0,f,g,00132,0,- b,32.75,2.335,u,g,d,h,5.75,f,f,0,t,g,00292,0,- a,52.17,0,y,p,ff,ff,0,f,f,0,f,g,00000,0,- a,48.17,1.335,u,g,i,o,0.335,f,f,0,f,g,00000,120,- a,20.42,10.5,y,p,x,h,0,f,f,0,t,g,00154,32,- b,50.75,0.585,u,g,ff,ff,0,f,f,0,f,g,00145,0,- b,17.08,0.085,y,p,c,v,0.04,f,f,0,f,g,00140,722,- b,18.33,1.21,y,p,e,dd,0,f,f,0,f,g,00100,0,- a,32.00,6,u,g,d,v,1.25,f,f,0,f,g,00272,0,- b,59.67,1.54,u,g,q,v,0.125,t,f,0,t,g,00260,0,+ b,18.00,0.165,u,g,q,n,0.21,f,f,0,f,g,00200,40,+ b,37.58,0,?,?,?,?,0,f,f,0,f,p,?,0,+ b,32.33,2.5,u,g,c,v,1.25,f,f,0,t,g,00280,0,- b,18.08,6.75,y,p,m,v,0.04,f,f,0,f,g,00140,0,- b,38.25,10.125,y,p,k,v,0.125,f,f,0,f,g,00160,0,- b,30.67,2.5,u,g,cc,h,2.25,f,f,0,t,s,00340,0,- b,18.58,5.71,u,g,d,v,0.54,f,f,0,f,g,00120,0,- a,19.17,5.415,u,g,i,h,0.29,f,f,0,f,g,00080,484,- a,18.17,10,y,p,q,h,0.165,f,f,0,f,g,00340,0,- b,24.58,13.5,y,p,ff,ff,0,f,f,0,f,g,?,0,- b,16.25,0.835,u,g,m,v,0.085,t,f,0,f,s,00200,0,- b,21.17,0.875,y,p,c,h,0.25,f,f,0,f,g,00280,204,- b,23.92,0.585,y,p,cc,h,0.125,f,f,0,f,g,00240,1,- b,17.67,4.46,u,g,c,v,0.25,f,f,0,f,s,00080,0,- a,16.50,1.25,u,g,q,v,0.25,f,t,01,f,g,00108,98,- b,23.25,12.625,u,g,c,v,0.125,f,t,02,f,g,00000,5552,- b,17.58,10,u,g,w,h,0.165,f,t,01,f,g,00120,1,- a,?,1.5,u,g,ff,ff,0,f,t,02,t,g,00200,105,- b,29.50,0.58,u,g,w,v,0.29,f,t,01,f,g,00340,2803,- b,18.83,0.415,y,p,c,v,0.165,f,t,01,f,g,00200,1,- a,21.75,1.75,y,p,j,j,0,f,f,0,f,g,00160,0,- b,23.00,0.75,u,g,m,v,0.5,f,f,0,t,s,00320,0,- a,18.25,10,u,g,w,v,1,f,t,01,f,g,00120,1,- b,25.42,0.54,u,g,w,v,0.165,f,t,01,f,g,00272,444,- b,35.75,2.415,u,g,w,v,0.125,f,t,02,f,g,00220,1,- a,16.08,0.335,u,g,ff,ff,0,f,t,01,f,g,00160,126,- a,31.92,3.125,u,g,ff,ff,3.04,f,t,02,t,g,00200,4,- b,69.17,9,u,g,ff,ff,4,f,t,01,f,g,00070,6,- b,32.92,2.5,u,g,aa,v,1.75,f,t,02,t,g,00720,0,- b,16.33,2.75,u,g,aa,v,0.665,f,t,01,f,g,00080,21,- b,22.17,12.125,u,g,c,v,3.335,f,t,02,t,g,00180,173,- a,57.58,2,u,g,ff,ff,6.5,f,t,01,f,g,00000,10,- b,18.25,0.165,u,g,d,v,0.25,f,f,0,t,s,00280,0,- b,23.42,1,u,g,c,v,0.5,f,f,0,t,s,00280,0,- a,15.92,2.875,u,g,q,v,0.085,f,f,0,f,g,00120,0,- a,24.75,13.665,u,g,q,h,1.5,f,f,0,f,g,00280,1,- b,48.75,26.335,y,p,ff,ff,0,t,f,0,t,g,00000,0,- b,23.50,2.75,u,g,ff,ff,4.5,f,f,0,f,g,00160,25,- b,18.58,10.29,u,g,ff,ff,0.415,f,f,0,f,g,00080,0,- b,27.75,1.29,u,g,k,h,0.25,f,f,0,t,s,00140,0,- a,31.75,3,y,p,j,j,0,f,f,0,f,g,00160,20,- a,24.83,4.5,u,g,w,v,1,f,f,0,t,g,00360,6,- b,19.00,1.75,y,p,c,v,2.335,f,f,0,t,g,00112,6,- a,16.33,0.21,u,g,aa,v,0.125,f,f,0,f,g,00200,1,- a,18.58,10,u,g,d,v,0.415,f,f,0,f,g,00080,42,- b,16.25,0,y,p,aa,v,0.25,f,f,0,f,g,00060,0,- b,23.00,0.75,u,g,m,v,0.5,t,f,0,t,s,00320,0,- b,21.17,0.25,y,p,c,h,0.25,f,f,0,f,g,00280,204,- b,17.50,22,l,gg,ff,o,0,f,f,0,t,p,00450,100000,+ b,19.17,0,y,p,m,bb,0,f,f,0,t,s,00500,1,+ b,36.75,0.125,y,p,c,v,1.5,f,f,0,t,g,00232,113,+ b,21.25,1.5,u,g,w,v,1.5,f,f,0,f,g,00150,8,+ a,18.08,0.375,l,gg,cc,ff,10,f,f,0,t,s,00300,0,+ a,33.67,0.375,u,g,cc,v,0.375,f,f,0,f,g,00300,44,+ b,48.58,0.205,y,p,k,v,0.25,t,t,11,f,g,00380,2732,+ b,33.67,1.25,u,g,w,v,1.165,f,f,0,f,g,00120,0,- a,29.50,1.085,y,p,x,v,1,f,f,0,f,g,00280,13,- b,30.17,1.085,y,p,c,v,0.04,f,f,0,f,g,00170,179,- ?,40.83,3.5,u,g,i,bb,0.5,f,f,0,f,s,01160,0,- b,34.83,2.5,y,p,w,v,3,f,f,0,f,s,00200,0,- b,?,4,y,p,i,v,0.085,f,f,0,t,g,00411,0,- b,20.42,0,?,?,?,?,0,f,f,0,f,p,?,0,- a,33.25,2.5,y,p,c,v,2.5,f,f,0,t,g,00000,2,- b,34.08,2.5,u,g,c,v,1,f,f,0,f,g,00460,16,- a,25.25,12.5,u,g,d,v,1,f,f,0,t,g,00180,1062,- b,34.75,2.5,u,g,cc,bb,0.5,f,f,0,f,g,00348,0,- b,27.67,0.75,u,g,q,h,0.165,f,f,0,t,g,00220,251,- b,47.33,6.5,u,g,c,v,1,f,f,0,t,g,00000,228,- a,34.83,1.25,y,p,i,h,0.5,f,f,0,t,g,00160,0,- a,33.25,3,y,p,aa,v,2,f,f,0,f,g,00180,0,- b,28.00,3,u,g,w,v,0.75,f,f,0,t,g,00300,67,- a,39.08,4,u,g,c,v,3,f,f,0,f,g,00480,0,- b,42.75,4.085,u,g,aa,v,0.04,f,f,0,f,g,00108,100,- b,26.92,2.25,u,g,i,bb,0.5,f,f,0,t,g,00640,4000,- b,33.75,2.75,u,g,i,bb,0,f,f,0,f,g,00180,0,- b,38.92,1.75,u,g,k,v,0.5,f,f,0,t,g,00300,2,- b,62.75,7,u,g,e,z,0,f,f,0,f,g,00000,12,- ?,32.25,1.5,u,g,c,v,0.25,f,f,0,t,g,00372,122,- b,26.75,4.5,y,p,c,bb,2.5,f,f,0,f,g,00200,1210,- b,63.33,0.54,u,g,c,v,0.585,t,t,03,t,g,00180,0,- b,27.83,1.5,u,g,w,v,2.25,f,t,01,t,g,00100,3,- a,26.17,2,u,g,j,j,0,f,f,0,t,g,00276,1,- b,22.17,0.585,y,p,ff,ff,0,f,f,0,f,g,00100,0,- b,22.50,11.5,y,p,m,v,1.5,f,f,0,t,g,00000,4000,- b,30.75,1.585,u,g,d,v,0.585,f,f,0,t,s,00000,0,- b,36.67,2,u,g,i,v,0.25,f,f,0,t,g,00221,0,- a,16.00,0.165,u,g,aa,v,1,f,t,02,t,g,00320,1,- b,41.17,1.335,u,g,d,v,0.165,f,f,0,f,g,00168,0,- a,19.50,0.165,u,g,q,v,0.04,f,f,0,t,g,00380,0,- b,32.42,3,u,g,d,v,0.165,f,f,0,t,g,00120,0,- a,36.75,4.71,u,g,ff,ff,0,f,f,0,f,g,00160,0,- a,30.25,5.5,u,g,k,v,5.5,f,f,0,t,s,00100,0,- b,23.08,2.5,u,g,ff,ff,0.085,f,f,0,t,g,00100,4208,- b,26.83,0.54,u,g,k,ff,0,f,f,0,f,g,00100,0,- b,16.92,0.335,y,p,k,v,0.29,f,f,0,f,s,00200,0,- b,24.42,2,u,g,e,dd,0.165,f,t,02,f,g,00320,1300,- b,42.83,1.25,u,g,m,v,13.875,f,t,01,t,g,00352,112,- a,22.75,6.165,u,g,aa,v,0.165,f,f,0,f,g,00220,1000,- b,39.42,1.71,y,p,m,v,0.165,f,f,0,f,s,00400,0,- a,23.58,11.5,y,p,k,h,3,f,f,0,t,g,00020,16,- b,21.42,0.75,y,p,r,n,0.75,f,f,0,t,g,00132,2,- b,33.00,2.5,y,p,w,v,7,f,f,0,t,g,00280,0,- b,26.33,13,u,g,e,dd,0,f,f,0,t,g,00140,1110,- a,45.00,4.585,u,g,k,h,1,f,f,0,t,s,00240,0,- b,26.25,1.54,u,g,w,v,0.125,f,f,0,f,g,00100,0,- ?,28.17,0.585,u,g,aa,v,0.04,f,f,0,f,g,00260,1004,- a,20.83,0.5,y,p,e,dd,1,f,f,0,f,g,00260,0,- b,28.67,14.5,u,g,d,v,0.125,f,f,0,f,g,00000,286,- b,20.67,0.835,y,p,c,v,2,f,f,0,t,s,00240,0,- b,34.42,1.335,u,g,i,bb,0.125,f,f,0,t,g,00440,4500,- b,33.58,0.25,u,g,i,bb,4,f,f,0,t,s,00420,0,- b,43.17,5,u,g,i,bb,2.25,f,f,0,t,g,00141,0,- a,22.67,7,u,g,c,v,0.165,f,f,0,f,g,00160,0,- a,24.33,2.5,y,p,i,bb,4.5,f,f,0,f,g,00200,456,- a,56.83,4.25,y,p,ff,ff,5,f,f,0,t,g,00000,4,- b,22.08,11.46,u,g,k,v,1.585,f,f,0,t,g,00100,1212,- b,34.00,5.5,y,p,c,v,1.5,f,f,0,t,g,00060,0,- b,22.58,1.5,y,p,aa,v,0.54,f,f,0,t,g,00120,67,- b,21.17,0,u,g,c,v,0.5,f,f,0,t,s,00000,0,- b,26.67,14.585,u,g,i,bb,0,f,f,0,t,g,00178,0,- b,22.92,0.17,u,g,m,v,0.085,f,f,0,f,s,00000,0,- b,15.17,7,u,g,e,v,1,f,f,0,f,g,00600,0,- b,39.92,5,u,g,i,bb,0.21,f,f,0,f,g,00550,0,- b,27.42,12.5,u,g,aa,bb,0.25,f,f,0,t,g,00720,0,- b,24.75,0.54,u,g,m,v,1,f,f,0,t,g,00120,1,- b,41.17,1.25,y,p,w,v,0.25,f,f,0,f,g,00000,195,- a,33.08,1.625,u,g,d,v,0.54,f,f,0,t,g,00000,0,- b,29.83,2.04,y,p,x,h,0.04,f,f,0,f,g,00128,1,- a,23.58,0.585,y,p,ff,ff,0.125,f,f,0,f,g,00120,87,- b,26.17,12.5,y,p,k,h,1.25,f,f,0,t,g,00000,17,- b,31.00,2.085,u,g,c,v,0.085,f,f,0,f,g,00300,0,- b,20.75,5.085,y,p,j,v,0.29,f,f,0,f,g,00140,184,- b,28.92,0.375,u,g,c,v,0.29,f,f,0,f,g,00220,140,- a,51.92,6.5,u,g,i,bb,3.085,f,f,0,t,g,00073,0,- a,22.67,0.335,u,g,q,v,0.75,f,f,0,f,s,00160,0,- b,34.00,5.085,y,p,i,bb,1.085,f,f,0,t,g,00480,0,- a,69.50,6,u,g,ff,ff,0,f,f,0,f,s,00000,0,- a,40.33,8.125,y,p,k,v,0.165,f,t,02,f,g,?,18,- a,19.58,0.665,y,p,c,v,1,f,t,01,f,g,02000,2,- b,16.00,3.125,u,g,w,v,0.085,f,t,01,f,g,00000,6,- b,17.08,0.25,u,g,q,v,0.335,f,t,04,f,g,00160,8,- b,31.25,2.835,u,g,ff,ff,0,f,t,05,f,g,00176,146,- b,25.17,3,u,g,c,v,1.25,f,t,01,f,g,00000,22,- a,22.67,0.79,u,g,i,v,0.085,f,f,0,f,g,00144,0,- b,40.58,1.5,u,g,i,bb,0,f,f,0,f,s,00300,0,- b,22.25,0.46,u,g,k,v,0.125,f,f,0,t,g,00280,55,- a,22.25,1.25,y,p,ff,ff,3.25,f,f,0,f,g,00280,0,- b,22.50,0.125,y,p,k,v,0.125,f,f,0,f,g,00200,70,- b,23.58,1.79,u,g,c,v,0.54,f,f,0,t,g,00136,1,- b,38.42,0.705,u,g,c,v,0.375,f,t,02,f,g,00225,500,- a,26.58,2.54,y,p,ff,ff,0,f,f,0,t,g,00180,60,- b,35.00,2.5,u,g,i,v,1,f,f,0,t,g,00210,0,- b,20.42,1.085,u,g,q,v,1.5,f,f,0,f,g,00108,7,- b,29.42,1.25,u,g,w,v,1.75,f,f,0,f,g,00200,0,- b,26.17,0.835,u,g,cc,v,1.165,f,f,0,f,g,00100,0,- b,33.67,2.165,u,g,c,v,1.5,f,f,0,f,p,00120,0,- b,24.58,1.25,u,g,c,v,0.25,f,f,0,f,g,00110,0,- a,27.67,2.04,u,g,w,v,0.25,f,f,0,t,g,00180,50,- b,37.50,0.835,u,g,e,v,0.04,f,f,0,f,g,00120,5,- b,49.17,2.29,u,g,ff,ff,0.29,f,f,0,f,g,00200,3,- b,33.58,0.335,y,p,cc,v,0.085,f,f,0,f,g,00180,0,- b,51.83,3,y,p,ff,ff,1.5,f,f,0,f,g,00180,4,- b,22.92,3.165,y,p,c,v,0.165,f,f,0,f,g,00160,1058,- b,21.83,1.54,u,g,k,v,0.085,f,f,0,t,g,00356,0,- b,25.25,1,u,g,aa,v,0.5,f,f,0,f,g,00200,0,- b,58.58,2.71,u,g,c,v,2.415,f,f,0,t,g,00320,0,- b,19.00,0,y,p,ff,ff,0,f,t,04,f,g,00045,1,- b,19.58,0.585,u,g,ff,ff,0,f,t,03,f,g,00350,769,- a,53.33,0.165,u,g,ff,ff,0,f,f,0,t,s,00062,27,- a,27.17,1.25,u,g,ff,ff,0,f,t,01,f,g,00092,300,- b,25.92,0.875,u,g,k,v,0.375,f,t,02,t,g,00174,3,- b,23.08,0,u,g,k,v,1,f,t,11,f,s,00000,0,- b,39.58,5,u,g,ff,ff,0,f,t,02,f,g,00017,1,- b,30.58,2.71,y,p,m,v,0.125,f,f,0,t,s,00080,0,- b,17.25,3,u,g,k,v,0.04,f,f,0,t,g,00160,40,- a,17.67,0,y,p,j,ff,0,f,f,0,f,g,00086,0,- a,?,11.25,u,g,ff,ff,0,f,f,0,f,g,?,5200,- b,16.50,0.125,u,g,c,v,0.165,f,f,0,f,g,00132,0,- a,27.33,1.665,u,g,ff,ff,0,f,f,0,f,g,00340,1,- b,31.25,1.125,u,g,ff,ff,0,f,t,01,f,g,00096,19,- b,20.00,7,u,g,c,v,0.5,f,f,0,f,g,00000,0,- b,?,3,y,p,i,bb,7,f,f,0,f,g,00000,1,- b,39.50,1.625,u,g,c,v,1.5,f,f,0,f,g,00000,316,- b,36.50,4.25,u,g,q,v,3.5,f,f,0,f,g,00454,50,- ?,29.75,0.665,u,g,w,v,0.25,f,f,0,t,g,00300,0,- b,52.42,1.5,u,g,d,v,3.75,f,f,0,t,g,00000,350,- b,36.17,18.125,u,g,w,v,0.085,f,f,0,f,g,00320,3552,- b,34.58,0,?,?,?,?,0,f,f,0,f,p,?,0,- b,29.67,0.75,y,p,c,v,0.04,f,f,0,f,g,00240,0,- b,36.17,5.5,u,g,i,bb,5,f,f,0,f,g,00210,687,- b,25.67,0.29,y,p,c,v,1.5,f,f,0,t,g,00160,0,- a,24.50,2.415,y,p,c,v,0,f,f,0,f,g,00120,0,- b,24.08,0.875,u,g,m,v,0.085,f,t,04,f,g,00254,1950,- b,21.92,0.5,u,g,c,v,0.125,f,f,0,f,g,00360,0,- a,36.58,0.29,u,g,ff,ff,0,f,t,10,f,g,00200,18,- a,23.00,1.835,u,g,j,j,0,f,t,01,f,g,00200,53,- a,27.58,3,u,g,m,v,2.79,f,t,01,t,g,00280,10,- b,31.08,3.085,u,g,c,v,2.5,f,t,02,t,g,00160,41,- a,30.42,1.375,u,g,w,h,0.04,f,t,03,f,g,00000,33,- b,22.08,2.335,u,g,k,v,0.75,f,f,0,f,g,00180,0,- b,16.33,4.085,u,g,i,h,0.415,f,f,0,t,g,00120,0,- a,21.92,11.665,u,g,k,h,0.085,f,f,0,f,g,00320,5,- b,21.08,4.125,y,p,i,h,0.04,f,f,0,f,g,00140,100,- b,17.42,6.5,u,g,i,v,0.125,f,f,0,f,g,00060,100,- b,19.17,4,y,p,i,v,1,f,f,0,t,g,00360,1000,- b,20.67,0.415,u,g,c,v,0.125,f,f,0,f,g,00000,44,- b,26.75,2,u,g,d,v,0.75,f,f,0,t,g,00080,0,- b,23.58,0.835,u,g,i,h,0.085,f,f,0,t,g,00220,5,- b,39.17,2.5,y,p,i,h,10,f,f,0,t,s,00200,0,- b,22.75,11.5,u,g,i,v,0.415,f,f,0,f,g,00000,0,- ?,26.50,2.71,y,p,?,?,0.085,f,f,0,f,s,00080,0,- a,16.92,0.5,u,g,i,v,0.165,f,t,06,t,g,00240,35,- b,23.50,3.165,y,p,k,v,0.415,f,t,01,t,g,00280,80,- a,17.33,9.5,u,g,aa,v,1.75,f,t,10,t,g,00000,10,- b,23.75,0.415,y,p,c,v,0.04,f,t,02,f,g,00128,6,- b,34.67,1.08,u,g,m,v,1.165,f,f,0,f,s,00028,0,- b,74.83,19,y,p,ff,ff,0.04,f,t,02,f,g,00000,351,- b,28.17,0.125,y,p,k,v,0.085,f,f,0,f,g,00216,2100,- b,24.50,13.335,y,p,aa,v,0.04,f,f,0,t,g,00120,475,- b,18.83,3.54,y,p,ff,ff,0,f,f,0,t,g,00180,1,- ?,45.33,1,u,g,q,v,0.125,f,f,0,t,g,00263,0,- @//E*O*F crx.data// chmod u=rw,g=,o= crx.data echo x - crx.names sed 's/^@//' > "crx.names" <<'@//E*O*F crx.names//' | This file concerns credit card applications. All attribute names | and values have been changed to meaningless symbols to protect | confidentiality of the data. | | Title: | Credit Approval | | Sources: | (confidential) | Submitted by quinlan@cs.su.oz.au | | Past Usage: | See Quinlan, | * "Simplifying decision trees", Int J Man-Machine Studies 27, | Dec 1987, pp. 221-234. | * "C4.5: Programs for Machine Learning", Morgan Kaufmann, Oct 1992 | | Relevant Information: | This dataset is interesting because there is a good mix of | attributes -- continuous, discrete with small numbers of | values, and discrete with larger numbers of values. There | are also a few missing values. | | Instances: | 690 | | Attributes: | 15 | | Missing Attribute Values: | 37 cases (5%) have one or more missing values. The missing | values from particular attributes are: | A1: 12 | A2: 12 | A4: 6 | A5: 6 | A6: 9 | A7: 9 | A14: 13 | | Class Distribution: | +: 307 (44.5%) | -: 383 (55.5%) +, -. | classes A1: b, a. |type: A A2: continuous. |type: B A3: continuous. |type: B A4: u, y, l, t. |type: C A5: g, p, gg. |type: D A6: c, d, cc, i, j, k, m, r, q, w, x, e, aa, ff. |type: E A7: v, h, bb, j, n, z, dd, ff, o. |type: E A8: continuous. |type: B A9: t, f. |type: F A10: t, f. |type: F A11: continuous. |type: B A12: t, f. |type: F A13: g, p, s. |type: G A14: continuous. |type: H A15: continuous. |type: H @//E*O*F crx.names// chmod u=rw,g=w,o=w crx.names echo x - crx.test sed 's/^@//' > "crx.test" <<'@//E*O*F crx.test//' a,47.25,0.75,u,g,q,h,2.75,t,t,01,f,g,00333,892,+ b,24.17,0.875,u,g,q,v,4.625,t,t,02,t,g,00520,2000,+ b,39.25,9.5,u,g,m,v,6.5,t,t,14,f,g,00240,4607,+ a,20.50,11.835,u,g,c,h,6,t,f,0,f,g,00340,0,+ a,18.83,4.415,y,p,c,h,3,t,f,0,f,g,00240,0,+ b,19.17,9.5,u,g,w,v,1.5,t,f,0,f,g,00120,2206,+ a,25.00,0.875,u,g,x,h,1.04,t,f,0,t,g,00160,5860,+ b,20.17,9.25,u,g,c,v,1.665,t,t,03,t,g,00040,28,+ b,25.75,0.5,u,g,c,v,1.46,t,t,05,t,g,00312,0,+ b,20.42,7,u,g,c,v,1.625,t,t,03,f,g,00200,1391,+ b,?,4,u,g,x,v,5,t,t,03,t,g,00290,2279,+ b,39.00,5,u,g,cc,v,3.5,t,t,10,t,g,00000,0,+ a,64.08,0.165,u,g,ff,ff,0,t,t,01,f,g,00232,100,+ b,28.25,5.125,u,g,x,v,4.75,t,t,02,f,g,00420,7,+ a,28.75,3.75,u,g,c,v,1.085,t,t,01,t,g,00371,0,+ b,31.33,19.5,u,g,c,v,7,t,t,16,f,g,00000,5000,+ a,18.92,9,u,g,aa,v,0.75,t,t,02,f,g,00088,591,+ a,24.75,3,u,g,q,h,1.835,t,t,19,f,g,00000,500,+ a,30.67,12,u,g,c,v,2,t,t,01,f,g,00220,19,+ b,21.00,4.79,y,p,w,v,2.25,t,t,01,t,g,00080,300,+ b,13.75,4,y,p,w,v,1.75,t,t,02,t,g,00120,1000,+ a,46.00,4,u,g,j,j,0,t,f,0,f,g,00100,960,+ a,44.33,0,u,g,c,v,2.5,t,f,0,f,g,00000,0,+ b,20.25,9.96,u,g,e,dd,0,t,f,0,f,g,00000,0,+ b,22.67,2.54,y,p,c,h,2.585,t,f,0,f,g,00000,0,+ b,?,10.5,u,g,x,v,6.5,t,f,0,f,g,00000,0,+ a,60.92,5,u,g,aa,v,4,t,t,04,f,g,00000,99,+ b,16.08,0.75,u,g,c,v,1.75,t,t,05,t,g,00352,690,+ a,28.17,0.375,u,g,q,v,0.585,t,t,04,f,g,00080,0,+ b,39.17,1.71,u,g,x,v,0.125,t,t,05,t,g,00480,0,+ ?,20.42,7.5,u,g,k,v,1.5,t,t,01,f,g,00160,234,+ a,30.00,5.29,u,g,e,dd,2.25,t,t,05,t,g,00099,500,+ b,22.83,3,u,g,m,v,1.29,t,t,01,f,g,00260,800,+ a,22.50,8.5,u,g,q,v,1.75,t,t,10,f,g,00080,990,- a,28.58,1.665,u,g,q,v,2.415,t,f,0,t,g,00440,0,- b,45.17,1.5,u,g,c,v,2.5,t,f,0,t,g,00140,0,- b,41.58,1.75,u,g,k,v,0.21,t,f,0,f,g,00160,0,- a,57.08,0.335,u,g,i,bb,1,t,f,0,t,g,00252,2197,- a,55.75,7.08,u,g,k,h,6.75,t,t,03,t,g,00100,50,- b,43.25,25.21,u,g,q,h,0.21,t,t,01,f,g,00760,90,- a,25.33,2.085,u,g,c,h,2.75,t,f,0,t,g,00360,1,- a,24.58,0.67,u,g,aa,h,1.75,t,f,0,f,g,00400,0,- b,43.17,2.25,u,g,i,bb,0.75,t,f,0,f,g,00560,0,- b,40.92,0.835,u,g,ff,ff,0,t,f,0,f,g,00130,1,- b,31.83,2.5,u,g,aa,v,7.5,t,f,0,t,g,00523,0,- a,33.92,1.585,y,p,ff,ff,0,t,f,0,f,g,00320,0,- a,24.92,1.25,u,g,ff,ff,0,t,f,0,f,g,00080,0,- b,35.25,3.165,u,g,x,h,3.75,t,f,0,t,g,00680,0,- b,34.25,1.75,u,g,w,bb,0.25,t,f,0,t,g,00163,0,- b,80.25,5.5,u,g,?,?,0.54,t,f,0,f,g,00000,340,- b,19.42,1.5,y,p,cc,v,2,t,f,0,t,g,00100,20,- b,42.75,3,u,g,i,bb,1,t,f,0,f,g,00000,200,- b,19.67,10,y,p,k,h,0.835,t,f,0,t,g,00140,0,- b,36.33,3.79,u,g,w,v,1.165,t,f,0,t,g,00200,0,- b,30.08,1.04,y,p,i,bb,0.5,t,t,10,t,g,00132,28,- b,44.25,11,y,p,d,v,1.5,t,f,0,f,s,00000,0,- b,23.58,0.46,y,p,w,v,2.625,t,t,06,t,g,00208,347,- b,23.92,1.5,u,g,d,h,1.875,t,t,06,f,g,00200,327,+ b,33.17,1,u,g,x,v,0.75,t,t,07,t,g,00340,4071,+ b,48.33,12,u,g,m,v,16,t,f,0,f,s,00110,0,+ b,76.75,22.29,u,g,e,z,12.75,t,t,01,t,g,00000,109,+ b,51.33,10,u,g,i,bb,0,t,t,11,f,g,00000,1249,+ b,34.75,15,u,g,r,n,5.375,t,t,09,t,g,00000,134,+ b,38.58,3.335,u,g,w,v,4,t,t,14,f,g,00383,1344,+ a,22.42,11.25,y,p,x,h,0.75,t,t,04,f,g,00000,321,+ b,41.92,0.42,u,g,c,h,0.21,t,t,06,f,g,00220,948,+ b,29.58,4.5,u,g,w,v,7.5,t,t,02,t,g,00330,0,+ a,32.17,1.46,u,g,w,v,1.085,t,t,16,f,g,00120,2079,+ b,51.42,0.04,u,g,x,h,0.04,t,f,0,f,g,00000,3000,+ a,22.83,2.29,u,g,q,h,2.29,t,t,07,t,g,00140,2384,+ a,25.00,12.33,u,g,cc,h,3.5,t,t,06,f,g,00400,458,+ b,26.75,1.125,u,g,x,h,1.25,t,f,0,f,g,00000,5298,+ b,23.33,1.5,u,g,c,h,1.415,t,f,0,f,g,00422,200,+ b,24.42,12.335,u,g,q,h,1.585,t,f,0,t,g,00120,0,+ b,42.17,5.04,u,g,q,h,12.75,t,f,0,t,g,00092,0,+ a,20.83,3,u,g,aa,v,0.04,t,f,0,f,g,00100,0,+ b,23.08,11.5,u,g,w,h,2.125,t,t,11,t,g,00290,284,+ a,25.17,2.875,u,g,x,h,0.875,t,f,0,f,g,00360,0,+ b,43.08,0.375,y,p,c,v,0.375,t,t,08,t,g,00300,162,+ a,35.75,0.915,u,g,aa,v,0.75,t,t,04,f,g,00000,1583,+ b,59.50,2.75,u,g,w,v,1.75,t,t,05,t,g,00060,58,+ b,21.00,3,y,p,d,v,1.085,t,t,08,t,g,00160,1,+ b,21.92,0.54,y,p,x,v,0.04,t,t,01,t,g,00840,59,+ a,65.17,14,u,g,ff,ff,0,t,t,11,t,g,00000,1400,+ a,20.33,10,u,g,c,h,1,t,t,04,f,g,00050,1465,+ b,32.25,0.165,y,p,c,h,3.25,t,t,01,t,g,00432,8000,+ b,30.17,0.5,u,g,c,v,1.75,t,t,11,f,g,00032,540,+ b,25.17,6,u,g,c,v,1,t,t,03,f,g,00000,0,+ b,39.17,1.625,u,g,c,v,1.5,t,t,10,f,g,00186,4700,+ b,39.08,6,u,g,m,v,1.29,t,t,05,t,g,00108,1097,+ b,31.67,0.83,u,g,x,v,1.335,t,t,08,t,g,00303,3290,+ b,41.00,0.04,u,g,e,v,0.04,f,t,01,f,s,00560,0,+ b,48.50,4.25,u,g,m,v,0.125,t,f,0,t,g,00225,0,+ b,32.67,9,y,p,w,h,5.25,t,f,0,t,g,00154,0,+ a,28.08,15,y,p,e,z,0,t,f,0,f,g,00000,13212,+ b,73.42,17.75,u,g,ff,ff,0,t,f,0,t,g,00000,0,+ b,64.08,20,u,g,x,h,17.5,t,t,09,t,g,00000,1000,+ b,51.58,15,u,g,c,v,8.5,t,t,09,f,g,00000,0,+ b,26.67,1.75,y,p,c,v,1,t,t,05,t,g,00160,5777,+ b,25.33,0.58,u,g,c,v,0.29,t,t,07,t,g,00096,5124,+ b,30.17,6.5,u,g,cc,v,3.125,t,t,08,f,g,00330,1200,+ b,27.00,0.75,u,g,c,h,4.25,t,t,03,t,g,00312,150,+ b,23.17,0,?,?,?,?,0,f,f,0,f,p,?,0,+ b,34.17,5.25,u,g,w,v,0.085,f,f,0,t,g,00290,6,+ b,38.67,0.21,u,g,k,v,0.085,t,f,0,t,g,00280,0,+ b,25.75,0.75,u,g,c,bb,0.25,t,f,0,f,g,00349,23,+ a,46.08,3,u,g,c,v,2.375,t,t,08,t,g,00396,4159,+ a,21.50,6,u,g,aa,v,2.5,t,t,03,f,g,00080,918,+ ?,20.08,0.125,u,g,q,v,1,f,t,01,f,g,00240,768,+ b,20.50,2.415,u,g,c,v,2,t,t,11,t,g,00200,3000,+ a,29.50,0.46,u,g,k,v,0.54,t,t,04,f,g,00380,500,+ ?,42.25,1.75,y,p,?,?,0,f,f,0,t,g,00150,1,- b,29.83,1.25,y,p,k,v,0.25,f,f,0,f,g,00224,0,- b,20.08,0.25,u,g,q,v,0.125,f,f,0,f,g,00200,0,- b,23.42,0.585,u,g,c,h,0.085,t,f,0,f,g,00180,0,- a,29.58,1.75,y,p,k,v,1.25,f,f,0,t,g,00280,0,- b,16.17,0.04,u,g,c,v,0.04,f,f,0,f,g,00000,0,+ b,32.33,3.5,u,g,k,v,0.5,f,f,0,t,g,00232,0,- b,?,0.04,y,p,d,v,4.25,f,f,0,t,g,00460,0,- b,47.83,4.165,u,g,x,bb,0.085,f,f,0,t,g,00520,0,- b,20.00,1.25,y,p,k,v,0.125,f,f,0,f,g,00140,4,- b,27.58,3.25,y,p,q,h,5.085,f,t,02,t,g,00369,1,- b,22.00,0.79,u,g,w,v,0.29,f,t,01,f,g,00420,283,- b,19.33,10.915,u,g,c,bb,0.585,f,t,02,t,g,00200,7,- a,38.33,4.415,u,g,c,v,0.125,f,f,0,f,g,00160,0,- b,29.42,1.25,u,g,c,h,0.25,f,t,02,t,g,00400,108,- b,22.67,0.75,u,g,i,v,1.585,f,t,01,t,g,00400,9,- b,32.25,14,y,p,ff,ff,0,f,t,02,f,g,00160,1,- b,29.58,4.75,u,g,m,v,2,f,t,01,t,g,00460,68,- b,18.42,10.415,y,p,aa,v,0.125,t,f,0,f,g,00120,375,- b,22.17,2.25,u,g,i,v,0.125,f,f,0,f,g,00160,10,- b,22.67,0.165,u,g,c,j,2.25,f,f,0,t,s,00000,0,+ a,25.58,0,?,?,?,?,0,f,f,0,f,p,?,0,+ b,18.83,0,u,g,q,v,0.665,f,f,0,f,g,00160,1,- b,21.58,0.79,y,p,cc,v,0.665,f,f,0,f,g,00160,0,- b,23.75,12,u,g,c,v,2.085,f,f,0,f,s,00080,0,- b,22.00,7.835,y,p,i,bb,0.165,f,f,0,t,g,?,0,- b,36.08,2.54,u,g,ff,ff,0,f,f,0,f,g,00000,1000,- b,29.25,13,u,g,d,h,0.5,f,f,0,f,g,00228,0,- a,19.58,0.665,u,g,w,v,1.665,f,f,0,f,g,00220,5,- a,22.92,1.25,u,g,q,v,0.25,f,f,0,t,g,00120,809,- a,27.25,0.29,u,g,m,h,0.125,f,t,01,t,g,00272,108,- a,38.75,1.5,u,g,ff,ff,0,f,f,0,f,g,00076,0,- b,32.42,2.165,y,p,k,ff,0,f,f,0,f,g,00120,0,- a,23.75,0.71,u,g,w,v,0.25,f,t,01,t,g,00240,4,- b,18.17,2.46,u,g,c,n,0.96,f,t,02,t,g,00160,587,- b,40.92,0.5,y,p,m,v,0.5,f,f,0,t,g,00130,0,- b,19.50,9.585,u,g,aa,v,0.79,f,f,0,f,g,00080,350,- b,28.58,3.625,u,g,aa,v,0.25,f,f,0,t,g,00100,0,- b,35.58,0.75,u,g,k,v,1.5,f,f,0,t,g,00231,0,- b,34.17,2.75,u,g,i,bb,2.5,f,f,0,t,g,00232,200,- ?,33.17,2.25,y,p,cc,v,3.5,f,f,0,t,g,00200,141,- b,31.58,0.75,y,p,aa,v,3.5,f,f,0,t,g,00320,0,- a,52.50,7,u,g,aa,h,3,f,f,0,f,g,00000,0,- b,36.17,0.42,y,p,w,v,0.29,f,f,0,t,g,00309,2,- b,37.33,2.665,u,g,cc,v,0.165,f,f,0,t,g,00000,501,- a,20.83,8.5,u,g,c,v,0.165,f,f,0,f,g,00000,351,- b,24.08,9,u,g,aa,v,0.25,f,f,0,t,g,00000,0,- b,25.58,0.335,u,g,k,h,3.5,f,f,0,t,g,00340,0,- a,35.17,3.75,u,g,ff,ff,0,f,t,06,f,g,00000,200,- b,48.08,3.75,u,g,i,bb,1,f,f,0,f,g,00100,2,- a,15.83,7.625,u,g,q,v,0.125,f,t,01,t,g,00000,160,- a,22.50,0.415,u,g,i,v,0.335,f,f,0,t,s,00144,0,- b,21.50,11.5,u,g,i,v,0.5,t,f,0,t,g,00100,68,- a,23.58,0.83,u,g,q,v,0.415,f,t,01,t,g,00200,11,- a,21.08,5,y,p,ff,ff,0,f,f,0,f,g,00000,0,- b,25.67,3.25,u,g,c,h,2.29,f,t,01,t,g,00416,21,- a,38.92,1.665,u,g,aa,v,0.25,f,f,0,f,g,00000,390,- a,15.75,0.375,u,g,c,v,1,f,f,0,f,g,00120,18,- a,28.58,3.75,u,g,c,v,0.25,f,t,01,t,g,00040,154,- b,22.25,9,u,g,aa,v,0.085,f,f,0,f,g,00000,0,- b,29.83,3.5,u,g,c,v,0.165,f,f,0,f,g,00216,0,- a,23.50,1.5,u,g,w,v,0.875,f,f,0,t,g,00160,0,- b,32.08,4,y,p,cc,v,1.5,f,f,0,t,g,00120,0,- b,31.08,1.5,y,p,w,v,0.04,f,f,0,f,s,00160,0,- b,31.83,0.04,y,p,m,v,0.04,f,f,0,f,g,00000,0,- a,21.75,11.75,u,g,c,v,0.25,f,f,0,t,g,00180,0,- a,17.92,0.54,u,g,c,v,1.75,f,t,01,t,g,00080,5,- b,30.33,0.5,u,g,d,h,0.085,f,f,0,t,s,00252,0,- b,51.83,2.04,y,p,ff,ff,1.5,f,f,0,f,g,00120,1,- b,47.17,5.835,u,g,w,v,5.5,f,f,0,f,g,00465,150,- b,25.83,12.835,u,g,cc,v,0.5,f,f,0,f,g,00000,2,- a,50.25,0.835,u,g,aa,v,0.5,f,f,0,t,g,00240,117,- ?,29.50,2,y,p,e,h,2,f,f,0,f,g,00256,17,- a,37.33,2.5,u,g,i,h,0.21,f,f,0,f,g,00260,246,- a,41.58,1.04,u,g,aa,v,0.665,f,f,0,f,g,00240,237,- a,30.58,10.665,u,g,q,h,0.085,f,t,12,t,g,00129,3,- b,19.42,7.25,u,g,m,v,0.04,f,t,01,f,g,00100,1,- a,17.92,10.21,u,g,ff,ff,0,f,f,0,f,g,00000,50,- a,20.08,1.25,u,g,c,v,0,f,f,0,f,g,00000,0,- b,19.50,0.29,u,g,k,v,0.29,f,f,0,f,g,00280,364,- b,27.83,1,y,p,d,h,3,f,f,0,f,g,00176,537,- b,17.08,3.29,u,g,i,v,0.335,f,f,0,t,g,00140,2,- b,36.42,0.75,y,p,d,v,0.585,f,f,0,f,g,00240,3,- b,40.58,3.29,u,g,m,v,3.5,f,f,0,t,s,00400,0,- b,21.08,10.085,y,p,e,h,1.25,f,f,0,f,g,00260,0,- a,22.67,0.75,u,g,c,v,2,f,t,02,t,g,00200,394,- a,25.25,13.5,y,p,ff,ff,2,f,t,01,t,g,00200,1,- b,17.92,0.205,u,g,aa,v,0.04,f,f,0,f,g,00280,750,- b,35.00,3.375,u,g,c,h,8.29,f,f,0,t,g,00000,0,- @//E*O*F crx.test// chmod u=rw,g=,o= crx.test echo x - defns.i sed 's/^@//' > "defns.i" <<'@//E*O*F defns.i//' #include #include #include #include /******************************************************************************/ /* */ /* Type definitions, including synonyms for structure pointers */ /* */ /******************************************************************************/ typedef unsigned char Var; typedef char Boolean, Ordering; /* valid instances are <,=,>,# */ /* A tuple is stored as an array of int / fp. * T[0] = tuple number + POSMARK (pos tuples) * T[i] = constant number, or fp value NB: If continuous (fp) values are used, type Const must be the same size as float --if this is not the case, change Const to long. Relation tuple sets are indexed by 3D array. * I[i][j][k] = no. of kth tuple with T[j] = i The last entry is followed by FINISH */ typedef int Const, *Tuple; typedef int ***Index; typedef struct _rel_rec *Relation; typedef struct _type_rec *TypeInfo; typedef struct _state_rec State; typedef struct _lit_rec *Literal, **Clause; typedef struct _arg_ord_rec *ArgOrder; typedef struct _poss_lit_rec *PossibleLiteral; typedef struct _backup_rec *Alternative; typedef struct _var_rec *VarInfo; /******************************************************************************/ /* */ /* Structure definitions */ /* */ /******************************************************************************/ /* State */ /* A state represents information about the search for a new clause, including the tuples that satisfy the clause and various counts for the clause and the tuples */ struct _state_rec { int MaxVar, /* highest variable */ NPos, /* number of pos tuples */ NTot, /* number of all tuples */ NOrigPos, /* original pos tuples covered */ NOrigTot; /* original tuples covered */ Tuple *Tuples; /* training set */ float BaseInfo; /* information per pos tuple */ }; /* Literal */ struct _lit_rec { char Sign; /* 0=negated, 1=pos, 2=determinate */ Relation Rel; Var *Args; int WeakLits; /* value up to this literal */ Ordering *ArgOrders, /* recursive lits: =, <, >, # */ *SaveArgOrders; /* copy during pruning */ float Bits; /* encoding length */ }; /* Relation */ /* Note: Relations are represented by the (positive) tuples they contain; if the closed world assumption is not in force, negative tuples known not to be in the relation can be given explicitly. A key specifies a sensible way that a relation can be accessed by noting which arguments must have bound values. There can be any number of keys; if there are none, all possible ways of accessing the relation are ok. */ struct _rel_rec { char *Name; int Arity, /* number of arguments */ NKeys, /* number of keys (0=all ok) */ *Key, /* keys, each packed in an int */ *Type; /* types of arguments */ TypeInfo *TypeRef; /* redundant pointers to types */ Tuple *Pos, /* positive tuples */ *Neg; /* negative tuples or Nil (CWA) */ Index PosIndex, /* index for positive tuples */ NegIndex; /* ditto for explicit negative tuples */ int PosDuplicates, /* number of duplicate pos tuples*/ NTrialArgs, /* number of args to try (gain) */ NTried; /* number of them evaluated */ Clause *Def; /* definition is array of clauses */ Boolean BinSym, /* true for binary symmetric relns */ PossibleTarget, **PosOrder, /* argument order info for R() */ **NegOrder, /* " " " " ~R() */ *ArgNotEq; /* args that cannot be the same var (indexed by ArgPair) */ float Bits; /* current encoding cost */ }; /* Type */ struct _type_rec { char *Name; /* type name */ Boolean Continuous, /* continuous (non-discrete) */ Ordered, /* ordered discrete type */ FixedPolarity; int NValues, /* number of discrete constants */ NTheoryConsts; /* number of theory constants */ Const *Value, /* constants */ *TheoryConst; /* theory constants */ int *CollSeq; /* CollSeq[k] = x if (global) constant k is x'th const of this type */ }; /* Possible argument order -- used in discovering constant orders */ struct _arg_ord_rec { Relation Rel; /* relation */ Boolean Sign; /* sign */ int A1, A2, /* A1 < A2 or A1 > A2 */ In; /* 0, -1 (reverse) or +1 */ }; /* Structures used in backing up search */ struct _poss_lit_rec { Relation Rel; Boolean Sign; Var *Args; float Gain, Bits; int WeakLits, NewSize, TotCov, PosCov; }; struct _backup_rec { float Value; Clause UpToHere; }; /* Variables */ struct _var_rec { char *Name; int Type, Depth; TypeInfo TypeRef; }; #define FP(X) (*((float *)(&X))) /* The first four relations are predefined comparisons with aliased names defined here */ #define EQVAR Reln[0] /* var = var */ #define EQCONST Reln[1] /* var = theory const */ #define GTVAR Reln[2] /* var > var */ #define GTCONST Reln[3] /* var > threshold */ #define Predefined(R) (R==EQVAR||R==EQCONST||R==GTVAR||R==GTCONST) #define HasConst(R) (R==EQCONST||R==GTCONST) #define Verbose(x) if (VERBOSITY >= x) #define LN2 0.693147 #define Log2(x) (log((float) x)/LN2) #define Log2e 1.44269 #define Log2sqrt2Pi 1.32575 #define LogComb(n,r) (Log2Fact(n) - Log2Fact(r) - Log2Fact((n)-(r))) #define Except(n,e) ((n) ? (1.1*(Log2(n) + LogComb(n, e))) : 0.0) #define Encode(n) Except(AllTuples, n) #define Nil 0 #define false 0 #define true 1 #define Max(a,b) ( (a)>(b) ? a : b ) #define Min(a,b) ( (a)<(b) ? a : b ) #define ForEach(V,First,Last) for(V=First;V<=Last;V++) #define Mask 077777777 #define PosMark 0100000000 /* Max tuples = 16.7M */ #define Positive(T) ((T)[0]&PosMark) #define TrueBit 02 #define FalseBit 01 #define SetFlag(A,B) Flags[A] |= B #define TestFlag(A,B) (Flags[A] & B) #define ClearFlags memset(Flags,0,StartDef.NTot) #define BestLitGain (NPossible ? Possible[1]->Gain : 0.0) #define MonitorWeakLits(W) if (W) NWeakLits++; else NWeakLits=0 #define Plural(n) ((n) != 1 ? "s" : "") #define ReadToEOLN while ( getchar() != '\n' ) #define Alloc(N,T) (T *) pmalloc((N)*sizeof(T)) #define AllocZero(N,T) (T *) pcalloc(N, sizeof(T)) #define Realloc(V,N,T) V = (T *) prealloc(V, (N)*sizeof(T)) #define MissingValue(R,A,X) (MissingVals && MissingVal(R,A,X)) #define ungetchar(A) ungetc(A, stdin) #define ArgPair(A2,A1) (((A2-1)*(A2-2))/2 + A1-1) /* The following are used to pack and unpack parameters into argument lists. AV must be the address of an int or float */ #define SaveParam(A,AV) memcpy(A,AV,sizeof(Const)) #define GetParam(A,AV) memcpy(AV,A,sizeof(Const)) /******************************************************************************/ /* */ /* Various constants */ /* */ /******************************************************************************/ #define FINISH 10000000 /* large constant used as a terminator */ #define UNBOUND 0357357 /* odd marker used in interpret.c, join.c */ #define MISSING_DISC 1 /* missing value "?" is the first constant */ #define MISSING_FP 0.03125 /* arbitrary number used as the floating point equivalent of MISSING_DISC - if it clashes with a genuine data value, just change this */ #define OUT_OF_RANGE 2 /* denotes constant outside closed world */ /******************************************************************************/ /* */ /* Synopsis of functions */ /* */ /******************************************************************************/ /* main.c */ void main(int Argc, char *Argv[]); /* utility.c */ void *pmalloc(unsigned arg); void *prealloc(void * arg1, unsigned arg2); void *pcalloc(unsigned arg1, unsigned arg2); void pfree(void *arg); float CPUTime(); /* input.c */ Boolean ReadType(); void ReadTypes(); Tuple ReadTuple(Relation R); Tuple *ReadTuples(Relation R, Boolean Pos); Relation ReadRelation(); void ReadRelations(); int FindType(char *N); char *CopyString(char *s); void Error(); void DuplicateTuplesCheck(Relation R); int CountDuplicates(Tuple *T, int N, int Left, int Right); Boolean SymmetryCheck(Relation R); char ReadName(char *s); Const FindConstant(char *N, Boolean MustBeThere); int Number(Tuple *T); void CheckTypeCompatibility(); Boolean CommonValue(int N1, Const *V1, int N2, Const *V2); Index MakeIndex(Tuple *T, int N, Relation R); void UnequalArgsCheck(Relation R); Boolean NeverEqual(Tuple *T, Var F, Var S); /* output.c */ void PrintTuple(Tuple C, int N, TypeInfo *TypeRef, Boolean ShowPosNeg); void PrintTuples(Tuple *TT, int N); void PrintSpecialLiteral(Relation R, Boolean RSign, Var *A); void PrintComposedLiteral(Relation R, Boolean RSign, Var *A); void PrintLiteral(Literal L); void PrintClause(Relation R, Clause C); void PrintSimplifiedClause(Relation R, Clause C); void Substitute(char *Old, char *New); void PrintDefinition(Relation R); /* literal.c */ void ExploreArgs(Relation R, Boolean CountFlag); Boolean AcceptableKey(Relation R, int Key); Boolean Repetitious(Relation R, Var *A); Boolean SameArgs(int N, Var *A1, int MV1, Var *A2, int MV2, int LitN); void ExploreEQVAR(); void ExploreEQCONST(); void ExploreGTVAR(); void ExploreGTCONST(); Boolean TryArgs(Relation R, int This, int HiVar, int FreeVars, int MaxDepth, int Key, Boolean TryMostGeneral, Boolean RecOK); int EstimatePossibleArgs(int TNo); /* evaluatelit.c */ void EvaluateLiteral(Relation R, Var *A, float LitBits, Boolean *Prune); void PrepareForScan(Relation R, Var *A); float NegThresh(int P, int P1); Boolean TerminateScan(Relation R, Var *A); Boolean Satisfies(int RN, Const V, Const W, Tuple Case); void CheckForPrune(Relation R, Var *A); void CheckNewVars(Tuple Case); float Worth(int N, int P, int T, int UV); float Info(int P, int T); Boolean MissingVal(Relation R, Var *A, Tuple T); Boolean Unknown(Var V, Tuple T); void FindThreshold(Var *A); void PossibleCut(float C); int MissingAndSort(Var V, int Fp, int Lp); void Quicksort(Tuple *Vec, int Fp, int Lp, Var V); /* join.c */ Boolean Join(Tuple *T, Index TIX, Var *A, Tuple C, int N, Boolean YesOrNo); /* state.c */ void OriginalState(Relation R); void AddTuple(int N, Tuple T, int ByteSize, int Mark); Tuple NextConstTuple(Relation R, Tuple Case); void RandomTuple(Relation R, Tuple Result); void NewState(Literal L, int NewSize); void FormNewState(Relation R, Boolean RSign, Var *A, int NewSize); void AcceptNewState(Relation R, Var *A, int NewSize); void RecoverState(Clause C); void CheckSize(int SoFar, int Extra, int *NewSize, Tuple **TSAddr); Tuple Extend(Tuple Case, Tuple Binding, Var *A, int N); void CheckOriginalCaseCover(); void FreeTuples(Tuple *TT, Boolean TuplesToo); double Log2Fact(int n); /* determinate.c */ Boolean GoodDeterminateLiteral(Relation R, Var *A, float LitBits); void ProcessDeterminateLiterals(Boolean AllWeak); Boolean SameVar(Var A, Var B); void ShiftVarsDown(int s); /* search.c */ void ProposeLiteral(Relation R, Boolean TF, Var *A, int Size, float LitBits, int OPos, int OTot, float Gain, Boolean Weak); Boolean Recover(); void Remember(Literal L, int OPos, int OTot); Literal MakeLiteral(int i); Literal SelectLiteral(); void FreeLiteral(Literal L); void FreeClause(Clause C); /* order.c */ void ExamineVariableRelationships(); Boolean RecursiveCallOK(Var *A); void AddOrders(Literal L); void NoteRecursiveLit(Literal L); /* finddef.c */ void FindDefinition(Relation R); Clause FindClause(); void ExamineLiterals(); void GrowNewClause(); Boolean SameLiteral(Relation R, Boolean Sign, Var *A); Boolean AllLHSVars(Literal L); Boolean AllDeterminate(); float CodingCost(Clause C); /* prune.c */ void PruneNewClause(); void CheckVariables(); Boolean TheoryConstant(Const C, TypeInfo T); Boolean ConstantVar(Var V, Const C); Boolean IdenticalVars(Var V, Var W); Boolean Known(Relation R, Var V, Var W); void Insert(Var V, Relation R, Var A1, Const A2); Boolean Contains(Var *A, int N, Var V); Boolean QuickPrune(Clause C, Var MaxBound, Boolean *Used); Boolean SatisfactoryNewClause(int Errs); void RenameVariables(); Boolean RedundantLiterals(int ErrsNow); Boolean EssentialBinding(int LitNo); void ReplaceVariable(Var Old, Var New); void SiftClauses(); Var HighestVarInDefinition(Relation R); Boolean Recursive(Clause C); /* interpret.c */ Boolean CheckRHS(Clause C); Boolean Interpret(Relation R, Tuple Case); void InitialiseValues(Tuple Case, int N); /* constants.c */ void OrderConstants(); void FindArgumentOrders(); void ExamineArgumentPairs(Relation R, Boolean Sign, Tuple *TP); Boolean ConsistentClosure(Boolean **Table, Tuple *TP, Var A, Var B); Boolean AddPair(Boolean **Table, int A, int B); void AddArgOrder(Relation R, Boolean Sig, int A1, int A2); Boolean **AllocatePartOrd(int Size); void FreePartOrd(Boolean **PO, int Size); void ClearPartOrd(Boolean **PO); void FindConsistentSubset(int Included, int TryNext, Boolean **PO); int CountEntries(int K); @//E*O*F defns.i// chmod u=rw,g=,o= defns.i echo x - determinate.c sed 's/^@//' > "determinate.c" <<'@//E*O*F determinate.c//' /******************************************************************************/ /* */ /* Routines for processing determinate literals */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" Boolean GoodDeterminateLiteral(Relation R, Var *A, float LitBits) /* ---------------------- */ { int MaxSoFar, PreviousMax, This, i, j; Var V; Literal L; Boolean SensibleBinding=false; /* See whether this determinate literal's bound variables were all bound by determinate literals on the same relation */ ForEach(j, 1, R->Arity) { SensibleBinding |= ( A[j] <= Target->Arity ); } MaxSoFar = Target->Arity; for ( i = 0 ; ! SensibleBinding && i < NLit ; i++ ) { if ( ! NewClause[i]->Sign ) continue; PreviousMax = MaxSoFar; ForEach(j, 1, NewClause[i]->Rel->Arity) { if ( (V = NewClause[i]->Args[j]) > MaxSoFar ) MaxSoFar = V; } if ( NewClause[i]->Rel != R || NewClause[i]->Sign != 2 ) { ForEach(j, 1, R->Arity) { SensibleBinding |= ( A[j] <= MaxSoFar && A[j] > PreviousMax ); } } } if ( ! SensibleBinding ) { Verbose(3) { printf("\tall vars bound by determinate lits on same relation\n"); } return false; } /* Record this determinate literal */ This = NLit + NDeterminate; if ( This && This%100 == 0 ) { Realloc(NewClause, This+100, Literal); } L = NewClause[This] = AllocZero(1, struct _lit_rec); L->Rel = R; L->Sign = 2; L->Bits = LitBits; L->Args = Alloc(R->Arity+1, Var); memcpy(L->Args, A, (R->Arity+1)*sizeof(Var)); NDeterminate++; return true; } void ProcessDeterminateLiterals(Boolean AllWeak) /* -------------------------- */ { int PrevMaxVar, i, j, l, m; Literal L; Var V; Boolean Unique, Changed; PrevMaxVar = Current.MaxVar; Verbose(1) printf("\nDeterminate literals\n"); ForEach(l, 1, NDeterminate) { L = NewClause[NLit++]; Verbose(1) { putchar('\t'); PrintLiteral(L); } Changed = PrevMaxVar != Current.MaxVar; /* Rename free variables */ ForEach(i, 1, L->Rel->Arity) { if ( L->Args[i] > PrevMaxVar ) { L->Args[i] += Current.MaxVar - PrevMaxVar; if ( L->Args[i] > MAXVARS ) { Verbose(1) printf("\t\tno more variables\n"); NLit--; MonitorWeakLits(AllWeak); return; } } } if ( Changed ) { Verbose(1) { printf(" ->"); PrintLiteral(L); } Changed = false; } if ( L->Rel == Target ) AddOrders(L); FormNewState(L->Rel, true, L->Args, Current.NTot); /* Verify that new variables introduced by this determinate literal don't replicate new variables introduced by previous determinate literals. [Note: new variables checked against old variables in EvaluateLiteral() ] */ for ( i = Current.MaxVar+1 ; i <= New.MaxVar ; ) { Unique = true; for ( j = PrevMaxVar+1 ; Unique && j <= Current.MaxVar ; j++ ) { Unique = ! SameVar(i, j); } if ( Unique ) { i++; } else { j--; Verbose(1) { printf(" %s=%s", Variable[i]->Name, Variable[j]->Name); } ShiftVarsDown(i); ForEach(V, 1, L->Rel->Arity) { if ( L->Args[V] == i ) L->Args[V] = j; else if ( L->Args[V] > i ) L->Args[V]--; } Changed = true; } } /* If no variables remain, delete this literal */ if ( Current.MaxVar == New.MaxVar ) { Verbose(1) printf(" (no new vars)"); NLit--; ForEach(m, 1, NDeterminate-l) { NewClause[NLit+m-1] = NewClause[NLit+m]; } FreeTuples(New.Tuples, true); } else { /* This determinate Literal is being kept in the clause */ if ( Changed ) { Verbose(1) { printf(" ->"); PrintLiteral(L); } } AcceptNewState(L->Rel, L->Args, Current.NTot); NDetLits++; if ( L->Rel == Target ) NoteRecursiveLit(L); } Verbose(1) putchar('\n'); } MonitorWeakLits(AllWeak); } /* See whether variable a is always the same as variable b in all positive tuples of the new state */ Boolean SameVar(Var A, Var B) /* ------- */ { Tuple *TSP, Case; for ( TSP = New.Tuples ; Case = *TSP++; ) { if ( Positive(Case) && Case[A] != Case[B] ) return false; } /* If same, delete any negative tuples where different */ for ( TSP = New.Tuples ; Case = *TSP; ) { if ( ! Positive(Case) && Case[A] != Case[B] ) { *TSP = New.Tuples[New.NTot-1]; New.NTot--; New.Tuples[New.NTot] = Nil; } else { TSP++; } } return true; } void ShiftVarsDown(int s) /* ------------- */ { Tuple *TSP, Case; Var V; New.MaxVar--; for ( TSP = New.Tuples ; Case = *TSP++ ; ) { ForEach(V, s, New.MaxVar) { Case[V] = Case[V+1]; } } ForEach(V, s, New.MaxVar) { Variable[V]->Type = Variable[V+1]->Type; Variable[V]->TypeRef = Variable[V+1]->TypeRef; } } @//E*O*F determinate.c// chmod u=rw,g=,o= determinate.c echo x - evaluatelit.c sed 's/^@//' > "evaluatelit.c" <<'@//E*O*F evaluatelit.c//' /******************************************************************************/ /* */ /* This group of routines has responsibility for evaluating a proposed */ /* literal. There are many aspects that are checked simultaneously: */ /* */ /* * whether the literal is determinate */ /* * whether this literal would result in a completed clause */ /* * whether this literal would produce too many tuples */ /* * pruning, both of this literal and of any specialisations of it */ /* * new variables that duplicate existing variables */ /* - for all tuples */ /* - for pos tuples (determinate literals) */ /* * all new variables being bound to constants on pos tuples */ /* * gain computation (including weak literal sequence check) */ /* * adjusting records of best literals so far */ /* */ /* The principles underlying this routine are: */ /* */ /* * No literal may introduce a variable that duplicates an existing */ /* variable (since the same effect could be obtained with a more */ /* specific literal). */ /* * No determinate literal may introduce a new variable that is */ /* the same as an existing variable on pos tuples (since the more */ /* specific literal would also be determinate). */ /* * Exploration of a literal can cease as soon as it is clear that */ /* the literal will not be used. In some cases, it is also possible*/ /* to exclude other literals subsumed by this. Such pruning is */ /* tied to the calculation of gain and determinacy, and would need */ /* to be altered if these are changed. */ /* */ /* The various counts have components with the following meanings: */ /* */ /* Pos pos tuples */ /* Neg neg tuples */ /* Tot all tuples */ /* */ /* T pertaining to the unnegated literal R(A) */ /* F pertaining to ~R(A) */ /* M missing value (so neither) */ /* */ /* Now number of tuples in current state */ /* Orig number of tuples in original state */ /* New referring to state if use R(A) or ~R(A) */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" int OrigTPos, /* orig pos tuples with extensions, R(A) */ OrigTTot, OrigFPos, /* ditto, ~R(A) */ OrigFTot, NowTPos, /* current pos tuples with extensions, R(A) */ NowTTot, NowFPos, /* ditto, ~R(A); NewFPos is identical */ NowFNeg, NowFTot, /* calculated for brevity at end */ NowMPos, /* pos tuples with missing values */ NowMTot, /* pos tuples with missing values */ NewTPos, /* pos tuples in new state, R(A) */ NewTTot, NNewVars, /* number of unbound vars in R(A) */ NConstVars, /* number of constant pseudo-vars */ NDuplicateVars, /* number of duplications so far */ NArgs, /* number of relation arguments */ BestCover, /* coverage of best saveable clause */ MinSaveableCover, /* min coverage if clause saveable */ MaxFPos, PossibleCuts; Var *OldVar, /* old var possibly equal to a new var */ *NewVarPosn, /* argument number of new var */ *ConstVarPosn; /* new vars with unchanging values */ Tuple FirstBinding; /* check for consts masquerading as new vars */ Boolean Allocate = true, NegatedLiteralOK, /* ~R(A) permissible */ *DifferOnNegs, /* corresponding pair not identical */ *FirstOccurrence, /* first time variable appears in args */ PossibleT, /* R(A) is a candidate */ PossibleF, /* ~R(A) is a candidate */ Determinate; /* R(A) is determinate */ float MinUsefulGain, /* min gain to affect outcome */ MinPos, /* min pos tuples to achieve MinUsefulGain */ BestAccuracy, /* accuracy of best saveable clause */ MaxFNeg, /* max FNeg tuples to avoid pruning ~R(A) */ NewClauseBits; /* if add literal to clause */ /* Examine literals R(A) and ~R(A) (if appropriate) */ void EvaluateLiteral(Relation R, Var *A, float LitBits, Boolean *Prune) /* --------------- */ { Boolean Abandoned, RealDuplicateVars=false, WeakT, WeakF, SavedSign; Var V, W; int i, j, Coverage, Size; float PosGain, NegGain, Gain, CurrentRatio, Accuracy, Extra; Verbose(3) { putchar('\t'); PrintComposedLiteral(R, true, A); } if ( Prune ) *Prune = false; Extra = LitBits - Log2(NLit+1.001-NDetLits); NewClauseBits = ClauseBits + Max(0, Extra); PrepareForScan(R, A); if ( R == GTCONST ) { /* Find best threshold and counts in one go */ FindThreshold(A); if ( PossibleCuts > 0 ) LitBits += Log2(PossibleCuts); Determinate = Abandoned = false; NDuplicateVars = NConstVars = 0; } else if ( (Abandoned = TerminateScan(R, A)) && NewTTot <= MAXTUPLES /* not because out of room for tuples */ && NNewVars /* new vars, so potential for pruning */ && Current.NPos - (NowFPos+NowMPos) < MinPos /* R(A) has insuff gain */ ) { /* Check for possible pruning of more specific literals */ if ( NegatedLiteralOK ) { /* A more specific ~R(A) will match more tuples. In order to prune, we must be sure that the current ~R(A) matches enough neg tuples to ensure that the gain is not interesting. Assume all pos tuples other than those known to have missing values would be matched by a more specific ~R(A) */ MaxFPos = Current.NPos - NowMPos; MaxFNeg = NegThresh(MaxFPos, MaxFPos); CheckForPrune(R, A); *Prune = NowFNeg > MaxFNeg; } else { /* Can prune only when a more specific literal than R(A) could not be saveable */ *Prune = OrigTPos < MinSaveableCover; } } NowFTot = NowFPos + NowFNeg; PossibleT &= NowTPos > 0; PossibleF &= NowFPos > 0; Verbose(3) { printf(" %d[%d/%d]", NowTPos, NewTPos, NewTTot); if ( NegatedLiteralOK || Abandoned ) { printf(" [%d/%d]", NowFPos, NowFTot); } printf(" "); } if ( Abandoned ) { Verbose(3) { printf(" abandoned"); if ( OutOfWorld ) printf(" ^"); printf("(%d%%)\n", (100 * (NowTTot+NowFTot+NowMTot)) / Current.NTot); } return; } ForEach(i, 0, NDuplicateVars-1) { V = A[ NewVarPosn[i] ]; W = OldVar[i]; if ( W > Current.MaxVar ) W = A[ W-Current.MaxVar ]; /* special */ if ( NowTPos || ! DifferOnNegs[i] ) { Verbose(3) printf(" %s%s%s", Variable[W]->Name, ( DifferOnNegs[i] ? "=+" : "=" ), Variable[V]->Name); } RealDuplicateVars |= ! DifferOnNegs[i]; } Verbose(3) { if ( NewTPos > 1 ) { ForEach(i, 0, NConstVars-1) { V = A[ j=ConstVarPosn[i] ]; printf(" %s=", Variable[V]->Name); if ( Variable[V]->TypeRef->Continuous ) { printf("%g", FP(FirstBinding[j])); } else { printf("%s", ConstName[FirstBinding[j]]); } } } } if ( Determinate ) { /* Check whether determinacy has been violated */ Determinate = ! NDuplicateVars && NConstVars < NNewVars; Verbose(3) printf(" [%s]", Determinate ? "Det" : "XDet"); } /* Now assess gain if applicable. Any literal that introduces a duplicate variable is unacceptable (the more specific literal would give the same result. A literal R(A) that introduces a new variable that replicates an existing variable on pos tuples is also excluded -- the more specific literal would match the same number of pos tuples and perhaps fewer neg tuples */ PossibleT &= ! NDuplicateVars; if ( RealDuplicateVars || ( ! PossibleT && ! PossibleF ) ) { Verbose(3) printf(" #\n"); return; } /* Due to arithmetic roundoff, ratios rather than gain are used to detect weak literals */ CurrentRatio = Current.NPos/(float) Current.NTot; if ( PossibleT ) { if ( OrigTPos == OrigTTot && OrigTPos == StartClause.NPos ) { PosGain = MaxPossibleGain; } else { PosGain = Worth(NowTPos, NewTPos, NewTTot, NNewVars-NConstVars); } WeakT = NowFTot <= 0 || NewTPos / (NewTTot+1E-3) <= 0.9999 * CurrentRatio; } else { PosGain = 0.0; } if ( PossibleF ) { if ( OrigFPos == OrigFTot && OrigFPos == StartClause.NPos ) { NegGain = MaxPossibleGain; } else { NegGain = Worth(NowFPos, NowFPos, NowFTot, 0); } WeakF = NowTTot <= 0 || NowFPos / (NowFTot+1E-3) <= 0.9999 * CurrentRatio; } else { NegGain = 0.0; } Verbose(3) { printf(" gain %.1f", PosGain); if ( NegatedLiteralOK ) printf(",%.1f", NegGain); } /* Weak literal sequence check */ if ( NWeakLits >= MAXWEAKLITS && ! Determinate && ( ! PossibleT || WeakT ) && ( ! PossibleF || WeakF ) ) { Verbose(3) printf(" (weak)\n"); return; } Verbose(3) putchar('\n'); /* Would the addition of this literal to the clause create the best saved clause so far? */ if ( PossibleT && ( ! PossibleF || OrigTPos / (float) OrigTTot > OrigFPos / (float) OrigFTot ) ) { SavedSign = 1; Accuracy = OrigTPos / (float) OrigTTot; Coverage = OrigTPos; } else if ( PossibleF ) { SavedSign = 0; Accuracy = OrigFPos / (float) OrigFTot; Coverage = OrigFPos; } else { Accuracy = 0; } if ( Accuracy >= AdjMinAccuracy-1E-3 && ( Accuracy > BestAccuracy || Accuracy == BestAccuracy && Coverage > BestCover ) ) { if ( ! AlterSavedClause ) { AlterSavedClause = AllocZero(1, struct _poss_lit_rec); } AlterSavedClause->Rel = R; AlterSavedClause->Sign = SavedSign; AlterSavedClause->Bits = LitBits; AlterSavedClause->WeakLits = 0; AlterSavedClause->TotCov = ( SavedSign ? OrigTTot : OrigFTot ); AlterSavedClause->PosCov = ( SavedSign ? OrigTPos : OrigFPos ); Size = R->Arity+1; if ( HasConst(R) ) Size += sizeof(Const) / sizeof(Var); AlterSavedClause->Args = Alloc(Size, Var); memcpy(AlterSavedClause->Args, A, Size*sizeof(Var)); } /* Compute gains and save if appropriate */ Gain = Max(PosGain, NegGain); if ( Determinate && Gain < DETERMINATE * MaxPossibleGain && GoodDeterminateLiteral(R, A, LitBits) ) { return; } if ( PosGain > 1E-3 && ( ! SavedClause || SavedClauseAccuracy < .999 || ! WeakT ) ) { ProposeLiteral(R, true, A, NowTTot, LitBits, OrigTPos, OrigTTot, PosGain, WeakT); } if ( NegGain > 1E-3 && ( ! SavedClause || SavedClauseAccuracy < .999 || ! WeakF ) ) { ProposeLiteral(R, false, A, NowFTot, LitBits, OrigFPos, OrigFTot, NegGain, WeakF); } } /* Initialise variables for scan. NOTE: this assumes that Current.BaseInfo and MaxPossibleGain have been set externally. */ void PrepareForScan(Relation R, Var *A) /* -------------- */ { int i, j, PossibleVarComps; Var V, W, VP; /* First time through, allocate arrays */ if ( Allocate ) { Allocate = false; PossibleVarComps = MAXARGS * MAXVARS + (MAXARGS * (MAXARGS-1) / 2); OldVar = Alloc(PossibleVarComps, Var); NewVarPosn = Alloc(PossibleVarComps, Var); ConstVarPosn = Alloc(MAXARGS+1, Var); DifferOnNegs = Alloc((MAXARGS+1)*(MAXVARS+1), Boolean); FirstOccurrence = Alloc(MAXVARS+MAXARGS, Boolean); FirstBinding = Alloc(MAXARGS+1, Const); } OrigTPos = 0; OrigTTot = 0; OrigFPos = 0; OrigFTot = 0; NowTPos = 0; NowTTot = 0; NowFPos = 0; NowFNeg = 0; NowMPos = 0; NowMTot = 0; NewTPos = 0; NewTTot = 0; NDuplicateVars = NNewVars = NConstVars = 0; NArgs = R->Arity; memset(FirstOccurrence, true, Current.MaxVar+NArgs); OutOfWorld = false; ForEach(i, 1, NArgs) { if ( (V = A[i]) > Current.MaxVar && FirstOccurrence[V] ) { NNewVars++; FirstOccurrence[V] = false; ConstVarPosn[NConstVars++] = i; ForEach(W, 1, Current.MaxVar) { if ( ! Compatible[Variable[W]->Type][R->Type[i]] ) continue; NewVarPosn[NDuplicateVars] = i; OldVar[NDuplicateVars] = W; DifferOnNegs[NDuplicateVars] = false; NDuplicateVars++; } } } /* New variables shouldn't replicate each other, either */ ForEach(i, 0, NConstVars-2) { VP = ConstVarPosn[i]; V = A[VP]; ForEach(j, i+1, NConstVars-1) { W = ConstVarPosn[j]; if ( ! Compatible[Variable[V]->Type][R->Type[W]] ) continue; NewVarPosn[NDuplicateVars] = W; OldVar[NDuplicateVars] = Current.MaxVar+VP; /* special */ DifferOnNegs[NDuplicateVars] = false; NDuplicateVars++; } } ClearFlags; PossibleT = true; PossibleF = NegatedLiteralOK = ( NEGLITERALS || R == GTVAR || R == GTCONST || ( NEGEQUALS && ( R == EQVAR || R == EQCONST ) ) ); Determinate = NNewVars > 0; /* The minimum gain that would be of interest is just enough to give a literal a chance to be saved by the backup procedure or, if there are determinate literals, to reach the required fraction of the maximum possible gain */ MinUsefulGain = NPossible < MAXPOSSLIT ? MINALTFRAC * BestLitGain : Max(Possible[MAXPOSSLIT]->Gain, MINALTFRAC * BestLitGain); if ( NDeterminate && MinUsefulGain < DETERMINATE * MaxPossibleGain ) { MinUsefulGain = DETERMINATE * MaxPossibleGain; } /* Set thresholds for pos tuples */ MinPos = MinUsefulGain / Current.BaseInfo - 0.001; /* Now check coverage required for a saveable clause that would pass the MDL criterion. Don't worry about long saveable clauses. */ if ( AlterSavedClause ) { BestCover = AlterSavedClause->PosCov; BestAccuracy = BestCover / (float) AlterSavedClause->TotCov; } else { BestCover = SavedClauseCover; BestAccuracy = SavedClauseAccuracy; } if ( NLit < 5 ) { MinSaveableCover = BestCover+1; while ( Encode(MinSaveableCover) <= NewClauseBits ) MinSaveableCover++; } else { MinSaveableCover = StartDef.NPos; } } /* Make a pass through the tuples, terminating if it becomes clear that neither R(A) or ~R(A) can achieve the minimum useful gain. Since all pos tuples appear first in the tuple sets, thresholds for NewTNeg and NowFNeg can be set when the first neg tuple is encountered. */ #define TermTest(Cond, Test)\ if ( Cond && Test && ! Determinate ) {\ Cond = false; if ( ! PossibleT && ! PossibleF ) return true; } Boolean TerminateScan(Relation R, Var *A) /* ------------- */ { Tuple *TSP, Case; Boolean BuiltIn=false, FirstNegTuple=true; int RN, MaxCover, OrigPos=0; Const X2; float NewTNegThresh, NowFNegThresh; if ( Predefined(R) ) { BuiltIn = true; RN = (int) R->Pos; if ( HasConst(R) ) { GetParam(&A[2], &X2); } else { X2 = A[2]; } } for ( TSP = Current.Tuples ; Case = *TSP++ ; ) { if ( FirstNegTuple && ! Positive(Case) ) { /* Encoding length checks */ PossibleT &= Encode(OrigTPos) > NewClauseBits; PossibleF &= Encode(OrigFPos) > NewClauseBits; if ( ! PossibleT && ! PossibleF ) { Verbose(3) { printf(" MDL prune %d,%d", OrigTPos, OrigFPos); } return true; } /* Set thresholds now that NowTPos and NowFPos are known */ NewTNegThresh = ( NNewVars && BestLitGain < 1E-2 ? MAXTUPLES : NegThresh(NowTPos, NewTPos) ); NowFNegThresh = NegThresh(NowFPos, NowFPos); FirstNegTuple = false; } if ( MissingValue(R, A, Case) ) { NowMTot++; if ( Positive(Case) ) NowMPos++; NFound = 0; } else if ( BuiltIn ? Satisfies(RN, A[1], X2, Case) : Join(R->Pos, R->PosIndex, A, Case, NArgs, false) ) { /* R(A) is barred if it would introduce an out-of-world constant. Note: can't use TermTest() since check for Determinate does not matter */ if ( OutOfWorld ) { PossibleT = false; if ( ! PossibleF ) return true; } /* Extensions of this tuple from R(A) */ CheckNewVars(Case); NowTTot++; NewTTot += NFound; TermTest(PossibleT, NewTTot > MAXTUPLES); if ( Positive(Case) ) { NowTPos++; NewTPos += NFound; /* If all remaining pos tuples go to NowFPos, are there sufficient to make ~R(A) viable? Note: do not abandon ~R(A) if it could lead to a saveable clause (assuming all remaining original pos tuples are covered by ~R(A)) */ MaxCover = OrigFPos + (Current.NOrigPos - OrigPos); if ( MaxCover < MinSaveableCover ) { TermTest(PossibleF, Current.NPos - (NowTPos + NowMPos) < MinPos-1E-3); } } else { /* We already know the final number of NewTPos tuples. Are there now enough NewTNeg tuples to make the gain of R(A) insufficient? (Note: since R(A) matches a neg tuple, don't have to worry about saveable clause.) */ TermTest(PossibleT, (NewTTot - NewTPos) > NewTNegThresh+1E-3); } if ( ! TestFlag(Case[0]&Mask, TrueBit) ) { SetFlag(Case[0]&Mask, TrueBit); OrigTTot++; if ( Positive(Case) ) { OrigTPos++; if ( ! TestFlag(Case[0]&Mask, FalseBit) ) OrigPos++; } } } else { if ( Positive(Case) ) { NowFPos++; /* If all remaining pos tuples go to NowTPos, are there sufficient to make R(A) viable? Note: don't kill R(A) if it could lead to a saveable clause when all remaining original pos tuples covered by R(A) */ MaxCover = OrigTPos + (Current.NOrigPos - OrigPos); if ( MaxCover < MinSaveableCover ) { TermTest(PossibleT, Current.NPos - (NowFPos + NowMPos) < MinPos-1E-3); } } else { NowFNeg++; /* We already know the final number of NowFPos tuples. Are there already enough NowFNeg tuples to make the gain of ~R(A) insufficient? (As above saveability not relevant.) */ TermTest(PossibleF, NowFNeg > NowFNegThresh+1E-3); } if ( ! TestFlag(Case[0]&Mask, FalseBit) ) { SetFlag(Case[0]&Mask, FalseBit); OrigFTot++; if ( Positive(Case) ) { OrigFPos++; if ( ! TestFlag(Case[0]&Mask, TrueBit) ) OrigPos++; } } } Determinate &= ( Positive(Case) ? NFound == 1 : NFound <= 1 ); } return false; } /* If there are unbound variables, try to satisfy the pruning criterion for more specific literals. A more specific negated literal will cover more tuples; NowFNeg must be great enough so that, if all positive tuples were covered by ~R(A), the gain would still be too low. */ void CheckForPrune(Relation R, Var *A) /* ------------- */ { Tuple *TSP, Case; int RemainingNeg; RemainingNeg = (Current.NTot - Current.NPos) - (NowMTot - NowMPos) - (NowTTot - NowTPos) - NowFNeg; for ( TSP = Current.Tuples + (NowMTot+NowTTot+NowFPos+NowFNeg) ; Case = *TSP++ ; ) { if ( Positive(Case) || MissingValue(R, A, Case) ) { continue; } if ( ! Join(R->Pos, R->PosIndex, A, Case, NArgs, true) ) { NowFNeg++; /* See if have found enough */ if ( NowFNeg > MaxFNeg ) break; } RemainingNeg--; /* See whether not enough left */ if ( NowFNeg + RemainingNeg <= MaxFNeg ) break; } } /* Check new variables for non-utility, specifically * replicating existing variables on all or pos tuples * all being bound to constants on pos tuples */ void CheckNewVars(Tuple Case) /* ------------ */ { Var P; Const OldVarVal; int i, j, Col; for ( i = 0 ; i < NDuplicateVars ; i++ ) { if ( ! Positive(Case) && DifferOnNegs[i] ) continue; P = OldVar[i]; if ( P <= Current.MaxVar ) OldVarVal = Case[P]; Col = NewVarPosn[i]; for ( j = 0 ; j < NFound ; j++ ) { if ( Found[j][Col] == ( P <= Current.MaxVar ? OldVarVal : Found[j][P-Current.MaxVar] ) ) { continue; } if ( Positive(Case) ) { NDuplicateVars--; for ( j = i ; j < NDuplicateVars ; j++ ) { NewVarPosn[j] = NewVarPosn[j+1]; OldVar[j] = OldVar[j+1]; DifferOnNegs[j] = DifferOnNegs[j+1]; } i--; } else { DifferOnNegs[i] = true; } break; } } /* Check for new vars bound to constants */ if ( NConstVars ) { if ( ! NowTTot ) { memcpy(FirstBinding, Found[0], (NArgs+1)*sizeof(Const)); } ForEach(i, 0, NConstVars-1) { Col = ConstVarPosn[i]; for ( j = 0 ; j < NFound ; j++ ) { if ( FirstBinding[Col] == Found[j][Col] ) continue; NConstVars--; for ( j = i ; j < NConstVars ; j++ ) { ConstVarPosn[j] = ConstVarPosn[j+1]; } i--; break; } } } } /* Compute the maximum number N1 of neg tuples that would allow P1 pos tuples (P orig pos tuples) to give a gain >= threshold. The underlying relation is P * (Current.BaseInfo + log(P1/(P1+N1)) >= MinUsefulGain where N1 is adjusted by the sampling factor. NOTE: This is the inverse of the gain calculation in Worth. If one is changed, the other must be modified accordingly */ float NegThresh(int P, int P1) /* --------- */ { return P <= 0 ? 0.0 : SAMPLE * (P1+1) * (exp(LN2 * (Current.BaseInfo - MinUsefulGain/P)) - 1); } /* Compute aggregate gain from a test on relation R, tuple T. The Basic gain is the number of positive tuples * information gained regarding each; but there is a minor adjustment: - a literal that has some positive tuples and no gain but introduces one or more new variables, is given a slight gain */ float Worth(int N, int P, int T, int UV) /* ----- */ { float G, TG; TG = N * (G = Current.BaseInfo - Info(P, T)); if ( G < 1E-3 && N && UV ) { return 0.0009 + UV * 0.0001; /* very small notional gain */ } else { return TG; } } /* The ratio P/T is tweaked slightly to (P+1)/(T+1) so that, if two sets of tuples have the same proportion of pos tuples, the smaller is preferred. The reasoning is that it is easier to filter out all neg tuples from a smaller set. If you don't like this idea and change it back to P/T, NegThresh must be changed also */ float Info(int P, int T) /* ---- */ { /* Adjust total T to take account of sampling */ T = (int)((float)(T-P) / SAMPLE) + P; return Log2(T+1) - Log2(P+1); } Boolean MissingVal(Relation R, Var *A, Tuple T) /* ---------- */ { register Var i, V; ForEach(i, 1, R->Arity) { V = A[i]; if ( V <= Current.MaxVar && Unknown(V, T) ) return true; } return false; } Boolean Unknown(Var V, Tuple T) /* ------- */ { return ( Variable[V]->TypeRef->Continuous ? FP(T[V]) == MISSING_FP : T[V] == MISSING_DISC ); } /* See whether a case satisfies built-in relation RN */ Boolean Satisfies(int RN, Const V, Const W, Tuple Case) /* --------- */ { switch ( RN ) { case 0: /* EQVAR */ NFound = ( Case[V] == Case[W] ); break; case 1: /* EQCONST */ NFound = ( Case[V] == W ); break; case 2: /* GTVAR */ NFound = ( FP(Case[V]) > FP(Case[W]) ); break; case 3: /* GTCONST */ NFound = ( FP(Case[V]) > FP(W) ); break; default: exit(0); } return NFound; } /* The following stuff calculates thresholds for GTCONST relations. The pos and neg tuples are sorted separately, then merged. The current value is acceptable as a threshold unless it is in the middle of a run of tuples of the same sign or a run of the same value */ float BestGain, BestThresh; int BestTPos, BestTTot; void FindThreshold(Var *A) /* ------------- */ { Tuple *ScanPos, *ScanNeg, Case; float PosVal, NegVal, ThisVal, PrevVal=(-1E30); Var V; int ThisSign, NextSign, Signs=0, i; V = A[1]; BestGain = -1E10; PossibleCuts = 0; NowMPos = MissingAndSort(V, 0, Current.NPos-1); NowMTot = NowMPos + MissingAndSort(V, Current.NPos, Current.NTot-1); NowTPos = Current.NPos - NowMPos; NowTTot = Current.NTot - NowMTot; ScanPos = &Current.Tuples[NowMPos]; ScanNeg = &Current.Tuples[Current.NPos + (NowMTot - NowMPos)]; PosVal = ( NowTPos ? FP(((*ScanPos)[V])) : 1E30 ); NegVal = ( NowTTot > NowTPos ? FP(((*ScanNeg)[V])) : 1E30 ); while ( NowTTot >= 1 ) { if ( PosVal <= NegVal ) { NowTPos--; NowTTot--; ScanPos++; ThisVal = PosVal; PosVal = ( NowTPos ? FP(((*ScanPos)[V])) : 1E30 ); ThisSign = 1; } else { NowTTot--; ScanNeg++; ThisVal = NegVal; NegVal = ( NowTTot > NowTPos ? FP(((*ScanNeg)[V])) : 1E30 ); ThisSign = 2; } if ( ThisVal == PrevVal ) { Signs |= ThisSign; } else { Signs = ThisSign; PrevVal = ThisVal; PossibleCuts++; } NextSign = ( PosVal == NegVal ? 3 : PosVal < NegVal ? 1 : 2 ); if ( NowTTot && ThisVal != PosVal && ThisVal != NegVal && (Signs | NextSign) == 3 ) { PossibleCut(ThisVal); } } PossibleCuts--; /* Fix up all required counts */ if ( BestGain >= 0 ) { NewTPos = NowTPos = BestTPos; NewTTot = NowTTot = BestTTot; NowFPos = Current.NPos - NowTPos - NowMPos; NowFNeg = (Current.NTot - Current.NPos) - (NowTTot - NowTPos) - (NowMTot - NowMPos); SaveParam(&A[2], &BestThresh); Verbose(3) printf("%g", BestThresh); /* Now determine coverage of original tuples */ ClearFlags; OrigTPos = OrigTTot = OrigFPos = OrigFTot = 0; ForEach(i, 0, Current.NTot-1) { Case = Current.Tuples[i]; ThisVal = FP(Case[V]); if ( ThisVal == MISSING_FP ) continue; if ( ThisVal > BestThresh ) { if ( ! TestFlag(Case[0]&Mask, TrueBit) ) { SetFlag(Case[0]&Mask, TrueBit); OrigTTot++; if ( Positive(Case) ) OrigTPos++; } } else { if ( ! TestFlag(Case[0]&Mask, FalseBit) ) { SetFlag(Case[0]&Mask, FalseBit); OrigFTot++; if ( Positive(Case) ) OrigFPos++; } } } /* Encoding length checks */ PossibleT &= Encode(OrigTPos) > NewClauseBits; PossibleF &= Encode(OrigFPos) > NewClauseBits; } else { NewTPos = NowTPos = Current.NPos; NewTTot = NowTTot = Current.NTot; NowFPos = NowFNeg = 0; PossibleT = PossibleF = false; } } void PossibleCut(float C) /* ----------- */ { float TGain, FGain, Better; TGain = Worth(NowTPos, NowTPos, NowTTot, 0); FGain = Worth(Current.NPos-NowTPos-NowMPos, Current.NPos-NowTPos-NowMPos, Current.NTot-NowTTot-NowMTot, 0); Better = Max(TGain, FGain); if ( Better > BestGain ) { BestGain = Better; BestThresh = C; BestTPos = NowTPos; BestTTot = NowTTot; } } /* Count missing values and sort the remainder */ Tuple Hold; #define Swap(V,A,B) { Hold = V[A]; V[A] = V[B]; V[B] = Hold; } int MissingAndSort(Var V, int Fp, int Lp) /* -------------- */ { int i, Xp; /* Omit and count unknown values */ Xp = Fp; ForEach(i, Fp, Lp) { if ( FP(Current.Tuples[i][V]) == MISSING_FP ) { Swap(Current.Tuples, Xp, i); Xp++; } } Quicksort(Current.Tuples, Xp, Lp, V); return Xp - Fp; } void Quicksort(Tuple *Vec, int Fp, int Lp, Var V) /* --------- */ { register int Middle, i; register float Thresh; if ( Fp < Lp ) { Thresh = FP(Vec[ (Fp+Lp)/2 ][V]); /* Isolate all items with values < threshold */ Middle = Fp; for ( i = Fp ; i <= Lp ; i++ ) { if ( FP(Vec[i][V]) < Thresh ) { if ( i != Middle ) Swap(Vec, Middle, i); Middle++; } } /* Sort the lower values */ Quicksort(Vec, Fp, Middle-1, V); /* Extract all values equal to the threshold */ for ( i = Middle ; i <= Lp ; i++ ) { if ( FP(Vec[i][V]) == Thresh ) { if ( i != Middle ) Swap(Vec, Middle, i); Middle++; } } /* Sort the higher values */ Quicksort(Vec, Middle, Lp, V); } } @//E*O*F evaluatelit.c// chmod u=rw,g=,o= evaluatelit.c echo x - extern.i sed 's/^@//' > "extern.i" <<'@//E*O*F extern.i//' /******************************************************************************/ /* */ /* Variables defined in global.c */ /* */ /******************************************************************************/ extern Boolean NEGLITERALS, NEGEQUALS, UNIFORMCODING, MissingVals, AnyPartialOrder, *Barred, OutOfWorld; extern float SAMPLE, MINACCURACY, MINALTFRAC, DETERMINATE; extern int MAXVARS, MAXARGS, MAXWEAKLITS, MAXPOSSLIT, MAXALTS, MAXVARDEPTH, MAXRECOVERS, MAXTUPLES, VERBOSITY, MaxConst, MaxType, MaxRel, AllTuples, NCl, NLit, NDetLits, NWeakLits, SavedClauseCover; extern PossibleLiteral AlterSavedClause; extern char **ConstName, *Flags; extern Relation *Reln, *RelnOrder, Target; extern State StartDef, StartClause, Current, New; extern float *LogFact, MaxPossibleGain, ClauseBits, AvailableBits, AdjMinAccuracy, SavedClauseAccuracy; extern Clause NewClause, SavedClause; extern Boolean **PartialOrder, **Compatible; extern Ordering **RecursiveLitOrders; extern int NRecLitClause, NRecLitDef; extern VarInfo *Variable; extern Var *DefaultVars; extern TypeInfo *Type; extern Tuple *Found; extern int NFound; extern Alternative *ToBeTried; extern int NToBeTried; extern PossibleLiteral *Possible; extern int NPossible, NDeterminate; @//E*O*F extern.i// chmod u=rw,g=,o= extern.i echo x - finddef.c sed 's/^@//' > "finddef.c" <<'@//E*O*F finddef.c//' /******************************************************************************/ /* */ /* All the stuff for trying possible next literals, growing clauses */ /* and assembling definitions */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" int FalsePositive, FalseNegative; void FindDefinition(Relation R) /* -------------- */ { int Size, i, TargetPos, FirstDefR; Target = R; NCl = 0; printf("\n----------\n%s:\n", R->Name); /* Reorder the relations so that the target relation comes first */ FirstDefR = ( RelnOrder[2] == GTVAR ? 4 : 2 ); for ( TargetPos = FirstDefR ; RelnOrder[TargetPos] != Target ; TargetPos++ ) ; for ( i = TargetPos ; i > FirstDefR ; i-- ) { RelnOrder[i] = RelnOrder[i-1]; } RelnOrder[FirstDefR] = Target; /* Generate initial tuples and make a copy */ OriginalState(R); StartClause = StartDef; Size = StartDef.NTot+1; StartClause.Tuples = Alloc(Size, Tuple); memcpy(StartClause.Tuples, StartDef.Tuples, Size*sizeof(Tuple)); NRecLitDef = 0; FalsePositive = 0; FalseNegative = StartDef.NPos; R->Def = Alloc(100, Clause); while ( StartClause.NPos ) { if ( ! (R->Def[NCl] = FindClause()) ) break; R->Def[NCl++][NLit] = Nil; if ( NCl % 100 == 0 ) { Realloc(R->Def, NCl+100, Clause); } NRecLitDef += NRecLitClause; } R->Def[NCl] = Nil; SiftClauses(); if ( FalsePositive || FalseNegative ) { printf("\n*** Warning: the following definition\n"); if ( FalsePositive ) { printf("*** matches %d tuple%s not in the relation\n", FalsePositive, Plural(FalsePositive)); } if ( FalseNegative ) { printf("*** does not cover %d tuple%s in the relation\n", FalseNegative, Plural(FalseNegative)); } } PrintDefinition(R); pfree(StartClause.Tuples); pfree(StartDef.Tuples); /* Restore original relation order */ for ( i = FirstDefR ; i < TargetPos ; i++ ) { RelnOrder[i] = RelnOrder[i+1]; } RelnOrder[TargetPos] = Target; } Clause FindClause() /* ---------- */ { Tuple Case, *TSP; InitialiseClauseInfo(); GrowNewClause(); /* Now that pruning includes addition of implicit equalities, should try even when there is a single RHS literal */ PruneNewClause(); /* Make sure accuracy criterion is satisfied */ if ( ! NLit || Current.NOrigPos+1E-3 < AdjMinAccuracy * Current.NOrigTot ) { if ( NLit ) { Verbose(1) printf("\nClause too inaccurate (%d/%d)\n", Current.NOrigPos, Current.NOrigTot); } pfree(NewClause); return Nil; } FalsePositive += Current.NOrigTot - Current.NOrigPos; FalseNegative -= Current.NOrigPos; /* Set flags for positive covered tuples */ ClearFlags; for ( TSP = Current.Tuples ; Case = *TSP ; TSP++ ) { if ( Positive(Case) ) { SetFlag(Case[0]&Mask, TrueBit); } } if ( Current.Tuples != StartClause.Tuples ) { FreeTuples(Current.Tuples, true); } /* Copy all negative tuples and uncovered positive tuples */ StartClause.NTot = StartClause.NPos = 0; for ( TSP = StartClause.Tuples ; Case = *TSP ; TSP++ ) { if ( ! Positive(Case) || ! TestFlag(Case[0]&Mask, TrueBit) ) { StartClause.Tuples[StartClause.NTot++] = Case; if ( Positive(Case) ) StartClause.NPos++; } } StartClause.Tuples[StartClause.NTot] = Nil; StartClause.NOrigPos = StartClause.NPos; StartClause.NOrigTot = StartClause.NTot; StartClause.BaseInfo = Info(StartClause.NPos, StartClause.NTot); Current = StartClause; Verbose(1) { printf("\nClause %d: ", NCl); PrintClause(Target, NewClause); } return NewClause; } void ExamineLiterals() /* --------------- */ { Relation R; int i, Relns=0; NPossible = NDeterminate = 0; MaxPossibleGain = Current.NPos * Current.BaseInfo; /* If this is not the first literal, review coverage and check variable orderings, identical variables etc. */ if ( NLit != 0 ) { CheckOriginalCaseCover(); ExamineVariableRelationships(); } AvailableBits = Encode(Current.NOrigPos) - ClauseBits; Verbose(1) { printf("\nState (%d/%d", Current.NPos, Current.NTot); if ( Current.NTot != Current.NOrigTot ) { printf(" [%d/%d]", Current.NOrigPos, Current.NOrigTot); } printf(", %.1f bits available", AvailableBits); if ( NWeakLits ) { Verbose(2) printf(", %d weak literal%s", NWeakLits, Plural(NWeakLits)); } printf(")\n"); Verbose(4) PrintTuples(Current.Tuples, Current.MaxVar); } /* Find possible literals for each relation */ ForEach(i, 0, MaxRel) { R = RelnOrder[i]; ExploreArgs(R, true); if ( R->NTrialArgs ) Relns++; } /* Evaluate them */ AlterSavedClause = Nil; Verbose(2) putchar('\n'); for ( i = 0 ; i <= MaxRel && BestLitGain < MaxPossibleGain ; i++ ) { R = RelnOrder[i]; if ( ! R->NTrialArgs ) continue; R->Bits = Log2(Relns) + Log2(R->NTrialArgs+1E-3); if ( NEGLITERALS || Predefined(R) ) R->Bits += 1.0; if ( R->Bits - Log2(NLit+1.001-NDetLits) > AvailableBits ) { Verbose(2) { printf("\t\t\t\t[%s requires %.1f bits]\n", R->Name, R->Bits); } } else { ExploreArgs(R, false); Verbose(2) printf("\t\t\t\t[%s tried %d/%d] %.1f secs\n", R->Name, R->NTried, R->NTrialArgs, CPUTime()); } } } void GrowNewClause() /* ------------- */ { Literal L; int i, OldNLit; Boolean Progress=true; float Accuracy, ExtraBits; while ( Progress && Current.NPos < Current.NTot ) { ExamineLiterals(); /* If have noted better saveable clause, record it */ if ( AlterSavedClause ) { Realloc(SavedClause, NLit+2, Literal); ForEach(i, 0, NLit-1) { SavedClause[i] = NewClause[i]; } SavedClause[NLit] = AllocZero(1, struct _lit_rec); SavedClause[NLit+1] = Nil; SavedClause[NLit]->Rel = AlterSavedClause->Rel; SavedClause[NLit]->Sign = AlterSavedClause->Sign; SavedClause[NLit]->Args = AlterSavedClause->Args; SavedClause[NLit]->Bits = AlterSavedClause->Bits; SavedClause[NLit]->WeakLits = 0; SavedClauseCover = AlterSavedClause->PosCov; SavedClauseAccuracy = AlterSavedClause->PosCov / (float) AlterSavedClause->TotCov; Verbose(1) { printf("\n\tSave clause ending with "); PrintLiteral(SavedClause[NLit]); printf(" (cover %d, accuracy %d%%)\n", SavedClauseCover, (int) (100*SavedClauseAccuracy)); } pfree(AlterSavedClause); } if ( NDeterminate && BestLitGain < DETERMINATE * MaxPossibleGain ) { ProcessDeterminateLiterals(true); } else if ( NPossible ) { /* At least one gainful literal */ NewClause[NLit] = L = SelectLiteral(); if ( ++NLit % 100 == 0 ) Realloc(NewClause, NLit+100, Literal); ExtraBits = L->Bits - Log2(NLit-NDetLits+1E-3); ClauseBits += Max(ExtraBits, 0); Verbose(1) { printf("\nBest literal "); PrintLiteral(L); printf(" (%.1f bits)\n", L->Bits); } /* Check whether should regrow clause */ if ( L->Rel != Target && AllLHSVars(L) && Current.MaxVar > Target->Arity && ! AllDeterminate() ) { OldNLit = NLit; NLit = 0; ForEach(i, 0, OldNLit-1) { if ( AllLHSVars(NewClause[i]) ) { NewClause[NLit++] = NewClause[i]; } } NewClause[NLit] = Nil; RecoverState(NewClause); Verbose(1) { printf("\n[Regrow clause] "); PrintClause(Target,NewClause); } GrowNewClause(); return; } NWeakLits = L->WeakLits; if ( L->Rel == Target ) AddOrders(L); NewState(L, Current.NTot); if ( L->Rel == Target ) NoteRecursiveLit(L); } else { Verbose(1) printf("\nNo literals\n"); Progress = Recover(); } } NewClause[NLit] = Nil; /* Finally, see whether saved clause is better */ CheckOriginalCaseCover(); Accuracy = Current.NOrigPos / (float) Current.NOrigTot; if ( SavedClause && ( SavedClauseAccuracy > Accuracy || SavedClauseAccuracy == Accuracy && SavedClauseCover > Current.NOrigPos || SavedClauseAccuracy == Accuracy && SavedClauseCover == Current.NOrigPos && CodingCost(SavedClause) < CodingCost(NewClause) ) ) { Verbose(1) printf("\n[Replace by saved clause]\n"); RecoverState(SavedClause); CheckOriginalCaseCover(); } } InitialiseClauseInfo() /* -------------------- */ { Var V; /* Initialise everything for start of new clause */ NewClause = Alloc(100, Literal); Current = StartClause; NLit = NDetLits = NWeakLits = NRecLitClause = 0; NToBeTried = 0; AnyPartialOrder = false; ClauseBits = 0; ForEach(V, 1, Target->Arity) { Variable[V]->Depth = 0; Variable[V]->Type = Target->Type[V]; Variable[V]->TypeRef = Target->TypeRef[V]; } memset(Barred, false, MAXVARS+1); SavedClause = Nil; SavedClauseAccuracy = SavedClauseCover = 0; MAXRECOVERS = MAXALTS; } Boolean SameLiteral(Relation R, Boolean Sign, Var *A) /* ----------- */ { Var V, NArgs; if ( R != AlterSavedClause->Rel || Sign != AlterSavedClause->Sign ) { return false; } NArgs = ( HasConst(R) ? 1 + sizeof(Const) : R->Arity); ForEach(V, 1, NArgs) { if ( A[V] != AlterSavedClause->Args[V] ) return false; } return true; } Boolean AllLHSVars(Literal L) /* ---------- */ { Var V; ForEach(V, 1, L->Rel->Arity) { if ( L->Args[V] > Target->Arity ) return false; } return true; } /* See whether all literals in clause are determinate */ Boolean AllDeterminate() /* -------------- */ { int i; ForEach(i, 0, NLit-2) { if ( NewClause[i]->Sign != 2 ) return false; } return true; } /* Find the coding cost for a clause */ float CodingCost(Clause C) /* ---------- */ { float SumBits=0, Contrib; int Lits=0; while ( *C ) { Lits++; if ( (Contrib = (*C)->Bits - Log2(Lits)) > 0 ) SumBits += Contrib; C++; } return SumBits; } @//E*O*F finddef.c// chmod u=rw,g=,o= finddef.c echo x - global.c sed 's/^@//' > "global.c" <<'@//E*O*F global.c//' #include "defns.i" /******************************************************************************/ /* */ /* Parameters set by options and variables accessible to many routines */ /* */ /******************************************************************************/ Boolean NEGLITERALS = true, /* negated literals ok */ NEGEQUALS = true, /* negated equality literals ok */ UNIFORMCODING = false, /* uniform coding of literals */ MissingVals = false, /* missing values in input? */ AnyPartialOrder, /* quick check to rule out recursive lits */ *Barred, /* duplicate variables */ OutOfWorld; /* flag ^ constant */ float SAMPLE = 1.0, /* fraction of negative tuples to sample */ MINACCURACY = 0.8, /* minimum acceptable clause accuracy */ MINALTFRAC = 0.8, /* fraction of best gain required for backup */ DETERMINATE = 0.8; /* use determinate literals unless a literal with this fraction of max possible gain */ int MAXVARS = 52, /* max number of variables */ MAXARGS = 5, /* max arity of any relation */ MAXWEAKLITS = 3, /* max weak literals in sequence */ MAXPOSSLIT = 5, /* 1 + max backups from single state */ MAXALTS = 20, /* max simultaneous backups */ MAXRECOVERS, /* max total backups */ MAXVARDEPTH = 4, /* max depth of var in literal */ MAXTUPLES = 100000, /* max number of tuples */ VERBOSITY = 1, /* level of output */ MaxConst = 0, /* no. constants */ MaxType = 0, /* no. types */ MaxRel = 0, /* highest relation no */ AllTuples, /* effective size of universe */ NCl, /* current clause number */ NLit, /* current literal number */ NDetLits, /* number of determinate lits in clause */ NWeakLits, /* current weak lits in sequence */ SavedClauseCover; /* coverage of saved clause */ char **ConstName, /* names of all discrete constants */ *Flags = Nil; /* flag bits for original tuples */ Relation *Reln, /* relations */ *RelnOrder, /* order to try relations */ Target; /* relation being induced */ State StartDef, /* at start of definition */ StartClause, /* at start of clause */ Current, /* current state */ New; /* possible next state */ float *LogFact = Nil, /* LogFact[i] = log2(i!) */ MaxPossibleGain, ClauseBits, /* bits used so far in this clause */ AvailableBits, /* bits available for this clause */ AdjMinAccuracy, /* min accuracy adjusted for sampling */ SavedClauseAccuracy; /* accuracy of saved clause */ Clause NewClause, /* clause being constructed */ SavedClause; /* best shorter clause discovered while developing current clause */ PossibleLiteral AlterSavedClause; /* last literal of saved clause */ Boolean **PartialOrder, /* partial orders on variables*/ **Compatible; /* Compatible[i][j] = true if types i, j have at least one common value */ Ordering **RecursiveLitOrders; /* pointers to orders in recursive lits */ int NRecLitClause, /* number of recursive lits in the new clause */ NRecLitDef; /* ditto in definition so far */ VarInfo *Variable; /* variables */ Var *DefaultVars; /* default variable list */ TypeInfo *Type; /* types */ Tuple *Found; /* join */ int NFound; /* number of tuples in join */ Alternative *ToBeTried; /* backup points */ int NToBeTried; PossibleLiteral *Possible; /* possible literals */ int NPossible, NDeterminate; @//E*O*F global.c// chmod u=rw,g=,o= global.c echo x - input.c sed 's/^@//' > "input.c" <<'@//E*O*F input.c//' /******************************************************************************/ /* */ /* All input routines */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" #define Space(s) (s == ' ' || s == '\t') #define SkipComment while ( ( c = getchar() ) != '\n' ) char Name[200], SectionDelim; Const *SortedConst = Nil; Boolean ContinuousVars = false; /******************************************************************************/ /* */ /* Routines for reading types */ /* */ /******************************************************************************/ Boolean ReadType() /* -------- */ { int i; char Delim; TypeInfo T; Boolean FirstTime=true, RecordTheoryConst; Const C; Delim = ReadName(Name); if ( ! *Name ) return false; else if ( Delim != ':' ) Error(1, Name); T = AllocZero(1, struct _type_rec); T->NValues = T->NTheoryConsts = 0; T->Value = T->TheoryConst = Nil; if ( Name[0] == '*' ) /* order specified by user */ { T->FixedPolarity = true; T->Ordered = true; T->Name = CopyString(Name+1); } else if ( Name[0] == '#' ) /* specified to be unordered */ { T->FixedPolarity = true; T->Ordered = false; T->Name = CopyString(Name+1); } else { T->FixedPolarity = false; T->Name = CopyString(Name); } /* Read first name */ while ( (Delim = ReadName(Name)) == '\n' ) ; if ( ! Name ) Error(1, Name); /* Check for continuous type */ if ( ! strcmp(Name, "continuous") ) { T->Continuous = true; T->FixedPolarity = true; T->Ordered = false; /* Never match on continuous value - hence no point in checking for orders on it */ ContinuousVars = true; } else { /* Discrete type, read the values */ T->Continuous = false; do { while ( ( FirstTime ? ! (FirstTime = false) : (Delim = ReadName(Name)) ) && Delim == '\n' ) ; if ( Name[0] == '*' ) { /* Theory constant */ RecordTheoryConst = true; for ( i = 0 ; Name[i++] ; ) { Name[i-1] = Name[i]; } } else { RecordTheoryConst = false; } if ( T->NValues % 100 == 0 ) { Realloc(T->Value, T->NValues+100, Const); } C = T->Value[ T->NValues++ ] = FindConstant(Name, false); /* Check for duplicate constants */ ForEach(i, 0, T->NValues-2) { if ( T->Value[i] == C ) Error(7, Name, T->Name); } if ( RecordTheoryConst ) { if ( T->NTheoryConsts % 10 == 0 ) { Realloc(T->TheoryConst, T->NTheoryConsts+10, Const); } T->TheoryConst[ T->NTheoryConsts++ ] = C; } } while ( Delim == ',' ); } if ( Delim != '.' ) Error(2, Name, T->Name); ReadToEOLN; /* Enter Type */ MaxType++; if ( MaxType % 100 == 1 ) { Realloc(Type, MaxType + 100, TypeInfo); } Type[MaxType] = T; return true; } void ReadTypes() /* --------- */ { int i, j; TypeInfo T; /* Record names for missing value and out-of-range */ FindConstant("?", false); FindConstant("^", false); /* Read all type definitions */ while ( ReadType() ) ; /* Generate collating sequences */ ForEach(i, 1, MaxType) { T = Type[i]; if ( T->Continuous ) continue; /* Skip continuous type */ T->CollSeq = Alloc(MaxConst+1, int); ForEach(j, 0, MaxConst) { T->CollSeq[j] = 0; } ForEach(j, 0, T->NValues-1) { T->CollSeq[T->Value[j]] = j+1; } T->CollSeq[MISSING_DISC] = T->NValues+1; } } /******************************************************************************/ /* */ /* Routines for reading tuples and relations */ /* */ /******************************************************************************/ Tuple ReadTuple(Relation R) /* --------- */ { char Delim; int N, i; Tuple T; N = R->Arity; if ( (Delim = ReadName(Name)) == '.' || Delim == ';' ) { return Nil; } T = Alloc(N+1, Const); ForEach(i, 1, N) { if ( i > 1 ) { Delim = ReadName(Name); } if ( R->TypeRef[i]->Continuous ) { if ( ! strcmp(Name,"?") ) { FP(T[i]) = MISSING_FP; MissingVals = true; } else { FP(T[i]) = atof(Name); if ( FP(T[i]) == MISSING_FP ) { printf("An input continuous values is equal to the\n"); printf("magic number used to designate missing values.\n"); printf("Change the definition of MISSING_FP in defns.i\n"); printf("and recompile.\n"); exit(1); } } } else { if ( ! strcmp(Name,"?") ) { T[i] = MISSING_DISC; MissingVals = true; } else { T[i] = FindConstant(Name, true); } } } if ( Delim != ':' && Delim != '\n' ) ReadToEOLN; ForEach(i, 1, N) { if ( ! R->TypeRef[i]->Continuous && T[i] != OUT_OF_RANGE && ! R->TypeRef[i]->CollSeq[T[i]] ) { Error(4, ConstName[T[i]], Type[R->Type[i]]->Name); } } return T; } Tuple *ReadTuples(Relation R, Boolean Pos) /* ---------- */ { Tuple T, *TheTuples=Nil; int ND=0; TheTuples = Alloc(101, Tuple); while ( T = ReadTuple(R) ) { T[0] = Pos ? PosMark : 0; if ( ND && ND % 100 == 0 ) { Realloc(TheTuples, ND+101, Tuple); } TheTuples[ND++] = T; } TheTuples[ND] = Nil; return TheTuples; } Relation ReadRelation() /* ------------ */ { Relation R; char Delim, c; int NArgs=0, Key[100], NKeys=0, i, t; if ( ReadName(Name) != '(' ) return Nil; printf("\nRelation %s\n", Name); /* Create a new record with all zero counts */ R = AllocZero(1, struct _rel_rec); if ( Name[0] == '*' ) { /* Background relation */ R->PossibleTarget = false; R->Name = CopyString(Name+1); } else { R->PossibleTarget = true; R->Name = CopyString(Name); } do { NArgs++; Realloc(R->Type, NArgs+1, int); Realloc(R->TypeRef, NArgs+1, TypeInfo); Delim = ReadName(Name); t = FindType(Name); R->Type[NArgs] = t; R->TypeRef[NArgs] = Type[t]; } while ( Delim != ')' ); R->Arity = NArgs; if ( NArgs > MAXARGS ) MAXARGS = NArgs; if ( R->PossibleTarget && NArgs > MAXVARS ) MAXVARS = NArgs; /* Read and store access keys */ do { do { c = getchar(); } while ( Space(c) ) ; if ( c != '\n' ) { Key[NKeys] = 0; ForEach(i, 1, NArgs) { if ( c == '-' ) Key[NKeys] |= (1 << i); c = getchar(); } NKeys++; } } while ( c == '/'); R->NKeys = NKeys; if ( NKeys ) { R->Key = Alloc(NKeys, int); memcpy(R->Key, Key, NKeys*sizeof(int)); } R->Pos = ReadTuples(R, true); R->PosIndex = MakeIndex(R->Pos, NArgs, R); if ( SectionDelim == '.' ) { R->Neg = Nil; } else { R->Neg = ReadTuples(R, false); /* The index of negative tuples isn't currently used, but may be useful if you are adapting the system */ /* R->NegIndex = MakeIndex(R->Neg, NArgs, R); */ } R->BinSym = SymmetryCheck(R); DuplicateTuplesCheck(R); UnequalArgsCheck(R); return R; } void ReadRelations() /* ------------- */ { int i, j, Next, Best, PosSize, WorldSize; Relation R; Tuple *T; Boolean *Waiting; float *Imbalance; while ( R = ReadRelation() ) { /* Make sure room for one more */ if ( ++MaxRel % 10 == 0 ) { Realloc(Reln, MaxRel+10, Relation); } Reln[MaxRel] = R; Verbose(4) { if ( Reln[MaxRel]->BinSym ) { printf(" is binary symmetric\n"); } for ( T = Reln[MaxRel]->Pos ; *T ; T++ ) { PrintTuple(*T, Reln[MaxRel]->Arity, Reln[MaxRel]->TypeRef, Reln[MaxRel]->Neg != Nil); } if ( Reln[MaxRel]->Neg ) { for ( T = Reln[MaxRel]->Neg ; *T ; T++ ) { PrintTuple(*T, Reln[MaxRel]->Arity, Reln[MaxRel]->TypeRef, true); } } } } /* Now put the relations into the order in which they should be tried. The idea is to put lower arity relations earlier to maximise the effect of pruning. Relations of the same arity are resolved by preferring relations with higher information */ RelnOrder = Alloc(MaxRel+1, Relation); Waiting = Alloc(MaxRel+1, Boolean); Imbalance = Alloc(MaxRel+1, float); memset(Waiting, true, MaxRel+1); ForEach(i, 4, MaxRel) { R = Reln[i]; PosSize = Number(R->Pos); if ( R->Neg ) { WorldSize = PosSize + Number(R->Neg); } else { WorldSize = 1; ForEach(j, 1, Reln[i]->Arity) { if ( ! R->TypeRef[j]->Continuous ) { WorldSize *= R->TypeRef[j]->NValues; } } } Imbalance[i] = fabs(0.5 - PosSize / (float) WorldSize); } RelnOrder[0] = Reln[1]; RelnOrder[1] = Reln[0]; RelnOrder[2] = Reln[3]; RelnOrder[3] = Reln[2]; /*ForEach(i, 0, 3) RelnOrder[i] = Reln[i];*/ Next = ( ContinuousVars ? 4 : 2 ); while ( true ) { Best = -1; ForEach(i, 4, MaxRel) { if ( Waiting[i] && ( Best < 0 || Reln[i]->Arity < Reln[Best]->Arity || Reln[i]->Arity == Reln[Best]->Arity && Imbalance[i] < Imbalance[Best] ) ) { Best = i; } } if ( Best < 0 ) break; RelnOrder[Next++] = Reln[Best]; Waiting[Best] = false; } MaxRel = Next-1; pfree(Waiting); pfree(Imbalance); } /* Find a type by name */ int FindType(char *N) /* -------- */ { int i; ForEach(i, 1, MaxType) { if ( ! strcmp(N, Type[i]->Name) ) return i; } Error(5, N); return 0; /* keep lint happy */ } /******************************************************************************/ /* */ /* DuplicateTuplesCheck(R) - check for duplicate tuples in R */ /* */ /******************************************************************************/ void DuplicateTuplesCheck(Relation R) /* -------------------- */ { int i, j, k, N, NPos, NNeg; Tuple *PosCopy, *NegCopy, PosTuple, NegTuple; Boolean MutualDuplicate; /* First copy the positive tuples and check number of duplicates */ NPos = Number(R->Pos); PosCopy = Alloc(NPos+1, Tuple); ForEach(i, 0, NPos) { PosCopy[i] = (R->Pos)[i]; } N = R->Arity; if ( R->PosDuplicates = CountDuplicates(PosCopy,N,0,NPos-1) ) { printf(" (warning: contains duplicate positive tuples)\n"); } /* If there are neg tuples, check for duplicates and mutual duplicates */ if ( R->Neg ) { NNeg = Number(R->Neg); NegCopy = Alloc(NNeg+1, Tuple); ForEach(i, 0, NNeg) { NegCopy[i] = (R->Neg)[i]; } if ( CountDuplicates(NegCopy,N,0,NNeg-1) ) { printf(" (warning: contains duplicate negative tuples)\n"); } /* Existence check for mutual duplicates */ MutualDuplicate = false; i = j = 0; while( i < NPos && j < NNeg ) { PosTuple = PosCopy[i]; NegTuple = NegCopy[j]; for ( k = 1 ; k <= N && PosTuple[k] == NegTuple[k] ; k++ ) ; if ( k > N ) /* tuples are duplicates */ { MutualDuplicate = true; break; } else if ( PosTuple[k] < NegTuple[k] ) { i++; } else { j++; } } if ( MutualDuplicate ) { printf(" (warning: contains tuples that are both "); printf("positive and negative)\n"); } pfree(NegCopy); } pfree(PosCopy); } /******************************************************************************/ /* */ /* CountDuplicates(T,N,left,right) - count the number of duplicate */ /* tuples in T between left and right. */ /* Sorts tuples on order given by comparison of Const type. */ /* N.B. This comparison is used even for continuous values as */ /* only checking for duplicates. */ /* */ /******************************************************************************/ int CountDuplicates(Tuple *T, int N, int Left, int Right) /* --------------- */ { register int i, j, last, first, swap, count=0; register Tuple temp, comp, other; if ( Left >= Right ) return 0; temp = T[Left]; T[Left] = T[swap=(Left+Right)/2]; T[swap] = temp; last = Left; comp = T[Left]; for ( i = Left + 1; i <= Right; i++ ) { other = T[i]; for( j = 1 ; j <= N && other[j] == comp[j] ; j++ ) ; if ( j > N || other[j] < comp[j] ) /* other <= comp */ { temp = T[++last]; T[last] = T[i]; T[i] = temp; } } temp = T[Left]; T[Left] = T[last]; T[last] = temp; first = last; for ( i = last - 1; i >= Left ; i-- ) { other = T[i]; for ( j = 1 ; j <= N && other[j] == comp[j] ; j++ ) ; if ( j > N ) /* other == comp */ { temp = T[--first]; T[first] = T[i]; T[i] = temp; count++; } } count += CountDuplicates(T,N,Left,first-1); count += CountDuplicates(T,N,last+1,Right); return count; } Boolean SymmetryCheck(Relation R) /* ------------- */ { Tuple *TheTuples; Boolean *SymCheck; int i, j, NPos; Const T1, T2; if ( R->Arity != 2 || R->TypeRef[1]->Continuous || R->TypeRef[2]->Continuous ) { return false; } TheTuples = R->Pos; NPos = Number(TheTuples); SymCheck = Alloc(NPos, Boolean); memset(SymCheck, false, NPos*sizeof(Boolean)); ForEach(i, 0, NPos-1) { if ( SymCheck[i] ) continue; T1 = TheTuples[i][1]; T2 = TheTuples[i][2]; for ( j = i ; j < NPos && ( T1 != TheTuples[j][2] || T2 != TheTuples[j][1] ) ; j++ ) ; if ( j == NPos ) { pfree(SymCheck); return false; } SymCheck[j] = true; } pfree(SymCheck); return true; } /* Construct the index for a set of tuples for relation R */ Index MakeIndex(Tuple *T, int N, Relation R) /* --------- */ { Index IX; Tuple Case, *Scan; int **Next, Arg, Val, No = 0; /* Allocate storage */ IX = Alloc(N+1, int **); Next = Alloc(N+1, int *); ForEach(Arg, 1, N) { IX[Arg] = Alloc(MaxConst+1, int *); Next[Arg] = AllocZero(MaxConst+1, int); } for ( Scan = T ; Case = *Scan++ ; ) { ForEach(Arg, 1, N) { if ( ! R->TypeRef[Arg]->Continuous ) Next[Arg][Case[Arg]]++; } } ForEach(Arg, 1, N) { ForEach(Val, 1, MaxConst) { IX[Arg][Val] = Next[Arg][Val] ? Alloc(Next[Arg][Val]+1, int) : Nil; Next[Arg][Val] = 0; } } /* Construct the index */ for ( Scan = T ; *Scan ; Scan++ ) { ForEach(Arg, 1, N) { if ( ! R->TypeRef[Arg]->Continuous ) { Val = (*Scan)[Arg]; IX[Arg][Val][Next[Arg][Val]++] = No; } } No++; } /* Terminate index and free Next */ ForEach(Arg, 1, N) { ForEach(Val, 1, MaxConst) { if ( IX[Arg][Val] ) { IX[Arg][Val][Next[Arg][Val]] = FINISH; } } pfree(Next[Arg]); } pfree(Next); return IX; } /******************************************************************************/ /* */ /* Basic routine -- read a delimited name into string s */ /* */ /* - Embedded spaces are permitted, but multiple spaces are replaced */ /* by a single space */ /* - Any character escaped by \ is ok */ /* - Characters after | are ignored */ /* */ /******************************************************************************/ char ReadName(char *s) /* --------- */ { register char *Sp = s; register int c; /* Skip to first non-space character */ while ( (c = getchar()) != EOF && ( c == '|' || Space(c) ) ) { if ( c == '|' ) SkipComment; } /* Return period if no names to read */ if ( c == EOF ) { return (SectionDelim = '.'); } else if ( c == ';' || c == '.' ) { ReadToEOLN; return (SectionDelim = c); } /* Read in characters up to the next delimiter */ while ( c != ',' && c != '\n' && c != '|' && c != EOF && c != '(' && c != ')' && c != ':' && c != '.' ) { if ( c == '\\' ) c = getchar(); *Sp++ = c; if ( c == ' ' ) while ( ( c = getchar() ) == ' ' ); else c = getchar(); if ( c == '.' ) /* Check for embedded period in number */ { c = getchar(); if (isdigit(c)) { *Sp++ = '.'; } else { ungetchar(c); c = '.'; } } } if ( c == '|' ) { SkipComment; c = '\n'; } /* Strip trailing spaces */ while ( Sp > s && Space(*(Sp-1)) ) Sp--; *Sp++ = '\0'; return c; } /* Find a constant using binary chop search */ Const FindConstant(char *N, Boolean MustBeThere) /* ------------ */ { int i, Hi=MaxConst+1, Lo=1, Differ=1; while ( Lo < Hi-1 ) { Differ = strcmp(N, ConstName[SortedConst[i = (Hi + Lo)/2]]); if ( ! Differ ) return SortedConst[i]; else if ( Differ > 0 ) Lo = i; else Hi = i; } if ( MustBeThere ) Error(3, N); /* This is a new constant -- record it */ MaxConst++; if ( MaxConst % 1000 == 1 ) { Realloc(ConstName, MaxConst+1000, char *); Realloc(SortedConst, MaxConst+1000, int); } Lo++; for ( i = MaxConst ; i > Lo ; i-- ) { SortedConst[i] = SortedConst[i-1]; } SortedConst[Lo] = MaxConst; ConstName[MaxConst] = CopyString(N); return MaxConst; } /* Check whether different types are compatible, i.e. share at least one common value */ void CheckTypeCompatibility() /* ---------------------- */ { int T1, T2; Compatible = Alloc(MaxType+1, Boolean *); ForEach(T1, 1, MaxType) { Compatible[T1] = Alloc(MaxType+1, Boolean); } Verbose(2) putchar('\n'); ForEach(T1, 1, MaxType) { Compatible[T1][T1] = true; ForEach(T2, T1+1, MaxType) { Compatible[T1][T2] = Compatible[T2][T1] = ( Type[T1]->Continuous || Type[T2]->Continuous ) ? false: CommonValue(Type[T1]->NValues, Type[T1]->Value, Type[T2]->NValues, Type[T2]->Value); Verbose(2) { printf("Types %s and %s %s compatible\n", Type[T1]->Name, Type[T2]->Name, Compatible[T1][T2] ? "are" : "are not"); } } } } Boolean CommonValue(int N1, Const *V1, int N2, Const *V2) /* ----------- */ { int i, j; ForEach(i, 0, N1-1) { ForEach(j, 0, N2-1) { if ( V1[i] == V2[j] ) return true; } } return false; } int Number(Tuple *T) /* ------ */ { int Count=0; if ( ! T ) return 0; while ( *T++ ) { Count++; } return Count; } char *CopyString(char *s) /* ---------- */ { char *new; int l; l = strlen(s) + 1; new = Alloc(l, char); memcpy(new, s, l); return new; } void Error(int n, char *s1, char *s2) /* ----- */ { switch ( n ) { case 1: printf("Illegal delimiter after %s\n", s1); exit(1); case 2: printf("Something wrong after %s in type %s\n", s1, s2); exit(1); case 3: printf("Undeclared constant %s\n", s1); exit(1); case 4: printf("Constant %s is not of type %s\n", s1, s2); exit(1); case 5: printf("Undeclared type %s\n", s1); exit(1); case 6: printf("Cannot use CWA for %s (continuous types)\n", s1); exit(1); case 7: printf("Type %s contains duplicate constant %s\n", s2, s1); exit(1); } } /* Check for arguments that cannot be equal */ void UnequalArgsCheck(Relation R) /* ---------------- */ { Var S, F; R->ArgNotEq = AllocZero(ArgPair(R->Arity,R->Arity), Boolean); ForEach(S, 2, R->Arity) { ForEach(F, 1, S-1) { R->ArgNotEq[ ArgPair(S,F) ] = NeverEqual(R->Pos, F, S); } } } Boolean NeverEqual(Tuple *T, Var F, Var S) /* ---------- */ { Tuple Case; while ( Case = *T++ ) { if ( Case[F] == Case[S] && Case[F] != OUT_OF_RANGE ) return false; } return true; } @//E*O*F input.c// chmod u=rw,g=,o= input.c echo x - interpret.c sed 's/^@//' > "interpret.c" <<'@//E*O*F interpret.c//' /******************************************************************************/ /* */ /* Routines for evaluating a definition on a case. Used both during */ /* pruning and when testing definitions found */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" #define HighestVar Current.MaxVar /* must be set externally! */ Boolean RecordArgOrders = false; /* flag set by prune */ Const *Value = Nil; /* current variable bindings */ Boolean CheckRHS(Clause C) /* -------- */ { Relation R; Tuple Case, *Bindings, *Scan; Literal L; int i, N; Var *A, V, W; Const KVal, *CopyValue; float VVal, WVal; Ordering ThisOrder, PrevOrder; Boolean SomeOrder=false; if ( ! (L = C[0]) ) return true; R = L->Rel; A = L->Args; N = R->Arity; /* If literal marked inactive, ignore */ if ( A[0] ) return CheckRHS(C+1); /* Record types of unbound variables */ ForEach(i, 1, N) { V = A[i]; if ( Value[V] == UNBOUND ) Variable[V]->TypeRef = R->TypeRef[i]; } /* Check for missing values */ if ( MissingValue(R, A, Value) ) return false; /* Adjust ordering information for recursive literals if required */ if ( RecordArgOrders && R == Target ) { ForEach(V, 1, N) { W = A[V]; if ( Value[W] == UNBOUND ) { ThisOrder = '#'; } else { if ( Variable[V]->TypeRef->Continuous ) { VVal = FP(Value[V]); WVal = FP(Value[W]); } else { VVal = Variable[V]->TypeRef->CollSeq[Value[V]]; WVal = Variable[V]->TypeRef->CollSeq[Value[W]]; } ThisOrder = ( VVal < WVal ? '<' : VVal > WVal ? '>' : '=' ); } PrevOrder = L->ArgOrders[V]; if ( PrevOrder != ThisOrder ) { L->ArgOrders[V] = ( ! PrevOrder ? ThisOrder : '#' ); } ThisOrder = L->ArgOrders[V]; SomeOrder |= ( ThisOrder == '<' || ThisOrder == '>' ); } if ( ! SomeOrder ) { return RecordArgOrders = false; } } /* Various possible cases */ if ( Predefined(R) ) { if ( HasConst(R) ) { GetParam(&A[2], &KVal); } else { KVal = A[2]; } return Satisfies((int)R->Pos, A[1], KVal, Value) == (L->Sign != 0) && CheckRHS(C+1); } if ( ! L->Sign ) { return ( ! Join(R->Pos, R->PosIndex, A, Value, N, true) ) && CheckRHS(C+1); } if ( ! Join(R->Pos, R->PosIndex, A, Value, N, false) ) return false; /* Each tuple found represents a possible binding for the free variables in A. Copy them (to prevent overwriting on subsequent calls to Join) and try them in sequence */ Bindings = Alloc(NFound+1, Tuple); memcpy(Bindings, Found, (NFound+1)*sizeof(Tuple)); CopyValue = Alloc(MAXVARS+1, Const); memcpy(CopyValue, Value, (HighestVar+1)*sizeof(Const)); Scan = Bindings; /* Check rest of RHS */ while ( Case = *Scan++ ) { ForEach(i, 1, N) { V = L->Args[i]; if ( Value[V] == UNBOUND ) Value[V] = Case[i]; } if ( CheckRHS(C+1) ) { pfree(Bindings); memcpy(Value, CopyValue, (HighestVar+1)*sizeof(Const)); pfree(CopyValue); return true; } memcpy(Value, CopyValue, (HighestVar+1)*sizeof(Const)); } pfree(Bindings); pfree(CopyValue); return false; } Boolean Interpret(Relation R, Tuple Case) /* --------- */ { int i; ForEach(i, 1, R->Arity) { Variable[i]->TypeRef = R->TypeRef[i]; } InitialiseValues(Case, R->Arity); for ( i = 0 ; R->Def[i] ; i++ ) { if ( CheckRHS(R->Def[i]) ) return true; } return false; } void InitialiseValues(Tuple Case, int N) /* ---------------- */ { int i; if ( ! Value ) { Value = Alloc(MAXVARS+1, Const); } ForEach(i, 1, N) { Value[i] = Case[i]; } ForEach(i, N+1, MAXVARS) { Value[i] = UNBOUND; } } @//E*O*F interpret.c// chmod u=rw,g=,o= interpret.c echo x - join.c sed 's/^@//' > "join.c" <<'@//E*O*F join.c//' #include "defns.i" #include "extern.i" /* Given tuples T with index TIX, find the tuples that satisfy the column and same-value constraints on case C. Leave the tuples in Found with their number in NFound */ /* NB: Foil spends a large proportion of its execution time in this single routine. For that reason, the code has been written for speed (on a DECstation), even though this has reduced its clarity. If using different hardware, it would probably be worth rewriting this */ int FoundSize = 0; Boolean Join(Tuple *T, Index TIX, Var *A, Tuple C, int N, Boolean YesOrNo) /* ---- */ { static int *Pair, /* Pair[i], Pair[i+1] are paired variables */ *Contin, /* Contin[i] is a continuous variable that must have the given value */ **Next; /* Next[i] = next tuple obeying ith constraint */ static Boolean *Checked; int *MaxPair, /* highest pair of same variables */ *PairPtr, *MaxContin, /* highest continuous variable */ *ContinPtr, MaxCol=0, /* highest column constraint */ MaxNo=0, /* index numbers in relation */ **NextPtr, **LastNext, V, Val, i, j; Boolean NoCols; Tuple Candidate; /* Allocate arrays first time through */ if ( ! FoundSize ) { Pair = Alloc(2*(MAXVARS+1), int); Next = Alloc(MAXVARS+1, int *); Checked = Alloc(MAXVARS+1, Boolean); Contin = Alloc(MAXVARS+1, int); FoundSize = 20000; Found = Alloc(FoundSize+1, Tuple); } MaxPair = Pair; MaxContin = Contin; NFound = 0; OutOfWorld = false; /* Set the column constraints and find pairs of free variables that must be the same */ memset(Checked+1, 0, N); ForEach(i, 1, N) { /* If this variable is bound, record a constraint; otherwise see if it is the same as another unbound variable */ if ( (V = A[i]) <= Current.MaxVar && (Val = C[V]) != UNBOUND ) { if ( Variable[V]->TypeRef->Continuous ) *MaxContin++ = i; else if ( ! (Next[MaxCol++] = TIX[i][Val]) ) return false; } else if ( ! Checked[i] ) { ForEach(j, i+1, N) { if ( A[j] == V ) { *MaxPair++ = i; *MaxPair++ = j; Checked[j] = true; } } } } NoCols = MaxCol-- <= 0; LastNext = Next + MaxCol; while ( true ) { /* Advance all columns to MaxNo */ for ( NextPtr = Next ; NextPtr <= LastNext ; ) { while ( **NextPtr < MaxNo ) (*NextPtr)++; MaxNo = **NextPtr++; } if ( MaxNo == FINISH || NoCols && ! T[MaxNo] ) { Found[NFound] = Nil; return (NFound > 0); } else if ( NoCols || MaxNo == *Next[0] ) { /* Found one possibility -- check same variable constraints */ Candidate = T[MaxNo]; for ( PairPtr = Pair ; PairPtr < MaxPair && Candidate[*PairPtr] == Candidate[*(PairPtr+1)] ; PairPtr += 2 ) ; for ( ContinPtr = Contin ; ContinPtr < MaxContin && Candidate[*ContinPtr] == C[ A[*ContinPtr] ] ; ContinPtr++ ) ; if ( PairPtr >= MaxPair && ContinPtr >= MaxContin ) { if ( YesOrNo ) return true; if ( NFound >= FoundSize ) { FoundSize += 20000; Realloc(Found, FoundSize+1, Tuple); } Found[NFound++] = Candidate; /* Check for falling off the end of the (closed) world */ for ( i = 1 ; ! OutOfWorld && i <= N ; i++ ) { if ( Candidate[i] == OUT_OF_RANGE ) { OutOfWorld = true; Found[NFound] = Nil; return true; } } } MaxNo++; } } } @//E*O*F join.c// chmod u=rw,g=,o= join.c echo x - literal.c sed 's/^@//' > "literal.c" <<'@//E*O*F literal.c//' /******************************************************************************/ /* */ /* Examine the space of possible literals on a relation */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" #define MAXTIME 100 Var *Arg = Nil; /* potential arguments */ Boolean CountOnly; float StartTime; /* CPU time at start of literal */ int Ticks, /* calls of TryArgs() */ TicksCheck; /* point to check time again */ /* Examine possible variable assignments for next literal using relation R. If CountOnly specified, this will only set the number of them in R->NTrialArgs; otherwise, it will evaluate the possible arguments */ void ExploreArgs(Relation R, Boolean CountFlag) /* ----------- */ { int MaxArgs=1; Var V; CountOnly = CountFlag; if ( CountOnly ) { R->NTrialArgs = 0; } else { R->NTried = 0; } if ( R == Target && ! AnyPartialOrder ) return; if ( Predefined(R) ) { if ( R == EQVAR ) { ExploreEQVAR(); } else if ( R == EQCONST ) { ExploreEQCONST(); } else if ( R == GTVAR ) { ExploreGTVAR(); } else if ( R == GTCONST ) { ExploreGTCONST(); } return; } if ( CountOnly ) { /* Carry out a preliminary feasibility check */ for ( V = 1 ; MaxArgs <= 1E7 && V <= R->Arity ; V++ ) { MaxArgs *= EstimatePossibleArgs(R->Type[V]); } if ( MaxArgs > 1E7 ) { Verbose(2) { printf("\t\t\t\t[%s: too many possibilities]\n", R->Name); } R->NTrialArgs = 0; return; } } else { Ticks = 0; TicksCheck = 10; StartTime = CPUTime(); } TryArgs(R, 1, Current.MaxVar, 0, 0, 0, true, false); } int EstimatePossibleArgs(int TNo) /* -------------------- */ { int Sum=1, V; ForEach(V, 1, Current.MaxVar) { if ( Compatible[Variable[V]->Type][TNo] ) Sum++; } return Sum; } /* Determine whether a key is acceptable for the relation being explored. Note that keys are packed bit strings with a 1 wherever there is an unbound variable */ Boolean AcceptableKey(Relation R, int Key) /* ------------- */ { int i; if ( ! R->NKeys ) return true; ForEach(i, 0, R->NKeys-1) { if ( (R->Key[i] | Key) == R->Key[i] ) return true; } return false; } /* See whether a potential literal is actually a repeat of a literal already in the clause (with perhaps different free variables) */ Boolean Repetitious(Relation R, Var *A) /* ----------- */ { Literal L; Var V, MaxV; int i, a, N; MaxV = Target->Arity; ForEach(i, 0, NLit-1) { L = NewClause[i]; if ( L->Rel == R && SameArgs(R->Arity, A, Current.MaxVar, L->Args, MaxV, i+1) ) { return true; } if ( L->Sign ) { N = L->Rel->Arity; ForEach(a, 1, N) { if ( (V = L->Args[a]) > MaxV ) MaxV = V; } } } return false; } Boolean Mentioned(Var V, int First) /* --------- */ { int i, a, N; Literal L; ForEach(i, First, NLit-1) { L = NewClause[i]; N = L->Rel->Arity; ForEach(a, 1, N) { if ( L->Args[a] == V ) return true; } } return false; } /* Check whether two aruments are identical up to substitution of free variables */ Boolean SameArgs(int N, Var *A1, int MV1, Var *A2, int MV2, int LN) /* -------- */ { int a; ForEach(a, 1, N) { if ( ( A1[a] <= MV1 ? A2[a] != A1[a] : ( A2[a]-MV2 != A1[a]-MV1 || Mentioned(A2[a], LN) ) ) ) { return false; } } return true; } /* Find arguments for predefined relations */ void ExploreEQVAR() /* ------------ */ { Var V, W; ForEach(V, 1, Current.MaxVar-1) { if ( Barred[V] ) continue; Arg[1] = V; ForEach(W, V+1, Current.MaxVar) { if ( Barred[W] ) continue; if ( Compatible[Variable[V]->Type][Variable[W]->Type] ) { if ( CountOnly ) { EQVAR->NTrialArgs++; } else { Arg[2] = W; EvaluateLiteral(EQVAR, Arg, EQVAR->Bits, Nil); EQVAR->NTried++; } } } } } void ExploreEQCONST() /* -------------- */ { Var V; int T, i, n; Const C; Boolean *VarBound; Literal L; /* Find variables that have bound values */ VarBound = AllocZero(Current.MaxVar+1, Boolean); ForEach(i, 0, NLit-1) { L = NewClause[i]; if ( L->Rel == EQCONST && L->Sign ) { VarBound[L->Args[1]] = true; } } ForEach(V, 1, Current.MaxVar) { if ( Barred[V] || VarBound[V] ) continue; T = Variable[V]->Type; if ( n = Type[T]->NTheoryConsts ) { Arg[1] = V; ForEach(i, 0, n-1) { if ( CountOnly ) { EQCONST->NTrialArgs++; } else { C = Type[T]->TheoryConst[i]; SaveParam(&Arg[2], &C); EvaluateLiteral(EQCONST, Arg, EQCONST->Bits, Nil); EQCONST->NTried++; } } } } free(VarBound); } void ExploreGTVAR() /* ------------ */ { Var V, W; ForEach(V, 1, Current.MaxVar-1) { if ( Barred[V] || ! Variable[V]->TypeRef->Continuous ) continue; Arg[1] = V; ForEach(W, V+1, Current.MaxVar) { if ( Barred[W] || Variable[W]->Type != Variable[V]->Type ) continue; if ( CountOnly ) { GTVAR->NTrialArgs++; } else { Arg[2] = W; EvaluateLiteral(GTVAR, Arg, GTVAR->Bits, Nil); GTVAR->NTried++; } } } } void ExploreGTCONST() /* -------------- */ { Var V; float Z=MISSING_FP; ForEach(V, 1, Current.MaxVar) { if ( Barred[V] || ! Variable[V]->TypeRef->Continuous ) continue; if ( CountOnly ) { GTCONST->NTrialArgs++; } else { Arg[1] = V; SaveParam(&Arg[2], &Z); EvaluateLiteral(GTCONST, Arg, GTCONST->Bits, Nil); GTCONST->NTried++; } } } /* Generate argument lists starting from position This. In the partial argument list Arg[1]..Arg[This-1], HiVar is the highest variable (min value MaxVar) FreeVars is the number of free variable occurrences MaxDepth is the highest depth of a bound variable Key gives the key so far TryMostGeneral is true when we need to fill all remaining argument positions with new free variables. RecOK is true when a more general argument list has been found to satisfy RecursiveCallOK(), so this must also. Return false if hit time limit. */ Boolean TryArgs(Relation R, int This, int HiVar, int FreeVars, int MaxDepth, int Key, Boolean TryMostGeneral, Boolean RecOK) /* ------- */ { Var V, W, MaxV; Boolean Prune, UselessSameVar; int NewFreeVars, NewMaxDepth, CopyKey; float TimeSpent; /* This version contains a time cutout to prevent too much effort begin invested in a single literal. Unfortunately, direct monitoring of time is too expensive (in system time and overhead) so a more circuitous method that calls CPUTime() rarely is used */ if ( ! CountOnly ) { if ( Ticks > TicksCheck ) { if ( (TimeSpent = CPUTime() - StartTime) > MAXTIME ) { return false; } else if ( TimeSpent > 0.001 * MAXTIME ) { TicksCheck += 0.01 * Ticks * MAXTIME / TimeSpent; } else { TicksCheck *= 10; } } Ticks++; } /* Try with all remaining positions (if any) as new free variables */ NewFreeVars = R->Arity - This + 1; if ( TryMostGeneral && HiVar + NewFreeVars <= MAXVARS /* enough variables */ && FreeVars < This-1 /* at least one bound */ && ( ! NewFreeVars || MaxDepth < MAXVARDEPTH ) ) { CopyKey = Key; ForEach(V, This, R->Arity) { Arg[V] = W = HiVar + (V - This + 1); CopyKey |= 1<Type = R->Type[V]; Variable[W]->TypeRef = R->TypeRef[V]; } if ( AcceptableKey(R, CopyKey) && ( R != Target || RecOK || (RecOK = RecursiveCallOK(Arg)) ) ) { if ( CountOnly ) { R->NTrialArgs++; } else if ( ! Repetitious(R, Arg) ) { EvaluateLiteral(R, Arg, R->Bits, &Prune); R->NTried++; if ( Prune && NewFreeVars ) { Verbose(3) printf("\t\t\t\t(pruning subsumed arguments)\n"); return true; } } } } if ( This > R->Arity ) return true; /* Now try substitutions recursively */ MaxV = ( Predefined(R) ? HiVar : This < R->Arity && HiVar < MAXVARS ? HiVar+1 : HiVar ); for ( V = 1 ; V <= MaxV && BestLitGain < MaxPossibleGain ; V++ ) { if ( V <= Current.MaxVar ) { if ( Barred[V] ) continue; NewMaxDepth = Max(MaxDepth, Variable[V]->Depth); NewFreeVars = FreeVars; } else { NewMaxDepth = MaxDepth; NewFreeVars = FreeVars+1; } if ( V > HiVar ) { Variable[V]->Type = R->Type[This]; Variable[V]->TypeRef = R->TypeRef[This]; Key |= 1<ArgNotEq[ ArgPair(This,W) ]; } if ( UselessSameVar || V <= HiVar && ! Compatible[Variable[V]->Type][R->Type[This]] || NewMaxDepth + (NewFreeVars > 0) > MAXVARDEPTH || R->BinSym && This == 2 && V < Arg[1] ) { continue; } Arg[This] = V; if ( ! TryArgs(R, This+1, Max(HiVar, V), NewFreeVars, NewMaxDepth, Key, V <= HiVar, RecOK) ) return false; } return true; } @//E*O*F literal.c// chmod u=rw,g=,o= literal.c echo x - main.c sed 's/^@//' > "main.c" <<'@//E*O*F main.c//' #include "defns.i" #include "extern.i" /* Read parameters and initialise variables */ void main(int Argc, char *Argv[]) /* ---- */ { int o, i, Cases, Errors; extern char *optarg; extern int optind; Boolean FirstTime=true; Var V; extern Var *Arg; /* in literal.c */ Relation R; Tuple Case; char Line[200], PlusOrMinus; /* Check overlaying of Const and float */ if ( sizeof(Const) != sizeof(float) ) { printf("Integers and floating point numbers are different sizes\n"); printf("Alter declaration of type Const (defns.i) and recompile\n"); exit(1); } printf("FOIL 6.4 [January 1996]\n--------\n"); /* Process options */ while ( (o = getopt(Argc, Argv, "nNus:a:f:g:V:d:A:w:l:t:m:v:")) != EOF ) { if ( FirstTime ) { printf("\n Options:\n"); FirstTime = false; } switch (o) { case 'n': NEGLITERALS = NEGEQUALS = false; printf("\tno negated literals\n"); break; case 'N': NEGLITERALS = false; printf("\tnegated literals only for =, > relations\n"); break; case 'u': /*UNIFORMCODING = true;*/ printf("\tuniform coding of literals not available\n"); break; case 's': SAMPLE = atof(optarg); printf("\tsample %g%% of negative tuples\n", SAMPLE); SAMPLE /= 100; break; case 'a': MINACCURACY = atof(optarg); printf("\tminimum clause accuracy %g%%\n",MINACCURACY); MINACCURACY /= 100; break; case 'f': MINALTFRAC = atof(optarg); printf("\tbacked-up literals have %g%% of best gain\n", MINALTFRAC); MINALTFRAC /= 100; break; case 'g': i = atoi(optarg); printf("\tuse determinate literals when gain <= "); printf("%d%% possible\n", i); DETERMINATE = i / 100.0; break; case 'V': MAXVARS = atoi(optarg); if ( MAXVARS > pow(2.0, 8*sizeof(Var)-1.0) ) { MAXVARS = pow(2.0, 8*sizeof(Var)-1.0) -0.9; } printf("\tallow up to %d variables\n", MAXVARS); break; case 'd': MAXVARDEPTH = atoi(optarg); printf("\tmaximum variable depth %d\n", MAXVARDEPTH); break; case 'w': MAXWEAKLITS = atoi(optarg); printf("\tallow up to %d consecutive weak literals\n", MAXWEAKLITS); break; case 'l': MAXPOSSLIT = atoi(optarg)+1; printf("\tmaximum %d backups from one literal\n", MAXPOSSLIT-1); break; case 't': MAXALTS = atoi(optarg); printf("\tmaximum %d total backups\n", MAXALTS); break; case 'm': MAXTUPLES = atoi(optarg); printf("\tmaximum %d tuples \n", MAXTUPLES); break; case 'v': VERBOSITY = atoi(optarg); printf("\tverbosity level %d\n", VERBOSITY); break; case '?': printf("unrecognised option\n"); exit(1); } } /* Set up predefined relations. These are treated specially in Join(). Rather than giving explicit pos tuples, the Pos field identifies the relation */ /* Note: EQCONST and GTCONST take one argument and one parameter (a theory constant or floating-point threshold). To simplify the code for all other relations, this parameter is packed into a "standard" arglist; the number of variable positions that it occupies will depend on the implementation. */ Reln = Alloc(10, Relation); EQVAR = AllocZero(1, struct _rel_rec); EQVAR->Name = "="; EQVAR->Arity = 2; EQVAR->Type = AllocZero(3, int); EQVAR->TypeRef = AllocZero(3, TypeInfo); EQVAR->Pos = (Tuple *) 0; EQVAR->BinSym = true; EQCONST = AllocZero(1, struct _rel_rec); EQCONST->Name = "=="; EQCONST->Arity = 1; EQCONST->Type = AllocZero(2, int); EQCONST->TypeRef = AllocZero(2, TypeInfo); EQCONST->Pos = (Tuple *) 1; EQCONST->BinSym = false; GTVAR = AllocZero(1, struct _rel_rec); GTVAR->Name = ">"; GTVAR->Arity = 2; GTVAR->Type = AllocZero(3, int); GTVAR->TypeRef = AllocZero(3, TypeInfo); GTVAR->Pos = (Tuple *) 2; GTVAR->BinSym = true; GTCONST = AllocZero(1, struct _rel_rec); GTCONST->Name = ">"; GTCONST->Arity = 1; GTCONST->Type = AllocZero(2, int); GTCONST->TypeRef = AllocZero(2, TypeInfo); GTCONST->Pos = (Tuple *) 3; GTCONST->BinSym = false; MaxRel = 3; ForEach(i, 0, MaxRel) { Reln[i]->PossibleTarget = false; } /* Read input */ ReadTypes(); CheckTypeCompatibility(); ReadRelations(); /* Initialise all global variables that depend on parameters */ Variable = Alloc(MAXVARS+1, VarInfo); DefaultVars = Alloc(MAXVARS+1, Var); ForEach(V, 0, MAXVARS) { Variable[V] = Alloc(1, struct _var_rec); if ( V == 0 ) { Variable[0]->Name = "_"; } else if ( V <= 26 ) { Variable[V]->Name = Alloc(2, char); Variable[V]->Name[0] = 'A' + V - 1; Variable[V]->Name[1] = '\0'; } else { Variable[V]->Name = Alloc(3, char); Variable[V]->Name[0] = 'A' + ((V-27) / 26); Variable[V]->Name[1] = 'A' + ((V-27) % 26); Variable[V]->Name[2] = '\0'; } DefaultVars[V] = V; } Barred = AllocZero(MAXVARS+1, Boolean); ToBeTried = Alloc(MAXALTS+1, Alternative); ForEach(i, 0, MAXALTS) { ToBeTried[i] = Alloc(1, struct _backup_rec); ToBeTried[i]->UpToHere = Nil; } PartialOrder = Alloc(MAXARGS+1, Boolean *); ForEach(V, 1, MAXARGS) { PartialOrder[V] = Alloc(MAXVARS+1, Boolean); } Possible = Alloc(MAXPOSSLIT+1, PossibleLiteral); ForEach(i, 1, MAXPOSSLIT) { Possible[i] = Alloc(1, struct _poss_lit_rec); Possible[i]->Args = Alloc(MAXARGS+1, Var); } Arg = Alloc(MAXARGS+1, Var); Arg[0] = 0; /* active */ /* Allocate space for trial recursive call */ RecursiveLitOrders = Alloc(1, Ordering *); RecursiveLitOrders[0] = Alloc(MAXARGS+1, Ordering); /* Find plausible orderings for constants of each type */ OrderConstants(); /* Find Definitions */ ForEach(i, 0, MaxRel) { R = RelnOrder[i]; if ( R->PossibleTarget ) { FindDefinition(R); } } /* Test definitions */ while ( gets(Line) ) { R = Nil; for ( i = 0 ; i <= MaxRel && ! R ; i++ ) { if ( ! strcmp(RelnOrder[i]->Name, Line) ) R = RelnOrder[i]; } if ( ! R ) { printf("\nUnknown relation %s\n", Line); exit(1); } else { printf("\nTest relation %s\n", Line); } Cases = Errors = 0; Current.MaxVar = HighestVarInDefinition(R); while ( Case = ReadTuple(R) ) { while ( (PlusOrMinus = getchar()) == ' ' || PlusOrMinus == '\t' ) ; ReadToEOLN; Cases++; if ( Interpret(R, Case) != ( PlusOrMinus == '+' ) ) { Verbose(1) { printf(" (%c)", PlusOrMinus); PrintTuple(Case, R->Arity, R->TypeRef, false); } Errors++; } } printf("Summary: %d error%s in %d trial%s\n", Errors, Plural(Errors), Cases, Plural(Cases)); } exit(0); } @//E*O*F main.c// chmod u=rw,g=,o= main.c echo x - member.d sed 's/^@//' > "member.d" <<'@//E*O*F member.d//' X: 1, 2, 3. L: [111], [112], [113], [11], [121], [122], [123], [12], [131], [132], [133], [13], [1], [211], [212], [213], [21], [221], [222], [223], [22], [231], [232], [233], [23], [2], [311], [312], [313], [31], [321], [322], [323], [32], [331], [332], [333], [33], [3], *[]. member(X,L) 1,[1] 3,[3] 1,[11] 1,[13] 3,[13] 1,[31] 3,[31] 3,[33] 1,[111] 1,[113] 3,[113] 1,[131] 3,[131] 1,[133] 3,[133] 1,[311] 3,[311] 1,[313] 3,[313] 1,[331] 3,[331] 3,[333] ; 1,[] 1,[3] 1,[33] 1,[333] 3,[] 3,[1] 3,[11] 3,[111] 1,[2] 1,[22] 1,[23] 1,[32] 1,[222] 1,[223] 1,[232] 1,[233] 1,[322] 1,[323] 1,[332] @. *components(L,X,L) #--/-## [1],1,[] [2],2,[] [3],3,[] [11],1,[1] [12],1,[2] [13],1,[3] [21],2,[1] [22],2,[2] [23],2,[3] [31],3,[1] [32],3,[2] [33],3,[3] [111],1,[11] [112],1,[12] [113],1,[13] [121],1,[21] [122],1,[22] [123],1,[23] [131],1,[31] [132],1,[32] [133],1,[33] [211],2,[11] [212],2,[12] [213],2,[13] [221],2,[21] [222],2,[22] [223],2,[23] [231],2,[31] [232],2,[32] [233],2,[33] [311],3,[11] [312],3,[12] [313],3,[13] [321],3,[21] [322],3,[22] [323],3,[23] [331],3,[31] [332],3,[32] [333],3,[33] @. member 2,[]: - 3,[121]: - 3,[23]: + 3,[232]: + @. @//E*O*F member.d// chmod u=rw,g=,o= member.d echo x - member.explain sed 's/^@//' > "member.explain" <<'@//E*O*F member.explain//' >>>>>> This file contains comments interspersed with FOIL6.4 input and >>>>>> output. Comments (even blank lines) begin with >>>>>>. >>>>>> >>>>>> The first section of input identifies the types and the constants >>>>>> associated with each type. Here there are two types, X and L >>>>>> (corresponding to element and list). Individual constant names >>>>>> can be complex; remember, though, that any structure implied by >>>>>> the name is invisible to FOIL. The * in front of [] indicates >>>>>> that this is a 'theory constant' that can appear in the learned >>>>>> definition. The blank line following the last type delineates >>>>>> this section from the next. >>>>>> X: 1, 2, 3. L: [111], [112], [113], [11], [121], [122], [123], [12], [131], [132], [133], [13], [1], [211], [212], [213], [21], [221], [222], [223], [22], [231], [232], [233], [23], [2], [311], [312], [313], [31], [321], [322], [323], [32], [331], [332], [333], [33], [3], *[]. >>>>>> >>>>>> The second section defines relations by specifying the tuples of >>>>>> constants that they contain ('positive' tuples); tuples that do >>>>>> not belong in the relation can be listed explicitly or FOIL can >>>>>> determine them using the closed world assumption. Here member >>>>>> is a relation with two arguments, an element and a list. The >>>>>> pairs 1,[1] through 3,[333] are given as belonging to member >>>>>> while 1,[] through 1,[332] are noted as not belonging to member >>>>>> ('negative' tuples). >>>>>> member(X,L) 1,[1] 3,[3] 1,[11] 1,[13] 3,[13] 1,[31] 3,[31] 3,[33] 1,[111] 1,[113] 3,[113] 1,[131] 3,[131] 1,[133] 3,[133] 1,[311] 3,[311] 1,[313] 3,[313] 1,[331] 3,[331] 3,[333] ; 1,[] 1,[3] 1,[33] 1,[333] 3,[] 3,[1] 3,[11] 3,[111] 1,[2] 1,[22] 1,[23] 1,[32] 1,[222] 1,[223] 1,[232] 1,[233] 1,[322] 1,[323] 1,[332] @. >>>>>> >>>>>> The input then defines another relation components with three >>>>>> arguments: a list, an element (the head of the list) and another >>>>>> list (the tail of the list). The asterisk in front of the >>>>>> relation name tells FOIL not to construct a definition for it. >>>>>> After the closing parenthesis there is a blank and the characters >>>>>> '#--/-##'. This is a 'key' (similar to that used in databases); >>>>>> to use this relation, either the value of the first argument or >>>>>> the values of both the second and third argument must be known, >>>>>> meaning that the corresponding variables in the definition must be >>>>>> bound. >>>>>> *components(L,X,L) #--/-## [1],1,[] [2],2,[] [3],3,[] [11],1,[1] [12],1,[2] [13],1,[3] [21],2,[1] [22],2,[2] [23],2,[3] [31],3,[1] [32],3,[2] [33],3,[3] [111],1,[11] [112],1,[12] [113],1,[13] [121],1,[21] [122],1,[22] [123],1,[23] [131],1,[31] [132],1,[32] [133],1,[33] [211],2,[11] [212],2,[12] [213],2,[13] [221],2,[21] [222],2,[22] [223],2,[23] [231],2,[31] [232],2,[32] [233],2,[33] [311],3,[11] [312],3,[12] [313],3,[13] [321],3,[21] [322],3,[22] [323],3,[23] [331],3,[31] [332],3,[32] [333],3,[33] @. >>>>>> >>>>>> Any number of relations may be defined. The order does not matter, >>>>>> as FOIL will reorder them anyway. This section also ends with a >>>>>> blank line. >>>>>> >>>>>> The final section contains cases to test the definitions found. >>>>>> The first line names the relation to be tested, followed by test >>>>>> tuples. Each tuple ends with a colon, space, and a sign that >>>>>> indicates whether or not the tuple is supposed to satisfy the >>>>>> definition. The test parcel ends with a line containing a period; >>>>>> there can be any number of such parcels. >>>>>> member 2,[]: - 3,[121]: - 3,[23]: + 3,[232]: + @. >>>>>> >>>>>> Let us now examine the output produced by FOIL for this example. >>>>>> The command used to run FOIL was 'foil6 -n -v3 >>>>> -n excludes negated literals and -v3 selects fairly verbose output. >>>>>> FOIL 6.4 [January 1996] -------- Options: no negated literals verbosity level 3 Types X and L are not compatible Relation member Relation *components >>>>>> >>>>>> After reading the relations, FOIL tries to find ordering for >>>>>> the constants of types X and L. It fails to find an ordering >>>>>> for type X, but discovers one for type L -- the original >>>>>> unhelpful lexicographic order (produced by 'sort') has been >>>>>> replaced by a length ordering. >>>>>> Ordering constants of type X Checking arguments of member Checking arguments of ~member Checking arguments of components unordered Ordering constants of type L Checking arguments of member Checking arguments of ~member Checking arguments of components arguments 1,3 are consistent Finding maximal consistent set best so far components:1>3 Final order: [] [1] [2] [3] [11] [12] [13] [21] [22] [23] [31] [32] [33] [111] [112] [113] [121] [122] [123] [131] [132] [133] [211] [212] [213] [221] [222] [223] [231] [232] [233] [311] [312] [313] [321] [322] [323] [331] [332] [333] ---------- member: >>>>>> >>>>>> FOIL then commences the search for the first clause of the >>>>>> definition of member. There are initially 22 positive tuples, >>>>>> 41 tuples in all. Literals are evaluated to see the result >>>>>> of adding them to the clause. If the literal "B=[]" were >>>>>> added, the clause would be satisfied by only two of the 41 >>>>>> tuples, 0 of them being positive. The negated form of this >>>>>> literal would be satisfied by 39 of the 41 tuples, of which >>>>>> 22 would be positive. The gains for the unnegated and negated >>>>>> forms of this literal would then be 0.0 bits and 1.5 bits >>>>>> respectively. >>>>>> State (22/41, 47.5 bits available) >>>>>> >>>>>> Evaluation of the literal B=[] is abandoned when it becomes clear >>>>>> that no plus tuples are covered by it. >>>>>> B=[] 0[0/1] [22/22] abandoned(56%) [== tried 1/1] 0.0 secs >>>>>> >>>>>> The following literal is noted as determinate ('[Det]'). >>>>>> components(B,C,D) 22[22/39] [Det] gain 1.5 components(B,A,C) 14[14/14] gain 12.2 >>>>>> >>>>>> Evaluation of the following literal is also pruned since it cannot >>>>>> achieve a gain as high as the previous one. >>>>>> components(C,A,B) 8[8/8] [9/9] abandoned(41%) [components tried 3/3] 0.0 secs >>>>>> >>>>>> Even though the following literal is not chosen, it is remembered >>>>>> since it would produce a complete clause. >>>>>> Save clause ending with components(B,A,C) (cover 14, accuracy 100%) >>>>>> >>>>>> The literal added is the determinate literal components(B,C,D); >>>>>> under the ordering discovered for type L, variable B is now >>>>>> greater than variable D. >>>>>> Determinate literals components(B,C,D) Note B>D State (22/39, 47.5 bits available, 1 weak literal) B=[] 0[0/0] # D=[] 2[2/5] [20/24] abandoned(74%) [== tried 2/2] 0.0 secs A=C 14[14/14] gain 11.2 B=D 0[0/0] [11/11] abandoned(28%) [= tried 2/2] 0.0 secs member(A,D) 16[16/16] gain 12.8 member(C,D) 7[7/7] [10/10] abandoned(43%) member(E,D) 20[28/34] gain 10.5 [member tried 3/3] 0.0 secs components(B,A,E) 14[14/14] D=E # components(B,A,D) 14[14/14] gain 11.2 components(B,C,E) 22[22/39] D=E [XDet] # components(D,E,F) 20[20/25] [2/5] abandoned(76%) components(D,A,E) 10[10/10] [10/10] abandoned(51%) (pruning subsumed arguments) components(D,C,E) 5[5/5] [10/10] abandoned(38%) (pruning subsumed arguments) components(D,E,B) 0[0/0] [10/10] abandoned(25%) components(E,A,B) 8[8/8] [10/10] abandoned(46%) components(E,A,D) 22[22/39] [Det] gain 0.0 components(E,C,B) 8[8/8] [7/7] abandoned(38%) components(E,C,D) 22[22/39] B=E [XDet] # [components tried 11/16] 0.0 secs >>>>>> >>>>>> We now have a better saveable clause. >>>>>> Save clause ending with member(A,D) (cover 16, accuracy 100%) Determinate literals components(E,A,D) Note B>D State (22/39, 47.5 bits available, 2 weak literals) B=[] 0[0/0] # D=[] 2[2/5] [20/24] abandoned(74%) E=[] 0[0/0] # [== tried 3/3] 0.0 secs A=C 14[14/14] gain 11.2 B=D 0[0/0] [11/11] abandoned(28%) B=E 14[14/14] gain 11.2 D=E 0[0/0] [11/11] abandoned(28%) [= tried 4/4] 0.0 secs member(A,D) 16[16/16] gain 12.8 member(C,D) 7[7/7] [10/10] abandoned(43%) member(F,D) 20[28/34] gain 10.5 [member tried 3/3] 0.0 secs components(B,F,G) 22[22/39] C=F D=G [XDet] # components(B,A,F) 14[14/14] D=F # components(B,A,D) 14[14/14] gain 11.2 components(B,A,E) 0[0/0] [9/9] abandoned(23%) components(B,C,F) 22[22/39] D=F [XDet] # components(B,C,E) 0[0/0] [9/9] abandoned(23%) components(B,F,E) 0[0/0] [9/9] abandoned(23%) components(D,F,G) 20[20/25] [2/5] abandoned(76%) components(D,A,F) 10[10/10] [9/9] abandoned(48%) (pruning subsumed arguments) components(D,C,F) 5[5/5] [9/9] abandoned(35%) (pruning subsumed arguments) components(D,F,B) 0[0/0] [9/9] abandoned(23%) components(D,F,E) 0[0/0] [9/9] abandoned(23%) components(E,F,G) 22[22/39] A=F D=G [XDet] # components(E,A,F) 22[22/39] D=F [XDet] # components(E,A,B) 0[0/0] [9/9] abandoned(23%) components(E,C,F) 14[14/14] D=F # components(E,C,B) 0[0/0] [9/9] abandoned(23%) components(E,C,D) 14[14/14] gain 11.2 components(E,F,B) 0[0/0] [9/9] abandoned(23%) components(E,F,D) 22[22/39] A=F [XDet] # components(F,A,B) 8[8/8] [9/9] abandoned(43%) components(F,A,E) 8[8/8] [9/9] abandoned(43%) components(F,C,B) 8[8/8] [9/9] abandoned(43%) components(F,C,D) 22[22/39] B=F [XDet] # components(F,C,E) 8[8/8] [9/9] abandoned(43%) [components tried 25/33] 0.0 secs Save A=C (14,14 value 12.2) Save B=E (14,14 value 12.2) Save components(B,A,D) (14,14 value 12.2) Save components(E,C,D) (14,14 value 12.2) Best literal member(A,D) (3.6 bits) >>>>>> >>>>>> After adding literals components(E,A,D) and member(A,D), the >>>>>> clause is found to be complete. However, it is more complex >>>>>> than the best saved clause which has the same coverage, so >>>>>> the saved clause is preferred. >>>>>> [Replace by saved clause] Initial clause (0 errs): member(A,B) :- components(B,C,D), member(A,D). member(A,D) essential components(B,C,D) essential Clause 0: member(A,B) :- components(B,C,D), member(A,D). State (6/25, 30.2 bits available) B=[] 0[0/1] [6/6] abandoned(28%) [== tried 1/1] 0.0 secs >>>>>> >>>>>> The apparent new variable C introduced by the next literal is >>>>>> identical to existing variable A on all positive tuples. >>>>>> It also gets the axe. >>>>>> components(B,C,D) 6[6/23] A=+C [XDet] # components(B,A,C) 6[6/6] [Det] gain 11.4 [components tried 2/3] 0.0 secs Save clause ending with components(B,A,C) (cover 6, accuracy 100%) Best literal components(B,A,C) (2.6 bits) Initial clause (0 errs): member(A,B) :- components(B,A,C). components(B,A,C) essential Clause 1: member(A,B) :- components(B,A,C). >>>>>> >>>>>> The final definition is screened and the clauses reordered >>>>>> to place the non-recursive base case ahead of the general >>>>>> recursive clause. >>>>>> Clause 1 needed for 1,[1] Clause 0 needed for 3,[13] member(A,B) :- components(B,A,C). member(A,B) :- components(B,C,D), member(A,D). Time 0.0 secs >>>>>> >>>>>> The definition is then tested on the four test cases. Horror: >>>>>> even though the definition seems fine, it gives an error on >>>>>> case 3,[232]! In order to determine by the recursive clause >>>>>> that 3 is a member of [232], it is necessary to be able to >>>>>> establish that 3 is a member of [32]. However, the tuple >>>>>> 3,[23] does not appear among the tuples known to be in the >>>>>> relation member, so 3,[232] is judged (incorrectly) to be >>>>>> false. A future release will allow the definition to be >>>>>> tested in Prolog interpretive mode, which would have produced >>>>>> the correct result for this case. >>>>>> Test relation member (+) 3,[232] Summary: 1 error in 4 trials @//E*O*F member.explain// chmod u=rw,g=,o= member.explain echo x - ncm.d sed 's/^@//' > "ncm.d" <<'@//E*O*F ncm.d//' N: *0, *1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, 28, 30, 32, 35, 36, 40, 42, 45, 48, 49, 50, 54, 56, 60, 63, 64, 70, 72, 80, 81, 90, 100. *dec(N,N) #- 1,0 2,1 3,2 4,3 5,4 6,5 7,6 8,7 9,8 10,9 11,10 @. *mult(N,N,N) ##- 0,0,0 0,1,0 0,2,0 0,3,0 0,4,0 0,5,0 0,6,0 0,7,0 0,8,0 0,9,0 0,10,0 1,0,0 1,1,1 1,2,2 1,3,3 1,4,4 1,5,5 1,6,6 1,7,7 1,8,8 1,9,9 1,10,10 2,0,0 2,1,2 2,2,4 2,3,6 2,4,8 2,5,10 2,6,12 2,7,14 2,8,16 2,9,18 2,10,20 3,0,0 3,1,3 3,2,6 3,3,9 3,4,12 3,5,15 3,6,18 3,7,21 3,8,24 3,9,27 3,10,30 4,0,0 4,1,4 4,2,8 4,3,12 4,4,16 4,5,20 4,6,24 4,7,28 4,8,32 4,9,36 4,10,40 5,0,0 5,1,5 5,2,10 5,3,15 5,4,20 5,5,25 5,6,30 5,7,35 5,8,40 5,9,45 5,10,50 6,0,0 6,1,6 6,2,12 6,3,18 6,4,24 6,5,30 6,6,36 6,7,42 6,8,48 6,9,54 6,10,60 7,0,0 7,1,7 7,2,14 7,3,21 7,4,28 7,5,35 7,6,42 7,7,49 7,8,56 7,9,63 7,10,70 8,0,0 8,1,8 8,2,16 8,3,24 8,4,32 8,5,40 8,6,48 8,7,56 8,8,64 8,9,72 8,10,80 9,0,0 9,1,9 9,2,18 9,3,27 9,4,36 9,5,45 9,6,54 9,7,63 9,8,72 9,9,81 9,10,90 10,0,0 10,1,10 10,2,20 10,3,30 10,4,40 10,5,50 10,6,60 10,7,70 10,8,80 10,9,90 10,10,100 @. choose(N,N,N) ##- 0,0,1 1,0,1 1,1,1 2,0,1 2,1,2 2,2,1 3,0,1 3,1,3 3,2,3 3,3,1 4,0,1 4,1,4 4,2,6 4,3,4 4,4,1 5,0,1 5,1,5 5,2,10 5,3,10 5,4,5 5,5,1 ; 0,0,2 0,0,3 0,0,4 0,0,5 0,0,6 0,0,7 0,0,8 0,0,9 0,0,10 1,0,2 1,0,3 1,0,4 1,0,5 1,0,6 1,0,7 1,0,8 1,0,9 1,0,10 1,1,2 1,1,3 1,1,4 1,1,5 1,1,6 1,1,7 1,1,8 1,1,9 1,1,10 2,0,2 2,0,3 2,0,4 2,0,5 2,0,6 2,0,7 2,0,8 2,0,9 2,0,10 2,1,1 2,1,3 2,1,4 2,1,5 2,1,6 2,1,7 2,1,8 2,1,9 2,1,10 2,2,2 2,2,3 2,2,4 2,2,5 2,2,6 2,2,7 2,2,8 2,2,9 2,2,10 3,0,2 3,0,3 3,0,4 3,0,5 3,0,6 3,0,7 3,0,8 3,0,9 3,0,10 3,1,1 3,1,2 3,1,4 3,1,5 3,1,6 3,1,7 3,1,8 3,1,9 3,1,10 3,2,1 3,2,2 3,2,4 3,2,5 3,2,6 3,2,7 3,2,8 3,2,9 3,2,10 3,3,2 3,3,3 3,3,4 3,3,5 3,3,6 3,3,7 3,3,8 3,3,9 3,3,10 4,0,2 4,0,3 4,0,4 4,0,5 4,0,6 4,0,7 4,0,8 4,0,9 4,0,10 4,1,1 4,1,2 4,1,3 4,1,5 4,1,6 4,1,7 4,1,8 4,1,9 4,1,10 4,2,1 4,2,2 4,2,3 4,2,4 4,2,5 4,2,7 4,2,8 4,2,9 4,2,10 4,3,1 4,3,2 4,3,3 4,3,5 4,3,6 4,3,7 4,3,8 4,3,9 4,3,10 4,4,2 4,4,3 4,4,4 4,4,5 4,4,6 4,4,7 4,4,8 4,4,9 4,4,10 5,0,2 5,0,3 5,0,4 5,0,5 5,0,6 5,0,7 5,0,8 5,0,9 5,0,10 5,1,1 5,1,2 5,1,3 5,1,4 5,1,6 5,1,7 5,1,8 5,1,9 5,1,10 5,2,1 5,2,2 5,2,3 5,2,4 5,2,5 5,2,6 5,2,7 5,2,8 5,2,9 5,3,1 5,3,2 5,3,3 5,3,4 5,3,5 5,3,6 5,3,7 5,3,8 5,3,9 5,4,1 5,4,2 5,4,3 5,4,4 5,4,6 5,4,7 5,4,8 5,4,9 5,4,10 5,5,2 5,5,3 5,5,4 5,5,5 5,5,6 5,5,7 5,5,8 5,5,9 5,5,10 @. @//E*O*F ncm.d// chmod u=rw,g=,o= ncm.d echo x - order.c sed 's/^@//' > "order.c" <<'@//E*O*F order.c//' /******************************************************************************/ /* */ /* Routines for controlling recursive definitions. The basic idea */ /* is to keep track of partial orders between variables (using */ /* either predefined or discovered constant orders) and to ensure */ /* that there is an ordering of all recursive literals that will */ /* guarantee termination. See Cameron-Jones and Quinlan, IJCAI'93 */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" /* Examine relationships among variables: LHSVar <,=,>,# anyvar and anyvar = anyvar */ void ExamineVariableRelationships() /* ---------------------------- */ { Var V, W; Const VVal, WVal; Ordering X, ThisX; Tuple *Scan, Case; int *TypeOrder; Boolean FirstTime=true; /* First reset all partial orders */ ForEach(V, 1, Target->Arity) { memset(PartialOrder[V], '#', Current.MaxVar+1); PartialOrder[V][V] = '='; } ForEach(V, 1, Current.MaxVar-1) { if ( Variable[V]->TypeRef->Continuous ) continue; if ( V <= Target->Arity ) { TypeOrder = Target->TypeRef[V]->CollSeq; } ForEach(W, V+1, Current.MaxVar) { if ( Variable[W]->TypeRef->Continuous || ! Compatible[Variable[V]->Type][Variable[W]->Type] ) continue; for ( X = 0, Scan = Current.Tuples ; X != '#' && *Scan ; Scan++ ) { Case = *Scan; if ( (VVal = Case[V]) == (WVal = Case[W]) ) { ThisX = '='; } else if ( V > Target->Arity || ! Variable[V]->TypeRef->Ordered || ! Variable[W]->TypeRef->Ordered ) { ThisX = '#'; } else { ThisX = ( TypeOrder[VVal] < TypeOrder[WVal] ? '<' : '>' ); } if ( ! X ) { X = ThisX; } else if ( X != ThisX ) { X = '#'; } } if ( X != '#' ) { Verbose(2) { if ( FirstTime ) { printf("\t\tNote"); FirstTime = false; } printf(" %s%c%s", Variable[V]->Name, X, Variable[W]->Name); } } if ( X == '=' ) Barred[W] = true; /* Record partial order for recursive literals. If polarity is fixed, treat > as # */ if ( V <= Target->Arity && X != '#' ) { ThisX = PartialOrder[V][W] = X; AnyPartialOrder |= ThisX == '<' || ThisX == '>'; if ( W <= Target->Arity ) { ThisX = PartialOrder[W][V] = X == '<' ? '>' : X == '>' ? '<' : '='; AnyPartialOrder |= ThisX == '<' || ThisX == '>'; } } } } Verbose(2) putchar('\n'); } /* Vet proposed arguments for recursive literal. Uses a mapping from ThisOrder x Cell to ThisOrder */ Boolean RecursiveCallOK(Var *A) /* --------------- */ { int i, j, k, N, NRowLeft, Count, NRow, BestCount, BestCol; Ordering *ThisCall, ThisOrder, BestOrder, Cell; Boolean SomeInequality=false, ColOrder[100]; static Ordering **Map=Nil; static Boolean *ColLeft, *RowLeft; if ( ! AnyPartialOrder ) return false; if ( ! Map ) { N = (int) '>'; /* max of '#', '<', '>', '=' */ Map = Alloc(N+1, Ordering *); /* We want the final value for a column to be '=' if it contains only '=' entries '<' if it contains only '<' and/or '=' entries '>' if it contains only '>' and/or '=' entries and '#' otherwise */ Map['='] = Alloc(N+1, Ordering); Map['<'] = Alloc(N+1, Ordering); Map['>'] = Alloc(N+1, Ordering); Map['#'] = Alloc(N+1, Ordering); Map['=']['='] = '='; Map['=']['<'] = '<'; Map['=']['>'] = '>'; Map['=']['#'] = '#'; Map['<']['='] = '<'; Map['<']['<'] = '<'; Map['<']['>'] = '#'; Map['<']['#'] = '#'; Map['>']['='] = '>'; Map['>']['<'] = '#'; Map['>']['>'] = '>'; Map['>']['#'] = '#'; Map['#']['='] = '#'; Map['#']['<'] = '#'; Map['#']['>'] = '#'; Map['#']['#'] = '#'; ColLeft = Alloc(MAXARGS+1, Boolean); RowLeft = Alloc(1001, Boolean); /* assume <1000 recursive lits! */ } N = Target->Arity; memset(ColLeft, true, N+1); NRow = NRowLeft = NRecLitClause + NRecLitDef; memset(RowLeft, true, NRow+1); /* First need to establish ordering constraints for these arguments. (Skip this if A is nil, called from pruning routines) */ if ( A ) { ThisCall = RecursiveLitOrders[0]; ForEach(i, 1, N) { if ( A[i] > Current.MaxVar ) { ThisCall[i] = '#'; } else { ThisCall[i] = PartialOrder[i][A[i]]; SomeInequality |= ThisCall[i] == '<' || ThisCall[i] == '>'; } } if ( ! SomeInequality ) return false; } else { NRowLeft--; RowLeft[0] = false; } /* Check for a possible ordering by * finding a column that has only (< or >) and = orders * delete rows containing (< or >) * continue until no rows remain */ /* This routine is also invoked during the pruning phase, when some literals have been (perhaps temporarily) removed from the most recent clause. Their orderings are marked as inactive; these are treated as if already covered */ ForEach(j, NRecLitDef+1, NRow) { if ( RecursiveLitOrders[j][0] ) { RowLeft[j] = false; NRowLeft--; } } /* Find the initial column ordering constraints */ ForEach(k, 1, N) { ColOrder[k] = ( Target->TypeRef[k]->FixedPolarity ? '>' : '=' ); } while( NRowLeft >= 0 ) { BestCol = BestCount = 0; ForEach(k, 1, N) { if ( ! ColLeft[k] ) continue; Count = 0; ThisOrder = ColOrder[k]; for ( j = 0 ; ThisOrder != '#' && j <= NRow ; j++ ) { if ( ! RowLeft[j] ) continue; Cell = RecursiveLitOrders[j][k]; if ( Cell != '=' ) Count++; ThisOrder = Map[ThisOrder][Cell]; } if ( ThisOrder != '#' && Count > BestCount ) { BestCount = Count; BestCol = k; BestOrder = ThisOrder; } } if ( ! BestCol ) { /* Recursive Call Not OK */ return false; } /* Process best column */ ForEach(j, 0, NRow) { if ( RowLeft[j] && RecursiveLitOrders[j][BestCol] != '=' ) { RowLeft[j] = false; NRowLeft--; } } ColLeft[BestCol] = false; /* Make sure the same type is treated consistently */ ForEach(k, 1, N) { if ( k != BestCol && Target->TypeRef[k] == Target->TypeRef[BestCol] ) { ColOrder[k] = BestOrder; } } } return NRowLeft < 0; } /* Add argument order information for recursive literal. Note: this must be performed before calling NewState so that new variables are correctly given ordering # */ void AddOrders(Literal L) /* --------- */ { Var V, W; /* Allocate ordering and mark as active */ if ( ! L->ArgOrders ) { L->ArgOrders = Alloc(Target->Arity+1, Ordering); L->ArgOrders[0] = 0; } ForEach(V, 1, Target->Arity) { W = L->Args[V]; L->ArgOrders[V] = ( W <= Current.MaxVar ? PartialOrder[V][W] : '#' ); } } /* Keep track of argument orders for recursive literals. (The first cell is reserved for testing) */ void NoteRecursiveLit(Literal L) /* ---------------- */ { static int RecLitSize=0; int i; NRecLitClause++; i = NRecLitDef + NRecLitClause; if ( i >= RecLitSize ) { RecLitSize += 100; Realloc(RecursiveLitOrders, RecLitSize, Ordering *); } RecursiveLitOrders[i] = L->ArgOrders; } @//E*O*F order.c// chmod u=rw,g=,o= order.c echo x - output.c sed 's/^@//' > "output.c" <<'@//E*O*F output.c//' /******************************************************************************/ /* */ /* All output routines */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" void PrintTuple(Tuple C, int N, TypeInfo *TypeRef, Boolean ShowPosNeg) /* ---------- */ { int i; printf("\t"); ForEach(i, 1, N) { if ( TypeRef ? TypeRef[i]->Continuous : Variable[i]->TypeRef->Continuous ) { /* Continuous value */ if ( FP(C[i]) == MISSING_FP ) { printf("?"); } else { printf("%g", FP(C[i])); } } else { printf("%s", ConstName[C[i]]); } if ( i < N ) putchar(','); } if ( ShowPosNeg ) { printf(": %c", (Positive(C) ? '+' : '-') ); } putchar('\n'); } void PrintTuples(Tuple *TT, int N) /* ----------- */ { while ( *TT ) { PrintTuple(*TT, N, Nil, true); TT++; } } void PrintSpecialLiteral(Relation R, Boolean RSign, Var *A) /* ------------------- */ { Const ThConst; float Thresh; if ( R == EQVAR ) { printf("%s%s%s", Variable[A[1]]->Name, RSign ? "=":"<>", Variable[A[2]]->Name); } else if ( R == EQCONST ) { GetParam(&A[2], &ThConst); printf("%s%s%s", Variable[A[1]]->Name, RSign ? "=" : "<>", ConstName[ThConst]); } else if ( R == GTVAR ) { printf("%s%s%s", Variable[A[1]]->Name, RSign ? ">" : "<=", Variable[A[2]]->Name); } else if ( R == GTCONST ) { GetParam(&A[2], &Thresh); if ( Thresh == MISSING_FP ) { printf("%s%s", Variable[A[1]]->Name, RSign ? ">" : "<="); } else { printf("%s%s%g", Variable[A[1]]->Name, RSign ? ">" : "<=", Thresh); } } } void PrintComposedLiteral(Relation R, Boolean RSign, Var *A) /* -------------------- */ { int i, V; if ( Predefined(R) ) { PrintSpecialLiteral(R, RSign, A); } else { if ( ! RSign ) { printf("not("); } printf("%s", R->Name); ForEach(i, 1, R->Arity) { printf("%c", (i > 1 ? ',' : '(')); if ( (V = A[i]) <= MAXVARS ) { printf("%s", Variable[V]->Name); } else { printf("_%d", V - MAXVARS); } } putchar(')'); if ( ! RSign ) { putchar(')'); } } } void PrintLiteral(Literal L) /* ------------ */ { PrintComposedLiteral(L->Rel, L->Sign, L->Args); } void PrintClause(Relation R, Clause C) /* ----------- */ { int Lit; PrintComposedLiteral(R, true, DefaultVars); for ( Lit = 0 ; C[Lit] ; Lit++ ) { printf("%s ", ( Lit ? "," : " :-" )); PrintLiteral(C[Lit]); } printf(".\n"); } /* Print clause, substituting for variables equivalent to constants */ void PrintSimplifiedClause(Relation R, Clause C) /* --------------------- */ { int i, Lit, NextUnbound; Literal L; Var V, Bound, *SaveArgs, *Unbound; char **HoldVarNames; Const TC; Boolean NeedComma=false; SaveArgs = Alloc(MAXVARS+1, Var); Unbound = Alloc(MAXVARS+1, Var); /* Save copy of variable names */ HoldVarNames = Alloc(MAXVARS+1, char *); ForEach(V, 1, MAXVARS) { HoldVarNames[V] = Variable[V]->Name; } /* Substitute for equal variables */ for ( Lit = 0 ; L = C[Lit] ; Lit++ ) { if ( L->Rel == EQVAR && L->Sign ) { Substitute(Variable[L->Args[2]]->Name, Variable[L->Args[1]]->Name); } } /* Set up alternate names for variables equated to theory constants */ for ( Lit = 0 ; L = C[Lit] ; Lit++ ) { if ( L->Rel == EQCONST && L->Sign ) { GetParam(&L->Args[2], &TC); Substitute(Variable[L->Args[1]]->Name, ConstName[TC]); } } PrintComposedLiteral(R, true, DefaultVars); Bound = R->Arity; for ( Lit = 0 ; L = C[Lit] ; Lit++ ) { /* Save literal args */ memcpy(SaveArgs, L->Args, (L->Rel->Arity+1) * sizeof(Var)); /* Update bound vars and change unbound vars in negated literals */ NextUnbound = MAXVARS; memset(Unbound, 0, MAXVARS+1); ForEach(i, 1, L->Rel->Arity ) { if ( (V = L->Args[i]) > Bound ) { if ( ! L->Sign ) { if ( ! Unbound[V] ) Unbound[V] = ++NextUnbound; L->Args[i] = Unbound[V]; } else { Bound = V; } } } /* Skip literals that are implicit in changed names */ if ( L->Rel != EQCONST && L->Rel != EQVAR || ! L->Sign ) { printf("%s", ( NeedComma ? ", " : " :- ") ); PrintLiteral(L); NeedComma = true; } /* Restore args */ memcpy(L->Args, SaveArgs, (L->Rel->Arity+1) * sizeof(Var)); } printf(".\n"); ForEach(V, 1, MAXVARS) { Variable[V]->Name = HoldVarNames[V]; } pfree(SaveArgs); pfree(Unbound); pfree(HoldVarNames); } void Substitute(char *Old, char *New) /* ---------- */ { Var V; ForEach(V, 1, MAXVARS) { if ( Variable[V]->Name == Old ) Variable[V]->Name = New; } } void PrintDefinition(Relation R) /* --------------- */ { int Cl, SecondPass=(-1); Clause C; putchar('\n'); for ( Cl = 0 ; C=R->Def[Cl] ; Cl++ ) { if ( Recursive(C) ) { SecondPass = Cl; } else { PrintSimplifiedClause(R, C); } } ForEach(Cl, 0, SecondPass) { if ( Recursive(C = R->Def[Cl]) ) PrintSimplifiedClause(R, C); } printf("\nTime %.1f secs\n", CPUTime()); } Boolean Recursive(Clause C) /* --------- */ { int Lit; for ( Lit = 0 ; C[Lit] ; Lit++ ) { if ( C[Lit]->Rel == Target ) return true; } return false; } @//E*O*F output.c// chmod u=rw,g=,o= output.c echo x - prune.c sed 's/^@//' > "prune.c" <<'@//E*O*F prune.c//' /******************************************************************************/ /* */ /* Stuff for pruning clauses and definitions. Clauses are first */ /* `quickpruned' to remove determinate literals that introduce unused */ /* variables; if this causes the definition to become less accurate, */ /* these are restored. Then literals are removed one at a time to */ /* see whether they contribute anything. A similar process is */ /* followed when pruning definitions: clauses are removed one at a */ /* time to see whether the remaining clauses suffice */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" extern Boolean RecordArgOrders; /* for interpret.c */ #define MarkLiteral(L,X) { (L)->Args[0]=X;\ if ((L)->ArgOrders) (L)->ArgOrders[0]=X;} /* See whether literals can be dropped from a clause */ void PruneNewClause() /* -------------- */ { int Errs, i, j, k; Boolean *Used, Changed=false; Literal L, LL; Var V; Errs = Current.NOrigTot - Current.NOrigPos; Used = Alloc(MAXVARS+1, Boolean); Verbose(2) { printf("\nInitial clause (%d errs): ", Errs); PrintClause(Target, NewClause); } /* Save arg orderings for recursive literals and promote any literals of form A=B or B=c to immediately after B appears in the clause */ ForEach(i, 0, NLit-1) { L = NewClause[i]; if ( L->Sign && ( L->Rel == EQVAR || L->Rel == EQCONST ) ) { V = ( L->Rel == EQVAR ? L->Args[2] : L->Args[1] ); if ( V > Target->Arity ) { ForEach(j, 1, i) { LL = NewClause[j-1]; if ( LL->Sign && Contains(LL->Args, LL->Rel->Arity, V) ) { break; } } } else { j = 0; } for ( k = i ; k > j ; k-- ) { NewClause[k] = NewClause[k-1]; } NewClause[j] = L; } else if ( L->Rel == Target ) { L->SaveArgOrders = Alloc(Target->Arity+1, Ordering); memcpy(L->SaveArgOrders, L->ArgOrders, (Target->Arity+1)*sizeof(Ordering)); } } /* Look for unexpected relations V=W or V=c */ CheckVariables(); /* Check for quick pruning of apparently useless literals */ if ( QuickPrune(NewClause, Target->Arity, Used) ) { if ( SatisfactoryNewClause(Errs) ) { Verbose(3) printf("\tAccepting quickpruned clause\n"); Changed = true; } else { /* Mark all literals as active again */ ForEach(i, 0, NLit-1) { MarkLiteral(NewClause[i], 0); } } } Changed |= RedundantLiterals(Errs); /* Remove unnecessary literals from NewClause */ if ( Changed ) { for ( i = 0 ; i < NLit ; ) { L = NewClause[i]; if ( L->Args[0] ) { FreeLiteral(L); NLit--; ForEach(j, i, NLit-1) { NewClause[j] = NewClause[j+1]; } } else { i++; } } NewClause[NLit] = Nil; RenameVariables(); /* Need to recompute partial orders and clause coverage */ RecoverState(NewClause); CheckOriginalCaseCover(); } else { /* Restore arg orders */ ForEach(i, 0, NLit-1) { L = NewClause[i]; if ( L->Rel == Target ) { memcpy(L->ArgOrders,L->SaveArgOrders, (Target->Arity+1)*sizeof(Ordering)); pfree(L->SaveArgOrders); } } } pfree(Used); } /* Look for unexpected equivalences of variables or variables with unchanging values. If found, insert pseudo-literals into the clause so that redundant literals can be pruned */ void CheckVariables() /* -------------- */ { Var A, B; ForEach(A, 1, Current.MaxVar) { if ( TheoryConstant(Current.Tuples[0][A], Variable[A]->TypeRef) && ConstantVar(A, Current.Tuples[0][A]) ) { if ( ! Known(EQCONST, A, 0) ) { Insert(A, EQCONST, A, Current.Tuples[0][A]); } } else { ForEach(B, A+1, Current.MaxVar) { if ( Compatible[Variable[A]->Type][Variable[B]->Type] && IdenticalVars(A,B) && ! Known(EQVAR, A, B) ) { Insert(B, EQVAR, A, B); } } } } } /* See whether a constant is a theory constant */ Boolean TheoryConstant(Const C, TypeInfo T) /* -------------- */ { int i; if ( T->Continuous ) return false; ForEach(i, 0, T->NTheoryConsts-1) { if ( C == T->TheoryConst[i] ) return true; } return false; } /* Check for variable with constant value */ Boolean ConstantVar(Var V, Const C) /* ----------- */ { Tuple Case, *TSP; for ( TSP = Current.Tuples ; Case = *TSP++; ) { if ( Positive(Case) && Case[V] != C ) return false; } return true; } /* Check for identical variables */ Boolean IdenticalVars(Var V, Var W) /* ------------- */ { Tuple Case, *TSP; for ( TSP = Current.Tuples ; Case = *TSP++; ) { if ( Positive(Case) && ( Unknown(V, Case) || Case[V] != Case[W] ) ) return false; } return true; } /* Make sure potential literal isn't already in clause */ Boolean Known(Relation R, Var V, Var W) /* ----- */ { int i; Literal L; ForEach(i, 0, NLit-1) { L = NewClause[i]; if ( L->Rel == R && L->Sign && L->Args[1] == V && ( ! W || L->Args[2] == W ) ) { return true; } } return false; } /* Insert new literal after V first bound */ void Insert(Var V, Relation R, Var A1, Const A2) /* ------ */ { int i=0, j; Literal L; if ( V > Target->Arity ) { ForEach(i, 1, NLit) { L = NewClause[i-1]; if ( L->Sign && Contains(L->Args, L->Rel->Arity, V) ) break; } } /* Insert literal before NewClause[i] */ if ( ++NLit % 100 == 0 ) Realloc(NewClause, NLit+100, Literal); for ( j = NLit ; j > i ; j-- ) { NewClause[j] = NewClause[j-1]; } L = AllocZero(1, struct _lit_rec); L->Rel = R; L->Sign = true; L->Bits = 0; if ( R == EQVAR ) { L->Args = AllocZero(3, Var); L->Args[1] = A1; L->Args[2] = A2; } else { L->Args = AllocZero(2+sizeof(Const), Var); L->Args[1] = A1; SaveParam(L->Args+2, &A2); } NewClause[i] = L; Verbose(2) { printf("\tInsert literal "); PrintSpecialLiteral(R, true, L->Args); printf("\n"); } } /* Check for variable in argument list */ Boolean Contains(Var *A, int N, Var V) /* -------- */ { int i; ForEach(i, 1, N) { if ( A[i] == V ) return true; } return false; } /* Remove determinate literals that introduce useless new variables (that are not used by any subsequent literal) */ Boolean QuickPrune(Clause C, Var MaxBound, Boolean *Used) /* ---------- */ { Var V, NewMaxBound; Literal L; Boolean SomeUsed=true, Changed=false; if ( (L = C[0]) == Nil ) { ForEach(V, 1, MaxBound) Used[V] = false; return false; } L->Args[0] = 0; NewMaxBound = MaxBound; if ( L->Sign ) { ForEach(V, 1, L->Rel->Arity) { if ( L->Args[V] > NewMaxBound ) NewMaxBound = L->Args[V]; } } Changed = QuickPrune(C+1, NewMaxBound, Used); if ( L->Sign == 2 ) { SomeUsed = false; ForEach(V, MaxBound+1, NewMaxBound) { SomeUsed = Used[V]; if ( SomeUsed ) break; } } if ( ! SomeUsed && C[1] ) { /* Mark this literal as inactive */ MarkLiteral(L, 1); Verbose(3) { printf("\tQuickPrune literal "); PrintLiteral(L); putchar('\n'); } Changed = true; } else ForEach(V, 1, L->Rel->Arity) { Used[L->Args[V]] = true; } return Changed; } Boolean SatisfactoryNewClause(int Errs) /* --------------------- */ { Boolean RecursiveLits=false, ProForma; Literal L; int i, ErrsNow=0; /* Prepare for redetermining argument orders */ ForEach(i, 0, NLit-1) { if ( (L = NewClause[i])->Args[0] ) continue; if ( L->Rel == Target ) { RecursiveLits = true; memset(L->ArgOrders, 0, Target->Arity+1); } } /* Scan case by case, looking for too many covered neg tuples */ RecordArgOrders = RecursiveLits; ForEach(i, StartDef.NPos, StartDef.NTot-1) { InitialiseValues(StartDef.Tuples[i], Target->Arity); if ( CheckRHS(NewClause) && ++ErrsNow > Errs || RecursiveLits && ! RecordArgOrders ) { RecordArgOrders = false; return false; } } /* If satisfactory and recursive literals, must also check pos tuples covered to complete arg order information */ for ( i = 0 ; i < StartDef.NPos && RecordArgOrders ; i++ ) { InitialiseValues(StartDef.Tuples[i], Target->Arity); ProForma = CheckRHS(NewClause); } /* Now check that recursion still well-behaved */ return ( RecursiveLits ? RecordArgOrders && RecursiveCallOK(Nil) : true ); } /* Rename variables in NewClause */ void RenameVariables() /* --------------- */ { Var *NewVar, Next, SaveNext, V; int l, i; Literal L; NewVar = AllocZero(MAXVARS+1, Var); Next = Target->Arity+1; ForEach(l, 0, NLit-1) { if ( (L=NewClause[l])->Args[0] ) continue; SaveNext = Next; ForEach(i, 1, L->Rel->Arity) { V = L->Args[i]; if ( V > Target->Arity ) { if ( ! NewVar[V] ) NewVar[V] = Next++; L->Args[i] = NewVar[V]; } } /* New variables appearing in negated lits are still free */ if ( ! L->Sign ) { Next = SaveNext; ForEach(V, 1, MAXVARS) if ( NewVar[V] >= Next ) NewVar[V] = 0; } } pfree(NewVar); } /* Omit the first unnecessary literal. This version prunes from the end of the clause; if a literal can't be dropped when it is examined, it will always be needed, since dropping earlier literals can only increase the number of minus tuples getting through to this literal */ Boolean RedundantLiterals(int ErrsNow) /* ----------------- */ { int i, j; Boolean Changed=false; Literal L; /* Check for the latest literal, omitting which would not increase the number of errors. Note: checking last literal is reinstated since clause may contain errors */ for ( i = NLit-1 ; i >= 0 ; i-- ) { L = NewClause[i]; if ( L->Args[0] || EssentialBinding(i) ) { continue; } MarkLiteral(L, 1); if ( SatisfactoryNewClause(ErrsNow) ) { Verbose(3) { printf("\t\t"); PrintLiteral(L); printf(" removed\n"); } Changed = true; } else { Verbose(3) { printf("\t\t"); PrintLiteral(L); printf(" essential\n"); } MarkLiteral(L, 0); /* If this literal is V=W, where W is a non-continuous variable bound on the RHS of the clause, substitute for W throughout and remove the literal */ if ( L->Rel == EQVAR && L->Sign && L->Args[2] > Target->Arity && ! Variable[L->Args[2]]->TypeRef->Continuous ) { ForEach(j, i, NLit-1) { NewClause[j] = NewClause[j+1]; } NLit--; ReplaceVariable(L->Args[2], L->Args[1]); } } } return Changed; } /* Can't omit a literal that is needed to bind a variable appearing in a later negated literal relation, or whose omission would leave a later literal containing all new variables */ #define NONE -1 #define MANY 1000000 Boolean EssentialBinding(int LitNo) /* ---------------- */ { int i, j, b, *UniqueBinding; Boolean Needed=false, Other; Literal L; Var V, NArgs; /* UniqueBinding[V] = NONE (if V not yet bound) = i (if V bound only by ith literal) = MANY (if V bound by more than one literal) */ UniqueBinding = Alloc(MAXVARS+1, int); ForEach(V, 1, MAXVARS) { UniqueBinding[V] = ( V <= Target->Arity ? MANY : NONE ); } for ( i = 0 ; i < NLit && ! Needed ; i++ ) { if ( (L = NewClause[i])->Args[0] ) continue; NArgs = L->Rel->Arity; if ( i > LitNo ) { if ( Predefined(L->Rel) || ! L->Sign ) { ForEach(j, 1, NArgs) { Needed |= UniqueBinding[L->Args[j]] == LitNo; } } else { Other = false; ForEach(j, 1, NArgs) { b = UniqueBinding[L->Args[j]]; Other |= b != NONE && b != LitNo; } Needed = ! Other; } if ( Needed ) { Verbose(/*3*/2) { printf("\t\t"); PrintLiteral(NewClause[LitNo]); printf(" needed for binding "); PrintLiteral(NewClause[i]); putchar('\n'); } } } if ( L->Sign ) { /* Update binding records for new variables */ ForEach(j, 1, NArgs) { V = L->Args[j]; if ( UniqueBinding[V] == NONE ) { UniqueBinding[V] = i; } else if ( UniqueBinding[V] != i ) { UniqueBinding[V] = MANY; } } } } pfree(UniqueBinding); return Needed; } /* Substitute for variable in clause */ void ReplaceVariable(Var Old, Var New) /* --------------- */ { int i, a; Literal L; Boolean Bound=false; ForEach(i, 0, NLit-1) { L = NewClause[i]; if ( L->Sign || Bound ) { ForEach(a, 1, L->Rel->Arity) { if ( L->Args[a] == Old ) { L->Args[a] = New; Bound = true; } } } } } /* See whether some clauses can be dispensed with */ void SiftClauses() /* ----------- */ { int i, j, Covers, Last, Retain=0, Remove=0; Boolean *Need, *Delete; if ( ! NCl ) return; Delete = AllocZero(NCl, Boolean); Need = AllocZero(NCl, Boolean); Current.MaxVar = HighestVarInDefinition(Target); while ( Retain+Remove < NCl ) { /* See if a clause uniquely covers a pos tuple */ for ( i = 0 ; i < StartDef.NPos && Retain < NCl ; i++ ) { Covers = 0; for ( j = 0 ; j < NCl && Covers <= 1 && Retain < NCl ; j++ ) { if ( Delete[j] ) continue; InitialiseValues(StartDef.Tuples[i], Target->Arity); if ( CheckRHS(Target->Def[j]) ) { Covers++; Last = j; } } if ( Covers == 1 && ! Need[Last] ) { Verbose(3) { printf("\tClause %d needed for ", Last); PrintTuple(StartDef.Tuples[i], Target->Arity, Target->TypeRef, false); } Need[Last] = true; Retain++; } } if ( Retain == NCl ) break; /* Remove the latest unneeded clause */ Last = -1; ForEach(i, 0, NCl-1) { if ( ! Need[i] && ! Delete[i] ) Last = i; } if ( Last == -1 ) break; Delete[Last] = true; Remove++; } if ( Retain < NCl ) { Verbose(1) printf("\nDelete clause%s\n", Plural(NCl - Retain)); Retain = 0; ForEach(i, 0, NCl-1) { if ( Delete[i] ) { Verbose(1) { printf("\t"); PrintClause(Target, Target->Def[i]); FreeClause(Target->Def[i]); } } else { Target->Def[Retain++] = Target->Def[i]; } } Target->Def[Retain] = Nil; } pfree(Delete); pfree(Need); } /* Find highest variable in any clause */ Var HighestVarInDefinition(Relation R) /* ---------------------- */ { Var V, HiV; Literal L; Clause C; int i; HiV = R->Arity; for ( i = 0 ; R->Def[i] ; i++ ) { for ( C = R->Def[i] ; L = *C ; C++ ) { if ( L->Sign ) { ForEach(V, 1, L->Rel->Arity) { if ( L->Args[V] > HiV ) HiV = L->Args[V]; } } } } return HiV; } @//E*O*F prune.c// chmod u=rw,g=,o= prune.c echo x - qs44.d sed 's/^@//' > "qs44.d" <<'@//E*O*F qs44.d//' *E: 0,1,2,3. *L: *[],[0],[1],[2],[3],[01],[02],[03],[10],[12],[13],[20],[21],[23],[30],[31],[32],[012],[013],[021],[023],[031],[032],[102],[103],[120],[123],[130],[132],[201],[203],[210],[213],[230],[231],[301],[302],[310],[312],[320],[321],[0123],[0132],[0213],[0231],[0312],[0321],[1023],[1032],[1203],[1230],[1302],[1320],[2013],[2031],[2103],[2130],[2301],[2310],[3012],[3021],[3102],[3120],[3201],[3210]. *elt(E) 0 1 2 3 @. *append(L,L,L) ##- [], [], [] [], [0], [0] [0], [], [0] [], [1], [1] [1], [], [1] [], [2], [2] [2], [], [2] [], [3], [3] [3], [], [3] [], [01], [01] [0], [1], [01] [01], [], [01] [], [02], [02] [0], [2], [02] [02], [], [02] [], [03], [03] [0], [3], [03] [03], [], [03] [], [10], [10] [1], [0], [10] [10], [], [10] [], [12], [12] [1], [2], [12] [12], [], [12] [], [13], [13] [1], [3], [13] [13], [], [13] [], [20], [20] [2], [0], [20] [20], [], [20] [], [21], [21] [2], [1], [21] [21], [], [21] [], [23], [23] [2], [3], [23] [23], [], [23] [], [30], [30] [3], [0], [30] [30], [], [30] [], [31], [31] [3], [1], [31] [31], [], [31] [], [32], [32] [3], [2], [32] [32], [], [32] [], [012], [012] [0], [12], [012] [01], [2], [012] [012], [], [012] [], [013], [013] [0], [13], [013] [01], [3], [013] [013], [], [013] [], [021], [021] [0], [21], [021] [02], [1], [021] [021], [], [021] [], [023], [023] [0], [23], [023] [02], [3], [023] [023], [], [023] [], [031], [031] [0], [31], [031] [03], [1], [031] [031], [], [031] [], [032], [032] [0], [32], [032] [03], [2], [032] [032], [], [032] [], [102], [102] [1], [02], [102] [10], [2], [102] [102], [], [102] [], [103], [103] [1], [03], [103] [10], [3], [103] [103], [], [103] [], [120], [120] [1], [20], [120] [12], [0], [120] [120], [], [120] [], [123], [123] [1], [23], [123] [12], [3], [123] [123], [], [123] [], [130], [130] [1], [30], [130] [13], [0], [130] [130], [], [130] [], [132], [132] [1], [32], [132] [13], [2], [132] [132], [], [132] [], [201], [201] [2], [01], [201] [20], [1], [201] [201], [], [201] [], [203], [203] [2], [03], [203] [20], [3], [203] [203], [], [203] [], [210], [210] [2], [10], [210] [21], [0], [210] [210], [], [210] [], [213], [213] [2], [13], [213] [21], [3], [213] [213], [], [213] [], [230], [230] [2], [30], [230] [23], [0], [230] [230], [], [230] [], [231], [231] [2], [31], [231] [23], [1], [231] [231], [], [231] [], [301], [301] [3], [01], [301] [30], [1], [301] [301], [], [301] [], [302], [302] [3], [02], [302] [30], [2], [302] [302], [], [302] [], [310], [310] [3], [10], [310] [31], [0], [310] [310], [], [310] [], [312], [312] [3], [12], [312] [31], [2], [312] [312], [], [312] [], [320], [320] [3], [20], [320] [32], [0], [320] [320], [], [320] [], [321], [321] [3], [21], [321] [32], [1], [321] [321], [], [321] [], [0123], [0123] [0], [123], [0123] [01], [23], [0123] [012], [3], [0123] [0123], [], [0123] [], [0132], [0132] [0], [132], [0132] [01], [32], [0132] [013], [2], [0132] [0132], [], [0132] [], [0213], [0213] [0], [213], [0213] [02], [13], [0213] [021], [3], [0213] [0213], [], [0213] [], [0231], [0231] [0], [231], [0231] [02], [31], [0231] [023], [1], [0231] [0231], [], [0231] [], [0312], [0312] [0], [312], [0312] [03], [12], [0312] [031], [2], [0312] [0312], [], [0312] [], [0321], [0321] [0], [321], [0321] [03], [21], [0321] [032], [1], [0321] [0321], [], [0321] [], [1023], [1023] [1], [023], [1023] [10], [23], [1023] [102], [3], [1023] [1023], [], [1023] [], [1032], [1032] [1], [032], [1032] [10], [32], [1032] [103], [2], [1032] [1032], [], [1032] [], [1203], [1203] [1], [203], [1203] [12], [03], [1203] [120], [3], [1203] [1203], [], [1203] [], [1230], [1230] [1], [230], [1230] [12], [30], [1230] [123], [0], [1230] [1230], [], [1230] [], [1302], [1302] [1], [302], [1302] [13], [02], [1302] [130], [2], [1302] [1302], [], [1302] [], [1320], [1320] [1], [320], [1320] [13], [20], [1320] [132], [0], [1320] [1320], [], [1320] [], [2013], [2013] [2], [013], [2013] [20], [13], [2013] [201], [3], [2013] [2013], [], [2013] [], [2031], [2031] [2], [031], [2031] [20], [31], [2031] [203], [1], [2031] [2031], [], [2031] [], [2103], [2103] [2], [103], [2103] [21], [03], [2103] [210], [3], [2103] [2103], [], [2103] [], [2130], [2130] [2], [130], [2130] [21], [30], [2130] [213], [0], [2130] [2130], [], [2130] [], [2301], [2301] [2], [301], [2301] [23], [01], [2301] [230], [1], [2301] [2301], [], [2301] [], [2310], [2310] [2], [310], [2310] [23], [10], [2310] [231], [0], [2310] [2310], [], [2310] [], [3012], [3012] [3], [012], [3012] [30], [12], [3012] [301], [2], [3012] [3012], [], [3012] [], [3021], [3021] [3], [021], [3021] [30], [21], [3021] [302], [1], [3021] [3021], [], [3021] [], [3102], [3102] [3], [102], [3102] [31], [02], [3102] [310], [2], [3102] [3102], [], [3102] [], [3120], [3120] [3], [120], [3120] [31], [20], [3120] [312], [0], [3120] [3120], [], [3120] [], [3201], [3201] [3], [201], [3201] [32], [01], [3201] [320], [1], [3201] [3201], [], [3201] [], [3210], [3210] [3], [210], [3210] [32], [10], [3210] [321], [0], [3210] [3210], [], [3210] @. *components(L,E,L) #--/-## [0], 0, [] [1], 1, [] [2], 2, [] [3], 3, [] [01], 0, [1] [02], 0, [2] [03], 0, [3] [10], 1, [0] [12], 1, [2] [13], 1, [3] [20], 2, [0] [21], 2, [1] [23], 2, [3] [30], 3, [0] [31], 3, [1] [32], 3, [2] [012], 0, [12] [013], 0, [13] [021], 0, [21] [023], 0, [23] [031], 0, [31] [032], 0, [32] [102], 1, [02] [103], 1, [03] [120], 1, [20] [123], 1, [23] [130], 1, [30] [132], 1, [32] [201], 2, [01] [203], 2, [03] [210], 2, [10] [213], 2, [13] [230], 2, [30] [231], 2, [31] [301], 3, [01] [302], 3, [02] [310], 3, [10] [312], 3, [12] [320], 3, [20] [321], 3, [21] [0123], 0, [123] [0132], 0, [132] [0213], 0, [213] [0231], 0, [231] [0312], 0, [312] [0321], 0, [321] [1023], 1, [023] [1032], 1, [032] [1203], 1, [203] [1230], 1, [230] [1302], 1, [302] [1320], 1, [320] [2013], 2, [013] [2031], 2, [031] [2103], 2, [103] [2130], 2, [130] [2301], 2, [301] [2310], 2, [310] [3012], 3, [012] [3021], 3, [021] [3102], 3, [102] [3120], 3, [120] [3201], 3, [201] [3210], 3, [210] @. sort(L, L) #- [], [] [0], [0] [1], [1] [2], [2] [3], [3] [01], [01] [02], [02] [03], [03] [10], [01] [12], [12] [13], [13] [20], [02] [21], [12] [23], [23] [30], [03] [31], [13] [32], [23] [012], [012] [013], [013] [021], [012] [023], [023] [031], [013] [032], [023] [102], [012] [103], [013] [120], [012] [123], [123] [130], [013] [132], [123] [201], [012] [203], [023] [210], [012] [213], [123] [230], [023] [231], [123] [301], [013] [302], [023] [310], [013] [312], [123] [320], [023] [321], [123] [0123], [0123] [0132], [0123] [0213], [0123] [0231], [0123] [0312], [0123] [0321], [0123] [1023], [0123] [1032], [0123] [1203], [0123] [1230], [0123] [1302], [0123] [1320], [0123] [2013], [0123] [2031], [0123] [2103], [0123] [2130], [0123] [2301], [0123] [2310], [0123] [3012], [0123] [3021], [0123] [3102], [0123] [3120], [0123] [3201], [0123] [3210], [0123] @. *partition(E,L,L,L) ##-- 0, [], [], [] 1, [], [], [] 2, [], [], [] 3, [], [], [] 1, [0], [0], [] 2, [0], [0], [] 3, [0], [0], [] 0, [1], [], [1] 2, [1], [1], [] 3, [1], [1], [] 0, [2], [], [2] 1, [2], [], [2] 3, [2], [2], [] 0, [3], [], [3] 1, [3], [], [3] 2, [3], [], [3] 2, [01], [01], [] 3, [01], [01], [] 1, [02], [0], [2] 3, [02], [02], [] 1, [03], [0], [3] 2, [03], [0], [3] 2, [10], [10], [] 3, [10], [10], [] 0, [12], [], [12] 3, [12], [12], [] 0, [13], [], [13] 2, [13], [1], [3] 1, [20], [0], [2] 3, [20], [20], [] 0, [21], [], [21] 3, [21], [21], [] 0, [23], [], [23] 1, [23], [], [23] 1, [30], [0], [3] 2, [30], [0], [3] 0, [31], [], [31] 2, [31], [1], [3] 0, [32], [], [32] 1, [32], [], [32] 3, [012], [012], [] 2, [013], [01], [3] 3, [021], [021], [] 1, [023], [0], [23] 2, [031], [01], [3] 1, [032], [0], [32] 3, [102], [102], [] 2, [103], [10], [3] 3, [120], [120], [] 0, [123], [], [123] 2, [130], [10], [3] 0, [132], [], [132] 3, [201], [201], [] 1, [203], [0], [23] 3, [210], [210], [] 0, [213], [], [213] 1, [230], [0], [23] 0, [231], [], [231] 2, [301], [01], [3] 1, [302], [0], [32] 2, [310], [10], [3] 0, [312], [], [312] 1, [320], [0], [32] 0, [321], [], [321] @. @//E*O*F qs44.d// chmod u=rw,g=,o= qs44.d echo x - search.c sed 's/^@//' > "search.c" <<'@//E*O*F search.c//' /******************************************************************************/ /* */ /* Routines to control search. The search for clauses is basically */ /* greedy, but a limited number of alternative possibilities is */ /* kept on hand */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" Boolean FirstSave; /* flag for printing */ /* At any stage, the MAXPOSSLIT best literals to use next are kept in the array Possible. This procedure puts a new literal into the list if it qualifies */ void ProposeLiteral(Relation R, Boolean TF, Var *A, int Size, float LitBits, int OPos, int OTot, float Gain, Boolean Weak) /* -------------- */ { PossibleLiteral Entry; int i, j, ArgSize; /* See where this literal would go. Other things being equal, prefer an unnegated literal - regarding "<=" as unnegated */ i = NPossible; while ( i > 0 && ( Gain > Possible[i]->Gain + 1E-3 || Gain == Possible[i]->Gain && TF && ! Possible[i]->Sign ) ) { i--; } if ( i >= MAXPOSSLIT ) return; if ( NPossible < MAXPOSSLIT ) NPossible++; Entry = Possible[MAXPOSSLIT]; for ( j = MAXPOSSLIT ; j > i+1 ; j-- ) { Possible[j] = Possible[j-1]; } Possible[i+1] = Entry; ArgSize = (R->Arity+1)*sizeof(Var); if ( HasConst(R) ) ArgSize += sizeof(Const); Entry->Gain = Gain; Entry->Rel = R; Entry->Sign = TF; memcpy(Entry->Args, A, ArgSize); Entry->Bits = LitBits; Entry->NewSize = Size; Entry->PosCov = OPos; Entry->TotCov = OTot; Entry->WeakLits = ( Weak ? NWeakLits+1 : 0 ); } /* When all possible literals have been explored, the best of them (if there are any) is extracted and used. Others with gain close to the best are entered as backups */ Literal SelectLiteral() /* ------------- */ { int i; if ( ! NPossible ) return Nil; FirstSave = true; ForEach(i, 2, NPossible) { if ( Possible[i]->Gain >= MINALTFRAC * Possible[1]->Gain ) { Remember(MakeLiteral(i), Possible[i]->PosCov, Possible[i]->TotCov); } } return MakeLiteral(1); } Literal MakeLiteral(int i) /* ----------- */ { int ArgSize; Literal L; L = AllocZero(1, struct _lit_rec); L->Rel = Possible[i]->Rel; L->Sign = Possible[i]->Sign; L->Bits = Possible[i]->Bits; L->WeakLits = Possible[i]->WeakLits; ArgSize = (L->Rel->Arity+1)*sizeof(Var); if ( HasConst(L->Rel) ) ArgSize += sizeof(Const); L->Args = Alloc(ArgSize, Var); memcpy(L->Args, Possible[i]->Args, ArgSize); return L; } /* The array ToBeTried contains all backup points so far. This procedure sees whether another proposed backup will fit or will displace an existing backup */ void Remember(Literal L, int OPos, int OTot) /* -------- */ { int i, j; Alternative Entry; float InfoGain; InfoGain = OPos * (Info(StartClause.NPos, StartClause.NTot) - Info(OPos, OTot)); /* See where this entry would go */ for ( i = NToBeTried ; i && ToBeTried[i]->Value < InfoGain ; i-- ) ; if ( i >= MAXALTS ) { FreeLiteral(L); return; } if ( NToBeTried < MAXALTS ) NToBeTried++; Entry = ToBeTried[MAXALTS]; for ( j = MAXALTS ; j > i+1 ; j-- ) { ToBeTried[j] = ToBeTried[j-1]; } ToBeTried[i+1] = Entry; if ( Entry->UpToHere ) pfree(Entry->UpToHere); Entry->UpToHere = Alloc(NLit+2, Literal); memcpy(Entry->UpToHere, NewClause, (NLit+1)*sizeof(Literal)); Entry->UpToHere[NLit] = L; Entry->UpToHere[NLit+1] = Nil; Entry->Value = InfoGain; Verbose(1) { if ( FirstSave ) { putchar('\n'); FirstSave = false; } printf("\tSave "); PrintLiteral(L); printf(" (%d,%d value %.1f)\n", OPos, OTot, InfoGain); } } Boolean Recover() /* ------- */ { int i; Clause C; Alternative Entry; if ( SavedClause || ! NToBeTried || MAXRECOVERS-- < 1 ) return Nil; Entry = ToBeTried[1]; C = ToBeTried[1]->UpToHere; Verbose(1) { printf("\nRecover to "); PrintClause(Target, C); } ForEach(i, 2, NToBeTried) { ToBeTried[i-1] = ToBeTried[i]; } ToBeTried[NToBeTried] = Entry; NToBeTried--; RecoverState(C); CheckOriginalCaseCover(); ExamineVariableRelationships(); return true; } void FreeLiteral(Literal L) /* ----------- */ { pfree(L->Args); if ( L->ArgOrders ) pfree(L->ArgOrders); pfree(L); } void FreeClause(Clause C) /* ---------- */ { Clause CC; for ( CC = C ; *CC ; CC++ ) { FreeLiteral(*CC); } pfree(C); } @//E*O*F search.c// chmod u=rw,g=,o= search.c echo x - sort.d sed 's/^@//' > "sort.d" <<'@//E*O*F sort.d//' E: 0,1,2,3. L: *[],[0],[1],[2],[3],[01],[02],[03],[10],[12],[13],[20],[21],[23],[30],[31],[32],[012],[013],[021],[023],[031],[032],[102],[103],[120],[123],[130],[132],[201],[203],[210],[213],[230],[231],[301],[302],[310],[312],[320],[321],[0123],[0132],[0213],[0231],[0312],[0321],[1023],[1032],[1203],[1230],[1302],[1320],[2013],[2031],[2103],[2130],[2301],[2310],[3012],[3021],[3102],[3120],[3201],[3210]. *elt(E) 0 1 2 3 @. *components(L,E,L) #--/-## [0], 0, [] [1], 1, [] [2], 2, [] [3], 3, [] [01], 0, [1] [02], 0, [2] [03], 0, [3] [10], 1, [0] [12], 1, [2] [13], 1, [3] [20], 2, [0] [21], 2, [1] [23], 2, [3] [30], 3, [0] [31], 3, [1] [32], 3, [2] [012], 0, [12] [013], 0, [13] [021], 0, [21] [023], 0, [23] [031], 0, [31] [032], 0, [32] [102], 1, [02] [103], 1, [03] [120], 1, [20] [123], 1, [23] [130], 1, [30] [132], 1, [32] [201], 2, [01] [203], 2, [03] [210], 2, [10] [213], 2, [13] [230], 2, [30] [231], 2, [31] [301], 3, [01] [302], 3, [02] [310], 3, [10] [312], 3, [12] [320], 3, [20] [321], 3, [21] [0123], 0, [123] [0132], 0, [132] [0213], 0, [213] [0231], 0, [231] [0312], 0, [312] [0321], 0, [321] [1023], 1, [023] [1032], 1, [032] [1203], 1, [203] [1230], 1, [230] [1302], 1, [302] [1320], 1, [320] [2013], 2, [013] [2031], 2, [031] [2103], 2, [103] [2130], 2, [130] [2301], 2, [301] [2310], 2, [310] [3012], 3, [012] [3021], 3, [021] [3102], 3, [102] [3120], 3, [120] [3201], 3, [201] [3210], 3, [210] @. sort(L, L) #- [], [] [0], [0] [1], [1] [2], [2] [3], [3] [01], [01] [02], [02] [03], [03] [10], [01] [12], [12] [13], [13] [20], [02] [21], [12] [23], [23] [30], [03] [31], [13] [32], [23] [012], [012] [013], [013] [021], [012] [023], [023] [031], [013] [032], [023] [102], [012] [103], [013] [120], [012] [123], [123] [130], [013] [132], [123] [201], [012] [203], [023] [210], [012] [213], [123] [230], [023] [231], [123] [301], [013] [302], [023] [310], [013] [312], [123] [320], [023] [321], [123] [0123], [0123] [0132], [0123] [0213], [0123] [0231], [0123] [0312], [0123] [0321], [0123] [1023], [0123] [1032], [0123] [1203], [0123] [1230], [0123] [1302], [0123] [1320], [0123] [2013], [0123] [2031], [0123] [2103], [0123] [2130], [0123] [2301], [0123] [2310], [0123] [3012], [0123] [3021], [0123] [3102], [0123] [3120], [0123] [3201], [0123] [3210], [0123] @. *lt(E,E) ## 0, 1 0, 2 0, 3 1, 2 1, 3 2, 3 @. @//E*O*F sort.d// chmod u=rw,g=,o= sort.d echo x - state.c sed 's/^@//' > "state.c" <<'@//E*O*F state.c//' /******************************************************************************/ /* */ /* A state, summarising a point in the search for a clause, consists */ /* of a set of tuples and various counts. The routines here set up */ /* an initial state for a relation and produce the new state that */ /* results when a literal is added to the current (partial) clause */ /* */ /******************************************************************************/ #include "defns.i" #include "extern.i" /* Set up original state for search for definition */ void OriginalState(Relation R) /* ------------- */ { int i, j, WorldSize=1, TupleArity, NegTuples, Remaining; Tuple Case, *Scan; double drand48(); if ( ! LogFact ) { LogFact = Alloc(1001, float); LogFact[0] = 0.0; ForEach(i, 1, 1000) { LogFact[i] = LogFact[i-1] + Log2(i); } } /* Establish number of variables hence size of tuples, and set variable types equal to the type of variable in that position in the relation, and variable depths to zero */ StartDef.MaxVar = Current.MaxVar = R->Arity; TupleArity = R->Arity+1; ForEach(i, 1, R->Arity) { Variable[i]->Type = R->Type[i]; Variable[i]->TypeRef = R->TypeRef[i]; Variable[i]->Depth = 0; } StartDef.NPos = Number(R->Pos); AdjMinAccuracy = MINACCURACY; /* Test whether negative tuples are already defined in the relation */ if ( R->Neg ) { /* Simply copy positive and negative tuples */ StartDef.NTot = AllTuples = Number(R->Neg) + StartDef.NPos; if ( StartDef.NTot > MAXTUPLES ) { printf("Training Set Size exceeds tuple limit: "); printf("%d > %d\n", StartDef.NTot, MAXTUPLES); printf("Rerun with larger MAXTUPLES to proceed further\n"); exit(0); } StartDef.Tuples = Alloc(StartDef.NTot+1, Tuple); i = 0; for ( Scan = R->Pos ; *Scan ; Scan++ ) { AddTuple(i, *Scan, TupleArity, PosMark); i++; } for ( Scan = R->Neg ; *Scan ; Scan++ ) { AddTuple(i, *Scan, TupleArity, 0); i++; } } else { /* Negative tuples not already defined */ /* Find maximum training set size */ ForEach(j, 1, R->Arity) { if ( R->TypeRef[j]->Continuous ) Error(6, R->Name, Nil); WorldSize *= R->TypeRef[j]->NValues; } Remaining = WorldSize - (StartDef.NPos - R->PosDuplicates); AllTuples = Remaining + StartDef.NPos; NegTuples = SAMPLE * Remaining; if ( SAMPLE < 0.99 ) { AdjMinAccuracy = MINACCURACY / (MINACCURACY + SAMPLE * (1-MINACCURACY)); Verbose(1) { printf("\t\t(Adjusted minimum clause accuracy %.1f%%)\n", 100*AdjMinAccuracy); } } StartDef.NTot = StartDef.NPos + NegTuples; if ( StartDef.NTot > MAXTUPLES ) { printf("Training Set Size will exceed tuple limit: "); printf("%d > %d\n", StartDef.NPos + NegTuples, MAXTUPLES); printf("Rerun with larger MAXTUPLES to proceed further\n"); printf("(or use smaller sample of negative tuples).\n"); exit(0); } StartDef.Tuples = Alloc(StartDef.NTot+1, Tuple); /* Copy positive tuples */ i = 0; for ( Scan = R->Pos ; *Scan ; Scan++ ) { AddTuple(i, *Scan, TupleArity, PosMark); i++; } if ( WorldSize <= 10*MAXTUPLES ) { /* Enumerate all possible tuples and add a sample of the negative tuples to the training set - note that if SAMPLE is 1, the default, all negative tuples are added to the training set */ Case = Nil; while ( NegTuples && (Case = NextConstTuple(R, Case)) ) { if ( ! Join(R->Pos, R->PosIndex, DefaultVars, Case, R->Arity, true) && drand48() <= NegTuples / (float) Remaining-- ) { AddTuple(i, Case, TupleArity, 0); i++; NegTuples--; } } if ( Case ) pfree(Case); } else { /* Might take too long to enumerate all tuples, so generate them randomly - can result in duplicate negative tuples */ Case = Alloc(TupleArity, Const); while ( i < StartDef.NTot ) { RandomTuple(R, Case); if ( ! Join(R->Pos, R->PosIndex, DefaultVars, Case, R->Arity, 1)) { AddTuple(i, Case, TupleArity, 0); i++; } } pfree(Case); } } StartDef.Tuples[StartDef.NTot] = Nil; StartDef.NOrigPos = StartDef.NPos; StartDef.NOrigTot = StartDef.NTot; Realloc(Flags, StartDef.NTot+1, char); StartDef.BaseInfo = Info(StartDef.NPos, StartDef.NTot); } void AddTuple(int N, Tuple T, int TupleArity, int Mark) /* -------- */ { StartDef.Tuples[N] = Alloc(TupleArity, Const); memcpy(StartDef.Tuples[N], T, TupleArity*sizeof(Const)); StartDef.Tuples[N][0] = N | Mark; } /* Generate in Case the next constant tuple taking note of type constraints */ Tuple NextConstTuple(Relation R, Tuple Case) /* -------------- */ { int i, v; TypeInfo T; if ( ! Case ) { Case = Alloc(R->Arity+1, Const); ForEach(i, 1, R->Arity) { Case[i] = R->TypeRef[i]->Value[0]; } } else { i = R->Arity; T = R->TypeRef[i]; while ( Case[i] == T->Value[T->NValues-1] ) { if ( i <= 1 ) { pfree(Case); return Nil; } Case[i] = T->Value[0]; T = R->TypeRef[--i]; } for ( v = 1; Case[i] != T->Value[v-1] ; v++ ) ; Case[i] = T->Value[v]; } return Case; } /*****************************************************************************/ /* */ /* RandomTuple - generate a random tuple satisfying type constraints for */ /* relation R */ /* */ /*****************************************************************************/ void RandomTuple(Relation R, Tuple Result) /* ----------- */ { int i, v; TypeInfo T; double drand48(); ForEach(i, 1, R->Arity) { T = R->TypeRef[i]; v = (int)(T->NValues * drand48()); Result[i] = T->Value[v]; } } void NewState(Literal L, int NewSize) /* -------- */ { FormNewState(L->Rel, L->Sign, L->Args, NewSize); AcceptNewState(L->Rel, L->Args, NewSize); } /* Construct new state in New */ void FormNewState(Relation R, Boolean RSign, Var *A, int NewSize) /* ------------ */ { Tuple *TSP, Case, *Bindings, Instance; int i, N, RN; Boolean BuiltIn=false, Match, NotNegated; Const X2; if ( Predefined(R) ) { /* Prepare for calls to Satisfies() */ BuiltIn = true; RN = (int) R->Pos; if ( HasConst(R) ) { GetParam(&A[2], &X2); } else { X2 = A[2]; } } N = R->Arity; /* Find highest variable in new clause */ New.MaxVar = Current.MaxVar; if ( RSign ) { ForEach(i, 1, N) { New.MaxVar = Max(A[i], New.MaxVar); } } New.Tuples = Alloc(NewSize+1, Tuple); New.NPos = New.NTot = 0; for ( TSP = Current.Tuples ; Case = *TSP++ ; ) { if ( MissingValue(R,A,Case) ) continue; Match = ( BuiltIn ? Satisfies(RN, A[1], X2, Case) : Join(R->Pos, R->PosIndex, A, Case, N, ! RSign) ); NotNegated = RSign != 0; if ( Match != NotNegated ) continue; if ( ! BuiltIn && RSign ) { /* Add tuples from R->Pos */ CheckSize(New.NTot, NFound, &NewSize, &New.Tuples); Bindings = Found; while ( Instance = *Bindings++ ) { New.Tuples[New.NTot] = Extend(Case, Instance, A, N); New.NTot++; if ( Positive(Case) ) New.NPos++; } } else { CheckSize(New.NTot, 1, &NewSize, &New.Tuples); New.Tuples[New.NTot] = Alloc(New.MaxVar+1, Const); memcpy(New.Tuples[New.NTot], Case, (New.MaxVar+1)*sizeof(Const)); New.NTot++; if ( Positive(Case) ) New.NPos++; } } New.Tuples[New.NTot] = Nil; } /* Move state in New to Current */ void AcceptNewState(Relation R, Var *A, int NewSize) /* -------------- */ { int i, N, MaxDepth=0; Var V; if ( Current.Tuples != StartClause.Tuples ) { FreeTuples(Current.Tuples, true); } if ( New.MaxVar > Current.MaxVar ) { /* New variable(s) - update type and depth info */ N = R->Arity; ForEach(i, 1, N) { if ( (V = A[i]) <= Current.MaxVar ) { MaxDepth = Max(MaxDepth, Variable[V]->Depth); } } MaxDepth++; ForEach(i, 1, N) { if ( (V = A[i]) > Current.MaxVar ) { Variable[V]->Type = R->Type[i]; Variable[V]->TypeRef = R->TypeRef[i]; Variable[V]->Depth = MaxDepth; } } } New.BaseInfo = Info(New.NPos, New.NTot); /* Move all information across and resize tuples if necessary */ Current = New; if ( New.NTot < NewSize ) { Realloc(Current.Tuples, Current.NTot+1, Tuple); } Current.BaseInfo = Info(Current.NPos, Current.NTot); } /* Rebuild a training set by applying the literals in a clause to the copy of the training set */ void RecoverState(Clause C) /* ------------ */ { int i, SaveVerbosity; Literal L; float ExtraBits; /* Turn off messages during recovery */ SaveVerbosity = VERBOSITY; VERBOSITY = 0; if ( Current.Tuples != StartClause.Tuples ) { FreeTuples(Current.Tuples, true); Current = StartClause; } ForEach(i, 1, Target->Arity) { memset(PartialOrder[i], '#', MAXVARS+1); PartialOrder[i][i] = '='; } AnyPartialOrder = false; memset(Barred, false, MAXVARS+1); NRecLitClause = NDetLits = ClauseBits = 0; for ( NLit = 0 ; (L = C[NLit]) ; NLit++ ) { NewClause[NLit] = L; if ( L->Rel == Target ) { ExamineVariableRelationships(); AddOrders(L); } NewState(L, Current.NTot); if ( L->Sign == 2 ) { NDetLits++; } else { ExtraBits = L->Bits - Log2(NLit+1.001-NDetLits); ClauseBits += Max(0, ExtraBits); } if ( L->Rel == Target ) NoteRecursiveLit(L); NWeakLits = L->WeakLits; } NewClause[NLit] = Nil; VERBOSITY = SaveVerbosity; } void CheckSize(int SoFar, int Extra, int *NewSize, Tuple **TSAddr) /* --------- */ { if ( SoFar+Extra > *NewSize ) { *NewSize += Max(Extra, 1000); Realloc(*TSAddr, *NewSize+1, Tuple); } } /* Tack extra variables on a tuple */ Tuple Extend(Tuple Case, Tuple Binding, Var *A, int N) /* ------ */ { Tuple NewCase; int i; NewCase = Alloc(New.MaxVar+1, Const); memcpy(NewCase, Case, (Current.MaxVar+1)*sizeof(Const)); ForEach(i, 1, N) { NewCase[A[i]] = Binding[i]; } return NewCase; } void CheckOriginalCaseCover() /* ---------------------- */ { Tuple *TSP, Case; ClearFlags; Current.NOrigPos = Current.NOrigTot = 0; for ( TSP = Current.Tuples ; Case = *TSP++ ; ) { if ( ! TestFlag(Case[0]&Mask, TrueBit) ) { SetFlag(Case[0]&Mask, TrueBit); Current.NOrigTot++; if ( Positive(Case) ) Current.NOrigPos++; } } } /* Free up a bunch of tuples */ void FreeTuples(Tuple *TT, Boolean TuplesToo) /* ------- */ { Tuple *P; if ( TuplesToo ) { for ( P = TT ; *P ; P++ ) { pfree(*P); } } pfree(TT); } /* Find log (base 2) factorials using tabulated values and Stirling's approximation (adjusted) */ double Log2Fact(int n) /* -------- */ { return ( n < 1000 ? LogFact[n] : (n+0.5) * Log2(n) - n * Log2e + Log2sqrt2Pi - (n*0.7623)/820000 ); } @//E*O*F state.c// chmod u=rw,g=,o= state.c echo x - utility.c sed 's/^@//' > "utility.c" <<'@//E*O*F utility.c//' #include "defns.i" #include #include extern int VERBOSITY; /* Protected memory allocation routines on call for memory which is not allocated rather than let program continue erroneously */ void *pmalloc(unsigned arg) /* ------- */ { void *p; p = (void *) malloc(arg); if( p || !arg ) return p; printf("\n*** malloc erroneously returns NULL\n"); exit(1); } void *prealloc(void * arg1, unsigned arg2) /* -------- */ { void *p; if ( arg1 == Nil ) return pmalloc(arg2); p = (void *)realloc(arg1,arg2); if( p || !arg2 ) return p; printf("\n*** realloc erroneously returns NULL\n"); exit(1); } void *pcalloc(unsigned arg1, unsigned arg2) /* ------- */ { void *p; p = (void *)calloc(arg1,arg2); if( p || !arg1 || !arg2 ) return p; printf("\n*** calloc erroneously returns NULL\n"); exit(1); } void pfree(void *arg) { if ( arg ) free(arg); } float CPUTime() { struct rusage usage; getrusage(RUSAGE_SELF, &usage); return (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / 1E6; } @//E*O*F utility.c// chmod u=rw,g=,o= utility.c exit 0