14246b616SDavid du Colombier #include <u.h>
24246b616SDavid du Colombier #include <libc.h>
34246b616SDavid du Colombier #include <bio.h>
44246b616SDavid du Colombier #include <ctype.h>
54246b616SDavid du Colombier #include "msgdb.h"
64246b616SDavid du Colombier
74246b616SDavid du Colombier void
usage(void)84246b616SDavid du Colombier usage(void)
94246b616SDavid du Colombier {
104246b616SDavid du Colombier fprint(2, "usage: upas/msgclass [-a] [-d name dbfile]... [-l lockfile] [-m mul] [-t thresh] [tokenfile ...]\n");
114246b616SDavid du Colombier exits("usage");
124246b616SDavid du Colombier }
134246b616SDavid du Colombier
144246b616SDavid du Colombier enum
154246b616SDavid du Colombier {
164246b616SDavid du Colombier MAXBEST = 32,
174246b616SDavid du Colombier MAXLEN = 64,
184246b616SDavid du Colombier MAXTAB = 256,
194246b616SDavid du Colombier };
204246b616SDavid du Colombier
214246b616SDavid du Colombier typedef struct Ndb Ndb;
224246b616SDavid du Colombier struct Ndb
234246b616SDavid du Colombier {
244246b616SDavid du Colombier char *name;
254246b616SDavid du Colombier char *file;
264246b616SDavid du Colombier Msgdb *db;
274246b616SDavid du Colombier double p;
284246b616SDavid du Colombier long nmsg;
294246b616SDavid du Colombier };
304246b616SDavid du Colombier
314246b616SDavid du Colombier typedef struct Word Word;
324246b616SDavid du Colombier struct Word
334246b616SDavid du Colombier {
344246b616SDavid du Colombier char s[MAXLEN];
354246b616SDavid du Colombier int count[MAXTAB];
364246b616SDavid du Colombier double p[MAXTAB];
374246b616SDavid du Colombier double mp;
384246b616SDavid du Colombier int mi; /* w.p[w.mi] = w.mp */
394246b616SDavid du Colombier int nmsg;
404246b616SDavid du Colombier };
414246b616SDavid du Colombier
424246b616SDavid du Colombier Ndb db[MAXTAB];
434246b616SDavid du Colombier int ndb;
444246b616SDavid du Colombier
454246b616SDavid du Colombier int add;
464246b616SDavid du Colombier int mul;
474246b616SDavid du Colombier Msgdb *indb;
484246b616SDavid du Colombier
494246b616SDavid du Colombier Word best[MAXBEST];
504246b616SDavid du Colombier int mbest = 15;
514246b616SDavid du Colombier int nbest;
524246b616SDavid du Colombier
534246b616SDavid du Colombier void process(Biobuf*, char*);
544246b616SDavid du Colombier void lockfile(char*);
554246b616SDavid du Colombier
564246b616SDavid du Colombier void
noteword(Word * w,char * s)574246b616SDavid du Colombier noteword(Word *w, char *s)
584246b616SDavid du Colombier {
594246b616SDavid du Colombier int i;
604246b616SDavid du Colombier
614246b616SDavid du Colombier for(i=nbest-1; i>=0; i--)
624246b616SDavid du Colombier if(w->mp < best[i].mp)
634246b616SDavid du Colombier break;
644246b616SDavid du Colombier i++;
654246b616SDavid du Colombier
664246b616SDavid du Colombier if(i >= mbest)
674246b616SDavid du Colombier return;
684246b616SDavid du Colombier if(nbest == mbest)
694246b616SDavid du Colombier nbest--;
704246b616SDavid du Colombier if(i < nbest)
714246b616SDavid du Colombier memmove(&best[i+1], &best[i], (nbest-i)*sizeof(best[0]));
724246b616SDavid du Colombier best[i] = *w;
734246b616SDavid du Colombier strecpy(best[i].s, best[i].s+MAXLEN, s);
744246b616SDavid du Colombier nbest++;
754246b616SDavid du Colombier }
764246b616SDavid du Colombier
774246b616SDavid du Colombier void
main(int argc,char ** argv)784246b616SDavid du Colombier main(int argc, char **argv)
794246b616SDavid du Colombier {
804246b616SDavid du Colombier int i, bad, m, tot, nn, j;
814246b616SDavid du Colombier Biobuf bin, *b, bout;
824246b616SDavid du Colombier char *s, *lf;
834246b616SDavid du Colombier double totp, p, thresh;
844246b616SDavid du Colombier long n;
854246b616SDavid du Colombier Word w;
864246b616SDavid du Colombier
874246b616SDavid du Colombier lf = nil;
884246b616SDavid du Colombier thresh = 0;
894246b616SDavid du Colombier ARGBEGIN{
904246b616SDavid du Colombier case 'a':
914246b616SDavid du Colombier add = 1;
924246b616SDavid du Colombier break;
934246b616SDavid du Colombier case 'd':
944246b616SDavid du Colombier if(ndb >= MAXTAB)
954246b616SDavid du Colombier sysfatal("too many db classes");
964246b616SDavid du Colombier db[ndb].name = EARGF(usage());
974246b616SDavid du Colombier db[ndb].file = EARGF(usage());
984246b616SDavid du Colombier ndb++;
994246b616SDavid du Colombier break;
1004246b616SDavid du Colombier case 'l':
1014246b616SDavid du Colombier lf = EARGF(usage());
1024246b616SDavid du Colombier break;
1034246b616SDavid du Colombier case 'm':
1044246b616SDavid du Colombier mul = atoi(EARGF(usage()));
1054246b616SDavid du Colombier break;
1064246b616SDavid du Colombier case 't':
1074246b616SDavid du Colombier thresh = atof(EARGF(usage()));
1084246b616SDavid du Colombier break;
1094246b616SDavid du Colombier default:
1104246b616SDavid du Colombier usage();
1114246b616SDavid du Colombier }ARGEND
1124246b616SDavid du Colombier
1134246b616SDavid du Colombier if(ndb == 0){
1144246b616SDavid du Colombier fprint(2, "must have at least one -d option\n");
1154246b616SDavid du Colombier usage();
1164246b616SDavid du Colombier }
1174246b616SDavid du Colombier
1184246b616SDavid du Colombier indb = mdopen(nil, 1);
1194246b616SDavid du Colombier if(argc == 0){
1204246b616SDavid du Colombier Binit(&bin, 0, OREAD);
1214246b616SDavid du Colombier process(&bin, "<stdin>");
1224246b616SDavid du Colombier Bterm(&bin);
1234246b616SDavid du Colombier }else{
1244246b616SDavid du Colombier bad = 0;
1254246b616SDavid du Colombier for(i=0; i<argc; i++){
1264246b616SDavid du Colombier if((b = Bopen(argv[i], OREAD)) == nil){
1274246b616SDavid du Colombier fprint(2, "opening %s: %r\n", argv[i]);
1284246b616SDavid du Colombier bad = 1;
1294246b616SDavid du Colombier continue;
1304246b616SDavid du Colombier }
1314246b616SDavid du Colombier process(b, argv[i]);
1324246b616SDavid du Colombier Bterm(b);
1334246b616SDavid du Colombier }
1344246b616SDavid du Colombier if(bad)
1354246b616SDavid du Colombier exits("open inputs");
1364246b616SDavid du Colombier }
1374246b616SDavid du Colombier
1384246b616SDavid du Colombier lockfile(lf);
1394246b616SDavid du Colombier bad = 0;
1404246b616SDavid du Colombier for(i=0; i<ndb; i++){
1414246b616SDavid du Colombier if((db[i].db = mdopen(db[i].file, 0)) == nil){
1424246b616SDavid du Colombier fprint(2, "opendb %s: %r\n", db[i].file);
1434246b616SDavid du Colombier bad = 1;
1444246b616SDavid du Colombier }
1454246b616SDavid du Colombier db[i].nmsg = mdget(db[i].db, "*From*");
1464246b616SDavid du Colombier }
1474246b616SDavid du Colombier if(bad)
1484246b616SDavid du Colombier exits("open databases");
1494246b616SDavid du Colombier
1504246b616SDavid du Colombier /* run conditional probabilities of input words, getting 15 most specific */
1514246b616SDavid du Colombier mdenum(indb);
1524246b616SDavid du Colombier nbest = 0;
1534246b616SDavid du Colombier while(mdnext(indb, &s, &n) >= 0){
1544246b616SDavid du Colombier tot = 0;
1554246b616SDavid du Colombier totp = 0.0;
1564246b616SDavid du Colombier for(i=0; i<ndb; i++){
1574246b616SDavid du Colombier nn = mdget(db[i].db, s)*(i==0 ? 3 : 1);
1584246b616SDavid du Colombier tot += nn;
1594246b616SDavid du Colombier w.count[i] = nn;
1604246b616SDavid du Colombier p = w.count[i]/(double)db[i].nmsg;
1614246b616SDavid du Colombier if(p >= 1.0)
1624246b616SDavid du Colombier p = 1.0;
1634246b616SDavid du Colombier w.p[i] = p;
1644246b616SDavid du Colombier totp += p;
1654246b616SDavid du Colombier }
1664246b616SDavid du Colombier //fprint(2, "%s tot %d totp %g\n", s, tot, totp);
1674246b616SDavid du Colombier if(tot < 2)
1684246b616SDavid du Colombier continue;
1694246b616SDavid du Colombier w.mp = 0.0;
1704246b616SDavid du Colombier for(i=0; i<ndb; i++){
1714246b616SDavid du Colombier p = w.p[i];
1724246b616SDavid du Colombier p /= totp;
1734246b616SDavid du Colombier if(p < 0.001)
1744246b616SDavid du Colombier p = 0.001;
1754246b616SDavid du Colombier else if(p > 0.999)
1764246b616SDavid du Colombier p = 0.999;
1774246b616SDavid du Colombier if(p > w.mp){
1784246b616SDavid du Colombier w.mp = p;
1794246b616SDavid du Colombier w.mi = i;
1804246b616SDavid du Colombier }
1814246b616SDavid du Colombier w.p[i] = p;
1824246b616SDavid du Colombier }
1834246b616SDavid du Colombier noteword(&w, s);
1844246b616SDavid du Colombier }
1854246b616SDavid du Colombier
1864246b616SDavid du Colombier /* compute conditional probabilities of message classes using 15 most specific */
1874246b616SDavid du Colombier totp = 0.0;
1884246b616SDavid du Colombier for(i=0; i<ndb; i++){
1894246b616SDavid du Colombier p = 1.0;
1904246b616SDavid du Colombier for(j=0; j<nbest; j++)
1914246b616SDavid du Colombier p *= best[j].p[i];
1924246b616SDavid du Colombier db[i].p = p;
1934246b616SDavid du Colombier totp += p;
1944246b616SDavid du Colombier }
1954246b616SDavid du Colombier for(i=0; i<ndb; i++)
1964246b616SDavid du Colombier db[i].p /= totp;
1974246b616SDavid du Colombier m = 0;
1984246b616SDavid du Colombier for(i=1; i<ndb; i++)
1994246b616SDavid du Colombier if(db[i].p > db[m].p)
2004246b616SDavid du Colombier m = i;
2014246b616SDavid du Colombier
2024246b616SDavid du Colombier Binit(&bout, 1, OWRITE);
2034246b616SDavid du Colombier if(db[m].p < thresh)
2044246b616SDavid du Colombier m = -1;
2054246b616SDavid du Colombier if(m >= 0)
2064246b616SDavid du Colombier Bprint(&bout, "%s", db[m].name);
2074246b616SDavid du Colombier else
2084246b616SDavid du Colombier Bprint(&bout, "inconclusive");
2094246b616SDavid du Colombier for(j=0; j<ndb; j++)
2104246b616SDavid du Colombier Bprint(&bout, " %s=%g", db[j].name, db[j].p);
2114246b616SDavid du Colombier Bprint(&bout, "\n");
2124246b616SDavid du Colombier for(i=0; i<nbest; i++){
2134246b616SDavid du Colombier Bprint(&bout, "%s", best[i].s);
2144246b616SDavid du Colombier for(j=0; j<ndb; j++)
2154246b616SDavid du Colombier Bprint(&bout, " %s=%g", db[j].name, best[i].p[j]);
2164246b616SDavid du Colombier Bprint(&bout, "\n");
2174246b616SDavid du Colombier }
2184246b616SDavid du Colombier Bprint(&bout, "%s %g\n", best[i].s, best[i].p[m]);
2194246b616SDavid du Colombier Bterm(&bout);
2204246b616SDavid du Colombier
2214246b616SDavid du Colombier if(m >= 0 && add){
2224246b616SDavid du Colombier mdenum(indb);
2234246b616SDavid du Colombier while(mdnext(indb, &s, &n) >= 0)
2244246b616SDavid du Colombier mdput(db[m].db, s, mdget(db[m].db, s)+n*mul);
2254246b616SDavid du Colombier mdclose(db[m].db);
2264246b616SDavid du Colombier }
2274246b616SDavid du Colombier exits(nil);
2284246b616SDavid du Colombier }
2294246b616SDavid du Colombier
2304246b616SDavid du Colombier void
process(Biobuf * b,char *)2314246b616SDavid du Colombier process(Biobuf *b, char*)
2324246b616SDavid du Colombier {
2334246b616SDavid du Colombier char *s;
2344246b616SDavid du Colombier char *p;
2354246b616SDavid du Colombier long n;
2364246b616SDavid du Colombier
2374246b616SDavid du Colombier while((s = Brdline(b, '\n')) != nil){
2384246b616SDavid du Colombier s[Blinelen(b)-1] = 0;
2394246b616SDavid du Colombier if((p = strrchr(s, ' ')) != nil){
2404246b616SDavid du Colombier *p++ = 0;
2414246b616SDavid du Colombier n = atoi(p);
2424246b616SDavid du Colombier }else
2434246b616SDavid du Colombier n = 1;
2444246b616SDavid du Colombier mdput(indb, s, mdget(indb, s)+n);
2454246b616SDavid du Colombier }
2464246b616SDavid du Colombier }
2474246b616SDavid du Colombier
2484246b616SDavid du Colombier int tpid;
2494246b616SDavid du Colombier void
killtickle(void)2504246b616SDavid du Colombier killtickle(void)
2514246b616SDavid du Colombier {
2524246b616SDavid du Colombier postnote(PNPROC, tpid, "die");
2534246b616SDavid du Colombier }
2544246b616SDavid du Colombier
2554246b616SDavid du Colombier void
lockfile(char * s)2564246b616SDavid du Colombier lockfile(char *s)
2574246b616SDavid du Colombier {
2584246b616SDavid du Colombier int fd, t, w;
2594246b616SDavid du Colombier char err[ERRMAX];
2604246b616SDavid du Colombier
2614246b616SDavid du Colombier if(s == nil)
2624246b616SDavid du Colombier return;
2634246b616SDavid du Colombier w = 50;
2644246b616SDavid du Colombier t = 0;
2654246b616SDavid du Colombier for(;;){
2664246b616SDavid du Colombier fd = open(s, OREAD);
2674246b616SDavid du Colombier if(fd >= 0)
2684246b616SDavid du Colombier break;
2694246b616SDavid du Colombier rerrstr(err, sizeof err);
270*375daca8SDavid du Colombier if(strstr(err, "file is locked")==nil && strstr(err, "exclusive lock")==nil))
2714246b616SDavid du Colombier break;
2724246b616SDavid du Colombier sleep(w);
2734246b616SDavid du Colombier t += w;
2744246b616SDavid du Colombier if(w < 1000)
2754246b616SDavid du Colombier w = (w*3)/2;
2764246b616SDavid du Colombier if(t > 120*1000)
2774246b616SDavid du Colombier break;
2784246b616SDavid du Colombier }
2794246b616SDavid du Colombier if(fd < 0)
2804246b616SDavid du Colombier sysfatal("could not lock %s", s);
2814246b616SDavid du Colombier switch(tpid = fork()){
2824246b616SDavid du Colombier case -1:
2834246b616SDavid du Colombier sysfatal("fork: %r");
2844246b616SDavid du Colombier case 0:
2854246b616SDavid du Colombier for(;;){
2864246b616SDavid du Colombier sleep(30*1000);
2874246b616SDavid du Colombier free(dirfstat(fd));
2884246b616SDavid du Colombier }
2894246b616SDavid du Colombier _exits(nil);
2904246b616SDavid du Colombier default:
2914246b616SDavid du Colombier break;
2924246b616SDavid du Colombier }
2934246b616SDavid du Colombier close(fd);
2944246b616SDavid du Colombier atexit(killtickle);
2954246b616SDavid du Colombier }
2964246b616SDavid du Colombier
297