|
|
researchv9-SUN3(old)
#include <stdio.h>
#define trace if (traceon) printf
extern FILE *popen();
extern char *getenv();
extern char *malloc();
/* HYpothesis Driven Expert */
struct ref {
struct ref *next;
struct defblk *this;
char *text;
};
struct defblk {
struct defblk *next;
char *name;
int type;
struct ref *definition;
};
struct conc {
int weight;
struct hype *hypo;
int vector;
int num;
struct fact *confirms[];
};
struct fact {
struct fact *next;
struct defblk *name;
int truth;
struct concr *setlist;
};
struct concr {
struct concr *next;
struct conc *this;
};
struct hype {
struct hype *next;
struct defblk *name;
int confid;
short asked;
short action;
struct ref *queries;
char *text;
char *explain;
};
#define NHASH 255
struct defblk *hashtable[NHASH];
#define FACT 1
#define HYPO 2
#define STRING 3
#define ASK 1
#define SCAN 2
#define RUN 3
#define FUNKNOWN 0
#define FTRUE 1
#define FFALSE -1
#define HUNCERTAIN 10
#define HTRUE 100
#define HFALSE 0
struct hype *hypes;
struct fact *facts;
int tot_facts;
int tot_hypes;
int traceon = 0;
FILE *kfile;
#define SYMCHAR 1
#define WHITE 2
char ctype[128] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, WHITE, WHITE, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
WHITE, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,
SYMCHAR,SYMCHAR,0, 0, 0, 0, 0, 0,
0,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,
SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,
SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,
SYMCHAR,SYMCHAR,SYMCHAR,0, 0, 0, 0, SYMCHAR,
0 ,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,
SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,
SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,SYMCHAR,
SYMCHAR,SYMCHAR,SYMCHAR,0, 0, 0, 0, 0
};
#define streq(x,y) (strcmp(x,y) == 0)
struct defblk *getref(name,type,create)
/* Keywords: symbol-table:50 internal-database:50 */
char *name;
int type;
int create;
{
int hash;
char *np;
struct defblk *defp;
np = name;
hash = 0;
while (*np) hash += *np++;
hash = hash %NHASH;
defp = hashtable[hash];
while (defp && strcmp(name,defp->name)) defp = defp->next;
if (defp == NULL) {
struct fact *factp;
struct hype *hypep;
if (create == 0) return(NULL);
defp = ((struct defblk *) malloc(sizeof(*defp)));
defp->next = hashtable[hash];
hashtable[hash] = defp;
defp->name = (char *) malloc(strlen(name)+1);
strcpy(defp->name,name);
defp->type = type;
switch(type) {
case STRING:
defp->definition = NULL;
break;
case FACT:
tot_facts++;
defp->definition = (struct ref *) malloc(sizeof(*factp));
factp = (struct fact *) defp->definition;
factp->name = defp;
factp->next = facts;
facts = factp;
factp->truth = FUNKNOWN;
factp->setlist = NULL;
trace ("Defining fact %s\n",name);
break;
case HYPO:
tot_hypes++;
defp->definition = (struct ref *) malloc(sizeof(*hypep));
hypep = (struct hype *) defp->definition;
hypep -> name = defp;
hypep -> next = hypes;
hypes = hypep;
hypep -> asked = 0;
hypep -> confid = HUNCERTAIN;
hypep -> text = NULL;
hypep -> explain = NULL;
hypep -> queries = NULL;
trace ("Defining hypothesis %s\n",name);
break;
}
} else {
if (type && (type != defp->type)) {
fprintf(stderr,"Multiply defined symbol: %s\n",name);
}
}
return(defp);
}
char expbuf[512];
char *expcom(oldcom)
register char *oldcom;
{
register char *newcom;
char symbuf[128];
char *symp;
struct defblk *defp;
struct fact *factp;
int infalse;
newcom = expbuf;
while (*oldcom) {
switch (*oldcom) {
case '\\':
*newcom++ = * ++oldcom;
break;
case '%':
oldcom++;
symp = symbuf;
while ((ctype[*oldcom] & SYMCHAR)==0) oldcom++;
while ((ctype[*oldcom] & SYMCHAR)) *symp++ = *oldcom++;
*symp = 0;
defp = getref(symbuf,0,0);
if (defp ) switch(defp->type) {
case STRING:
symp = (char *) defp->definition;
while (*symp) *newcom++ = *symp++;
oldcom--;
break;
case FACT:
factp = (struct fact *) defp->definition;
while (*oldcom != '(' ) oldcom++;
infalse = 0;
oldcom++;
while (1) {
switch (*oldcom) {
case 0:
case ')':
goto done;
case ':':
infalse++;
break;
case '\\':
++oldcom;
default:
if (((factp->truth == FTRUE) && (infalse == 0)) ||
((factp->truth == FFALSE) && (infalse))) {
*newcom++ = *oldcom;
}
break;
}
oldcom++;
}
} else {
fprintf(stderr,"%s is undefined on expansion",symbuf);
}
done: break;
default:
*newcom++ = *oldcom;
}
oldcom++;
}
*newcom= 0;
trace ("Expanded into %s\n",expbuf);
return(expbuf);
}
struct hype * curhype()
{
struct hype *hype,*rehype;
int maxhype;
maxhype = HUNCERTAIN; /* Cut off any below this level */
rehype = NULL;
for (hype = hypes; hype; hype = hype-> next) if ((hype->asked==0) && (hype->confid > maxhype)) {
maxhype = hype->confid;
rehype = hype;
}
trace ("Best hypothesis is %s\n",rehype->name->name);
return(rehype);
}
reset()
{
struct fact *factp;
struct hype *hypep;
struct defblk *defp;
int i;
for (i = 0; i < NHASH; i++) {
for (defp = hashtable[i]; defp; defp = defp->next) {
if (defp->type == STRING) defp->definition = NULL;
}
}
for (factp = facts; factp; factp = factp->next) factp->truth=FUNKNOWN;
for (hypep = hypes; hypep; hypep = hypep->next) {
hypep->confid = HUNCERTAIN;
hypep->asked = 0;
}
defp = getref("start",FACT,1);
setfact(defp->definition,FTRUE); /* Start up the inference engine */
}
askhype(hype)
struct hype *hype;
{
char buf[20];
struct defblk *defp;
struct ref *refp;
struct fact *factp;
struct fact *factors[20];
int truth[20];
int nfact = 0;
int i;
char *bufp;
FILE *fp;
trace ("Asking about hypothesis %s\n",hype->name->name);
refp = hype->queries;
while (refp) {
defp = refp->this;
if (defp->type == STRING) {
if (defp->definition) return(0);
goto setup;
}
factp = (struct fact *) defp->definition;
trace ("Sub-fact %s, state %d\n",factp->name->name,factp->truth);
if (factp->truth == FUNKNOWN) {
if (nfact == 0) {
setup: switch (hype->action) {
case ASK: printf ("%s\n\n",expcom(hype->text));
if (defp->type == STRING) {
gets(buf);
defp->definition = (struct ref *) malloc(strlen(buf)+1);
strcpy(defp->definition,buf);
return(1);
}
break;
case SCAN:
fp = fopen(hype->text,"r");
trace ("Scanning %s from hypothesis %s\n", hype->text,hype->name->name);
fmatch(fp,hype->queries);
fclose(fp);
return(1);
case RUN:
fp = popen(expcom(hype->text),"r");
trace ("Running %s from hypothesis %s\n", hype->text,hype->name->name);
fmatch(fp,hype->queries);
pclose(fp);
return(1);
}
}
factors[nfact++] = factp;
printf (" %d) %s\n",nfact,refp->text);
}
refp = refp->next;
}
if (nfact == 0) return(0);
printf ("\n? ");
again: gets(buf);
for (i = 0; i < nfact; i++) truth[i] = FFALSE;
for (bufp = buf; *bufp; bufp++) {
if (*bufp == 't') {
traceon = !traceon;
continue;
}
if (*bufp == '!') {
bufp++;
if (*bufp == 0) {
bufp = getenv("SHELL");
if ((bufp == NULL) || (*bufp == 0)) bufp= "/bin/sh";
}
system (bufp);
return(askhype(hype));
}
if (*bufp == 'q') return(-1);
if ((*bufp < '1') || (*bufp > '0'+nfact)) {
if ((*bufp == ' ') || (*bufp == ',')) continue;
printf ("Please type all of the numbers that apply\n");
goto again;
}
truth[*bufp-'1'] = FTRUE;
}
for (i = 0; i < nfact; i++) {
setfact(factors[i],truth[i]);
}
return(1);
}
setfact(factp,truth)
struct fact *factp;
int truth;
{
struct hype *hype;
struct conc *concp;
struct concr *refp;
int trigger;
int i;
factp->truth = truth;
trace ("Setting fact %s to %d\n",factp->name->name,truth);
for (refp = factp->setlist; refp; refp = refp ->next) {
concp = refp->this;
trigger = 1;
for (i = 0;(trigger && (i < concp->num)); i++) {
if (concp->confirms[i]->truth == FUNKNOWN) trigger = 0;
else {
if ((concp->vector>>i) & 1) {
if (concp->confirms[i]->truth == FFALSE) trigger = 0;
} else {
if (concp->confirms[i]->truth == FTRUE) trigger = 0;
}
}
}
if (trigger) {
sethype(concp->hypo,concp->weight);
}
}
}
sethype(hype,weight)
struct hype *hype;
int weight;
{
if (hype->name->type == FACT) {
struct fact *factp;
factp = (struct fact *) hype;
if (factp-> truth != FUNKNOWN) return;
if (weight == 0) {
setfact(factp,FFALSE);
} else {
setfact(factp,FTRUE);
}
return;
}
if (weight < 0) hype->confid = HTRUE;
else {
hype->confid *= weight;
hype->confid /= 10;
}
if (hype->confid > HTRUE) hype->confid = HTRUE;
trace ("Adjusting hypothesis %s by %d gives %d\n",hype->name->name,weight,hype->confid);
}
dumplike()
{
struct hype *hypo;
for (hypo = hypes; hypo; hypo = hypo->next) {
hypo->asked = 0;
}
while (hypo = curhype()) {
hypo->asked = 1;
if (hypo->explain) {
printf ("The following is a possible cause of your problem:\n\n%s\n",hypo->explain);
printf ("\nThis explaination has a confidence factor of %d on a scale of %d to %d\n",hypo->confid,HFALSE,HTRUE);
printf ("_________________________________________________________________________\n");
}
}
}
cycle()
{
struct hype *hypo;
int ret;
#ifdef DIAGNOSE
printf ("You will be asked to clarify your problem\n");
#endif
printf ("For each question, please answer with all of the numbers\n");
printf ("of the statements that apply. For example 136\n");
printf ("if answers 1, 3, and 6 apply. If you would like to quit, type 'q'\n");
printf ("If you would like to escape to run a unix commmand, type '!'\n");
printf ("or '!command' in response to a question.\n\n");
while (hypo = curhype()) {
if (ret= askhype(hypo)) {
if (ret < 0) return; /* User quit */
if (hypo->explain == NULL) hypo->asked = 1;
} else {
hypo->asked = 1;
if (hypo->explain) {
#ifdef DIAGNOSE
printf ("The following is a possible cause of your problem:\n\n%s\n",hypo->explain);
printf ("\nThis explaination has a confidence factor of %d on a scale of %d to %d\n",hypo->confid,HFALSE,HTRUE);
if (gyn("Would you like to continue to identify other possible causes") == 0) return;
#else
printf("%s\n",hypo->explain);
return(0);
#endif
}
}
}
}
gyn(string)
char *string;
{
char buf[100];
while (1) {
printf ("%s\n",string);
if (gets(buf) == NULL) return(0);
if (buf[0] == 'y') return(1);
if (buf[0] == 'n') return(0);
printf ("Please answer with 'yes' or 'no'\n");
}
}
char *
gstring()
{
char buf[512];
char *bufp;
int c;
c = nonblank();
if (c != '"') {
fprintf("Missing character string argument\n");
ungetc(c,kfile);
return;
}
bufp = buf;
while (((c =getc(kfile)) != EOF) && (c != '"')) {
if (c == '\\') c = getc(kfile);
*bufp++ = c;
}
*bufp++ = 0;
bufp = malloc(bufp-buf+1);
strcpy(bufp,buf);
trace ("Storing character string %s\n",bufp);
return(bufp);
}
nonblank()
{
int c;
while ((c = getc(kfile)) != EOF) {
if ((ctype[c] & WHITE) == 0) return(c);
}
return(EOF);
}
int number(sp)
/* Keywords: string-processing file-scanning:50 user-interface:10 */
char *sp;
{
int n;
n = 0;
while (*sp) n = n*10 + (*sp++) -'0';
return(n);
}
char symbuf[64];
char * symbol()
{
int c;
char *symp;
symp = symbuf;
c = nonblank();
while ((c != EOF) && (ctype[c]&SYMCHAR)) {
*symp++ = c;
c = getc(kfile);
}
if (c == EOF) return(NULL);
ungetc(c,kfile);
*symp++ = 0;
trace ("Reading symbol: %s\n",symbuf);
return(symbuf);
}
/* Knowledge file formats: */
/* Hypothesis name: { */
/* Ask: "text for asking" */
/* Scan: "file(s) to scan" */
/* Run: "command to run" */
/* Replies: { */
/* factname: "description" */
/* } */
/* Read: string */
/* Explain: "explaination if terminal diagnosis" */
/* Infer hypothesis <with certaintity number> from { */
/* Conclude fact from { */
/* fact, or !fact */
/* } */
main(argc, argv)
/* Keywords: user-interface command-line file-scanning:10 file-opening:10 */
int argc;
char *argv [];
{
int i;
int ktest = 0;
for (i = 1; i < argc; i++) {
if (streq(argv[i],"-t")) {
traceon++;
i++;
}
if (streq(argv[i],"-k")) {
ktest++;
i++;
}
if (argc>2) printf ("Loading file %s\n",argv[i]);
parse(argv[i]);
}
if (ktest) {
dumpknow();
}
while (1) {
reset();
cycle();
#ifdef DIAGNOSE
printf ("I can offer no further help with this problem\n");
printf ("If you are still having trouble, contact ihnss!warren\n\n");
if (gyn("Would you like a summary of all likely causes?")) dumplike();
if (gyn("Would you like to try another diagnosis?")==0) break;
#else
if (gyn("Would you like to do something else?")==0) break;
#endif
}
}
dumpknow()
{
struct fact *factp;
struct hype *hypep;
struct ref *refp;
struct conc *consp;
struct concr *concrp;
int header;
reset();
header = 0;
for (factp = facts; factp; factp= factp->next) {
for (concrp = factp->setlist; concrp; concrp = concrp->next) {
concrp->this->hypo->asked = 1;
}
}
header = 0;
for (hypep = hypes; hypep; hypep = hypep->next) {
if ((hypep->text == NULL)&& (hypep->explain == NULL)) {
if (header == 0) {
header = 1;
printf ("The following hypotheses are never defined:\n");
}
printf (" %s\n",hypep->name->name);
}
for (refp = hypep->queries; refp; refp = refp->next) {
((struct fact *) refp->this->definition)->truth = FTRUE;
}
}
header = 0;
for (hypep = hypes; hypep; hypep = hypep->next) {
if (hypep->asked == 0) {
if (header == 0) {
header = 1;
printf ("The following hypotheses are not inferred by any facts:\n");
}
printf (" %s\n",hypep->name->name);
}
}
header = 0;
for (factp = facts; factp; factp= factp->next) {
if (factp->truth == FUNKNOWN) {
if (header == 0) {
header = 1;
printf ("The following facts are never set:\n");
}
printf (" %s\n",factp->name->name);
}
}
header = 0;
for (factp = facts; factp; factp= factp->next) {
if (factp->setlist == NULL) {
if (header == 0) {
header = 1;
printf ("The following facts are never used to infer anything:\n");
}
printf (" %s\n",factp->name->name);
}
}
reset();
}
parse(np)
/* Keywords: file-scanning file-opening:10 preprocessor:10 database-input:10 */
char *np;
{
register char *symp;
char c;
kfile = fopen(np,"r");
if (kfile == NULL) {
fprintf(stderr,"Can't open %s\n",np);
return;
}
while (symp = symbol()) {
if (streq(symp,"Hypothesis")) addhype();
else if (streq(symp,"Infer")) addinfer(HYPO);
else if (streq(symp,"Conclude")) addinfer(FACT);
else {
fprintf (stderr,"Bad keyword %s\n",symp);
c = nonblank();
if (ctype[c] & SYMCHAR) ungetc(c,kfile);
}
}
}
addhype()
{
register char *sp;
register struct hype *hypep;
register struct defblk *defp;
register struct fact *factp;
struct ref *refp;
char c;
sp = symbol();
if (sp == NULL) {
eof: fprintf(stderr,"Unexpected EOF in hypothesis\n");
return;
}
defp = getref(sp,HYPO,1);
hypep = (struct hype *) defp->definition;
c = nonblank();
if (c != ':') {
fprintf(stderr,"Missing ':' after hypothesis name %s\n",sp);
}
c = nonblank();
if (c != '{') {
fprintf (stderr,"Empty hypothesis body %s\n",sp);
}
while (1) {
c = nonblank();
if ((c == EOF) || (c == '}')) return;
ungetc(c,kfile);
sp = symbol();
c = nonblank();
if (c != ':') {
fprintf(stderr,"Missing ':' after hypothesis name %s\n",sp);
}
if (streq(sp,"Ask")) {
hypep->text = gstring();
hypep->action = ASK;
}
else if (streq(sp,"Scan")) {
hypep->text = gstring();
hypep->action = SCAN;
}
else if (streq(sp,"Run")) {
hypep->text = gstring();
hypep->action = RUN;
} else if (streq(sp,"Explain")) {
hypep->explain = gstring();
} else if (streq(sp,"Read")) {
sp = symbol();
defp = getref(sp,STRING,1);
refp = (struct ref *) malloc(sizeof *refp);
refp->next = hypep->queries;
refp->this = defp;
refp->text = NULL;
hypep->queries = refp;
} else if (streq(sp,"Replies")) {
c = nonblank();
if (c != '{') {
fprintf (stderr,"Empty replies body %s\n",sp);
}
while (1) {
c = nonblank();
if (c == '}') break;
ungetc(c,kfile);
sp = symbol();
c = nonblank();
if (c != ':') {
fprintf(stderr,"Missing ':' after reply name %s\n",sp);
}
if ((*sp >= 'A') && (*sp <= 'Z')) {
/* Define a hypothesis and fact of the same name, and make an inference */
struct hype *infhype;
struct conc *concp;
struct concr *concrp;
defp = getref(sp,HYPO,1);
infhype = (struct hype *) defp->definition;
*sp += 32;
defp = getref(sp,FACT,1);
factp = (struct fact *) defp->definition;
if (factp->setlist) {
/* Already exists, assume the infers part does to */
goto makeref; /* Join other branch to make this reference to it. */
}
concrp = (struct concr *) malloc(sizeof *concrp);
factp->setlist = concrp;
concp = (struct conc *) malloc((sizeof *concp) + (sizeof factp));
concrp->this = concp;
concrp->next = NULL;
concp -> weight = -1;
concp ->hypo = infhype;
concp -> vector = 1;
concp -> num = 1;
concp ->confirms[0] = factp;
} else {
defp = getref(sp,FACT,1);
factp = (struct fact *) defp->definition;
}
makeref:
c = nonblank();
ungetc(c,kfile);
refp = (struct ref *) malloc(sizeof *refp);
refp -> next = hypep -> queries;
hypep->queries = refp;
refp->this = defp;
if (c == '"') {
refp->text = gstring();
}
}
} else {
fprintf (stderr,"Bad Keyword %s\n",sp);
}
}
}
addinfer(type)
int type;
{
struct hype *hypep;
struct fact *factp;
struct conc *concp;
struct fact *facts[20];
struct concr *concrp;
struct ref *refp;
struct defblk *defp;
register char *sp;
int factor;
int vector;
int c;
int numinf;
int num;
sp = symbol();
factor = -1;
if (*sp == '!') {
factor = 0;
sp++;
}
defp = getref(sp,type,1);
hypep = (struct hype *) defp->definition;
sp = symbol();
if (streq(sp,"certainty")) {
if (type != HYPO) fprintf(stderr,"Conclude clause can't have a certainty factor\n");
sp = symbol();
factor = number(sp);
sp = symbol();
}
if (streq(sp,"from")) {
c = nonblank();
if (c == '{') {
num=1000;
} else {
ungetc(c,kfile);
num = 1;
}
vector = 0;
numinf = 0;
while (num--) {
c = nonblank();
if (c == '}') break;
vector = vector << 1;
if (c != '!' ) {
vector += 1;
ungetc(c,kfile);
}
sp = symbol();
defp = getref(sp,FACT,1);
facts[numinf++] = (struct fact *) defp->definition;
}
if (numinf) {
int x;
concp = (struct conc *) malloc((sizeof *concp) + numinf * (sizeof factp));
concp ->hypo = hypep;
concp -> weight = factor;
concp -> vector = vector;
concp -> num = numinf;
x = 0;
while (--numinf >= 0) {
factp = facts[numinf];
concrp = (struct concr *) malloc(sizeof *concrp);
concrp ->next = factp->setlist;
factp->setlist = concrp;
concrp->this = concp;
concp->confirms[x++] = factp;
}
}
}
}
match(pat,targ)
char *pat,*targ;
{
int first;
register char *p, *t;
if (*pat== '^') {
first=1;
pat++;
} else first = 0;
while ( *targ) {
if (*pat == *targ) {
p = pat;
t = targ;
while (*p) if (*p++ != *t++) goto next;
return(1);
}
next: if (first) return(0);
targ++;
}
return(0);
}
fmatch(fp,refp)
FILE *fp;
struct ref *refp;
{
struct fact *factp;
struct ref *rp;
char buf[512];
if (fp == NULL) return;
while (fgets(buf,512,fp)) {
for (rp = refp; rp != NULL; rp = rp->next) {
if (rp->this->type == STRING) {
buf[strlen(buf)-1] = 0;
rp->this->definition = (struct ref *) malloc(strlen(buf)+1);
strcpy(rp->this->definition,buf);
} else {
factp = (struct fact *) rp->this->definition;
if ((factp->truth == FUNKNOWN) && match(rp->text,buf)) setfact(factp,FTRUE);
}
}
}
for (rp = refp; rp != NULL; rp = rp->next) {
if (rp->this->type == FACT) {
factp = (struct fact *) rp->this->definition;
if (factp->truth == FUNKNOWN) setfact(factp,FFALSE);
}
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.