OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [mw/] [src/] [demos/] [nxscribble/] [sc.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 673 markom
/***********************************************************************
2
 
3
sc.c - creates classifiers from feature vectors of examples, as well as
4
   classifying example feature vectors.
5
 
6
Copyright (C) 1991 Dean Rubine
7
 
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 1, or (at your option)
11
any later version.
12
 
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
 
18
You should have received a copy of the GNU General Public License
19
along with this program (in ../COPYING); if not, write to the Free
20
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
 
22
***********************************************************************/
23
 
24
 
25
#include "bitvector.h"
26
#include "matrix.h"
27
#include "util.h"
28
#include "sc.h"
29
#include "stdio.h"
30
#include "stdlib.h"
31
#include "math.h"
32
#include "zdebug.h"
33
 
34
#define EPS     (1.0e-6)        /* for singular matrix check */
35
sClassifier
36
sNewClassifier()
37
{
38
        register sClassifier sc = allocate(1, struct sclassifier);
39
        sc->nfeatures = -1;
40
        sc->nclasses = 0;
41
        sc->classdope = allocate(MAXSCLASSES, sClassDope);
42
        sc->w = NULL;
43
        return sc;
44
}
45
 
46
void
47
sFreeClassifier(sc)
48
register sClassifier sc;
49
{
50
        register int i;
51
        register sClassDope scd;
52
 
53
        for(i = 0; i < sc->nclasses; i++) {
54
                scd = sc->classdope[i];
55
                if(scd->name) free(scd->name);
56
                if(scd->sumcov) FreeMatrix(scd->sumcov);
57
                if(scd->average) FreeVector(scd->average);
58
                free(scd);
59
                if(sc->w && sc->w[i]) FreeVector(sc->w[i]);
60
        }
61
        free(sc->classdope);
62
        if(sc->w) free(sc->w);
63
        if(sc->cnst) FreeVector(sc->cnst);
64
        if(sc->invavgcov) FreeMatrix(sc->invavgcov);
65
        free(sc);
66
}
67
 
68
sClassDope
69
sClassNameLookup(sc, classname)
70
register sClassifier sc;
71
register char *classname;
72
{
73
        register int i;
74
        register sClassDope scd;
75
        static sClassifier lastsc = NULL;
76
        static sClassDope lastscd = NULL;
77
 
78
        /* quick check for last class name */
79
        if(lastsc == sc && lastscd != NULL && STREQ(lastscd->name, classname))
80
                return lastscd;
81
 
82
        /* linear search through all classes for name */
83
        for(i = 0; i < sc->nclasses; i++) {
84
                scd = sc->classdope[i];
85
                if(STREQ(scd->name, classname))
86
                        return lastsc = sc, lastscd = scd;
87
        }
88
        lastsc = NULL;
89
        lastscd = NULL;
90
        return NULL;
91
}
92
 
93
static sClassDope
94
sAddClass(sc, classname)
95
register sClassifier sc;
96
char *classname;
97
{
98
        register sClassDope scd;
99
 
100
        sc->classdope[sc->nclasses] = scd = allocate(1, struct sclassdope);
101
        scd->name = scopy(classname);
102
        scd->number = sc->nclasses;
103
        scd->nexamples = 0;
104
        scd->sumcov = NULL;
105
        ++sc->nclasses;
106
        return scd;
107
}
108
 
109
void
110
sAddExample(sc, classname, y)
111
register sClassifier sc;
112
char *classname;
113
Vector y;
114
{
115
        register sClassDope scd;
116
        register int i, j;
117
        double nfv[50];
118
        double nm1on, recipn;
119
 
120
        scd = sClassNameLookup(sc, classname);
121
        if(scd == NULL) {
122
/* fprintf(stderr, "sAddExample: calling sAddClass on %s.\n", classname); */
123
                scd = sAddClass(sc, classname);
124
              }
125
 
126
        if(sc->nfeatures == -1) {
127
                sc->nfeatures = NROWS(y);
128
/*              fprintf(stderr, "sAddExample: setting sc->nfeatures to NROWS(y).\n"); */
129
              }
130
 
131
        if(scd->nexamples == 0) {
132
/*              fprintf(stderr, "sAddExample: allocating  & zeroing scd->average & scd->sumcov.\n"); */
133
                scd->average = NewVector(sc->nfeatures);
134
                ZeroVector(scd->average);
135
                scd->sumcov = NewMatrix(sc->nfeatures, sc->nfeatures);
136
                ZeroMatrix(scd->sumcov);
137
 
138
        }
139
 
140
        if(sc->nfeatures != NROWS(y)) {
141
                PrintVector(y, "sAddExample: funny feature vector nrows!=%d",
142
                        sc->nfeatures);
143
                return;
144
        }
145
 
146
        scd->nexamples++;
147
        nm1on = ((double) scd->nexamples-1)/scd->nexamples;
148
        recipn = 1.0/scd->nexamples;
149
 
150
        /* incrementally update covariance matrix */
151
        for(i = 0; i < sc->nfeatures; i++)
152
                nfv[i] = y[i] - scd->average[i];
153
 
154
        /* only upper triangular part computed */
155
        for(i = 0; i < sc->nfeatures; i++)
156
           for(j = i; j < sc->nfeatures; j++)
157
                scd->sumcov[i][j] += nm1on * nfv[i] * nfv[j];
158
 
159
        /* incrementally update mean vector */
160
        for(i = 0; i < sc->nfeatures; i++)
161
                scd->average[i] = nm1on * scd->average[i] + recipn * y[i];
162
 
163
}
164
 
165
void
166
sDoneAdding(sc)
167
register sClassifier sc;
168
{
169
        register int i, j;
170
        int c;
171
        int ne, denom;
172
        double oneoverdenom;
173
        register Matrix s;
174
        register Matrix avgcov;
175
        double det;
176
        register sClassDope scd;
177
 
178
        if(sc->nclasses == 0) {
179
                error("No classes for adding to classifier");
180
                return;
181
            }
182
 
183
        /* Given covariance matrices for each class (* number of examples - 1)
184
            compute the average (common) covariance matrix */
185
 
186
        avgcov = NewMatrix(sc->nfeatures, sc->nfeatures);
187
        ZeroMatrix(avgcov);
188
        ne = 0;
189
        for(c = 0; c < sc->nclasses; c++) {
190
                scd = sc->classdope[c];
191
                ne += scd->nexamples;
192
                s = scd->sumcov;
193
                for(i = 0; i < sc->nfeatures; i++)
194
                        for(j = i; j < sc->nfeatures; j++)
195
                                avgcov[i][j] += s[i][j];
196
        }
197
 
198
        denom = ne - sc->nclasses;
199
        if(denom <= 0) {
200
            error("Number of classes must be less than number of examples");
201
            return;
202
        }
203
 
204
        oneoverdenom = 1.0 / denom;
205
        for(i = 0; i < sc->nfeatures; i++)
206
                for(j = i; j < sc->nfeatures; j++)
207
                        avgcov[j][i] = avgcov[i][j] *= oneoverdenom;
208
 
209
        Z('a') PrintMatrix(avgcov, "Average Covariance Matrix\n");
210
        /* invert the avg covariance matrix */
211
 
212
        sc->invavgcov = NewMatrix(sc->nfeatures, sc->nfeatures);
213
        det = InvertMatrix(avgcov, sc->invavgcov);
214
        if(fabs(det) <= EPS)
215
                FixClassifier(sc, avgcov);
216
 
217
        /* now compute discrimination functions */
218
        sc->w = allocate(sc->nclasses, Vector);
219
        sc->cnst = NewVector(sc->nclasses);
220
        for(c = 0; c < sc->nclasses; c++) {
221
                scd = sc->classdope[c];
222
                sc->w[c] = NewVector(sc->nfeatures);
223
                VectorTimesMatrix(scd->average, sc->invavgcov, sc->w[c]);
224
                sc->cnst[c] = -0.5 * InnerProduct(sc->w[c], scd->average);
225
                /* could add log(priorprob class c) to cnst[c] */
226
        }
227
 
228
        FreeMatrix(avgcov);
229
        return;
230
}
231
 
232
sClassDope
233
sClassify(sc, fv) {
234
        return sClassifyAD(sc, fv, NULL, NULL);
235
}
236
 
237
sClassDope
238
sClassifyAD(sc, fv, ap, dp)
239
sClassifier sc;
240
Vector fv;
241
double *ap;
242
double *dp;
243
{
244
        double disc[MAXSCLASSES];
245
        register int i, maxclass;
246
        double denom, exp();
247
        register sClassDope scd;
248
        double d;
249
 
250
        if(sc->w == NULL) {
251
                error("%x not a trained classifier", sc);
252
                return(NULL);
253
       }
254
 
255
        for(i = 0; i < sc->nclasses; i++) {
256
/* ari */
257
          double IP;
258
          IP = InnerProduct(sc->w[i], fv);
259
/*        fprintf(stderr, "sClassifyAD:  InnerProduct for class %s is %f.\n", sc->classdope[i]->name, IP); */
260
/*        fprintf(stderr, "sClassifyAD:  sc->cnst[i] = %f.\n", sc->cnst[i]); */
261
          disc[i] = IP + sc->cnst[i];
262
/*        fprintf(stderr, "sClassifyAD:  Set disc = %f for class %s.\n", disc[i],sc->classdope[i]->name); */
263
 
264
/*        disc[i] = InnerProduct(sc->w[i], fv) + sc->cnst[i]; */
265
        }
266
 
267
        maxclass = 0;
268
        for(i = 1; i < sc->nclasses; i++)
269
                if(disc[i] > disc[maxclass])
270
                        maxclass = i;
271
 
272
/* ari */
273
/* PF_INIT_COS  0         initial angle (cos)                         */
274
/* PF_INIT_SIN  1        initial angle (sin)                         */
275
/* PF_BB_LEN    2        length of bounding box diagonal             */
276
/* PF_BB_TH     3        angle of bounding box diagonal              */
277
/* PF_SE_LEN    4        length between start and end points         */
278
/* PF_SE_COS    5        cos of angle between start and end points   */
279
/* PF_SE_SIN    6        sin of angle between start and end points   */
280
/* PF_LEN       7        arc length of path                          */
281
/* PF_TH        8        total angle traversed                       */
282
/* PF_ATH       9        sum of abs vals of angles traversed         */
283
/* PF_SQTH      10       sum of squares of angles traversed          */
284
/* PF_DUR       11       duration of path                            */
285
/* ifndef USE_TIME                                                   */
286
/*      NFEATURES       12                                           */
287
/* else                                                              */
288
/*      PF_MAXV         12         maximum speed                     */
289
/*      NFEATURES       13                                           */
290
/* endif                                                             */
291
 
292
/*
293
* fprintf(stderr, "\nFeature vector:\n");
294
* fprintf(stderr, "    start cosine      %8.4f    path length       %8.4f\n",
295
*       fv[PF_INIT_COS], fv[PF_LEN]);
296
* fprintf(stderr, "    start sine        %8.4f    total angle       %8.4f\n",
297
*       fv[PF_INIT_SIN], fv[PF_TH]);
298
* fprintf(stderr, "    b.b. length       %8.4f    total abs. angle  %8.4f\n",
299
*       fv[PF_BB_LEN], fv[PF_ATH]);
300
* fprintf(stderr, "    b.b. angle        %8.4f    total sq. angle   %8.4f\n",
301
*       fv[PF_BB_TH], fv[PF_SQTH]);
302
* fprintf(stderr, "    st-end length     %8.4f    duration          %8.4f\n",
303
*       fv[PF_SE_LEN], fv[PF_DUR]);
304
* fprintf(stderr, "    st-end cos        %8.4f\n", fv[PF_SE_COS]);
305
* fprintf(stderr, "    st-end sin        %8.4f\n", fv[PF_SE_SIN]);
306
*/
307
        ZZ('C') {
308
                scd = sc->classdope[maxclass];
309
                PrintVector(fv, "%10.10s  ", scd->name);
310
                ZZZ('C') {
311
                        for(i = 0; i < sc->nclasses; i++) {
312
                                scd = sc->classdope[i];
313
                                PrintVector(scd->average, "%5.5s %5g ",
314
                                        scd->name, disc[i]);
315
                        }
316
                }
317
        }
318
 
319
        scd = sc->classdope[maxclass];
320
/* ari */
321
/* fprintf(stderr,"%s", scd->name); */
322
/*
323
   fprintf(stderr,"Stroke identified as %s [ ", scd->name);
324
   for (i = 0; i < sc->nclasses; i++) {
325
      if ( (disc[maxclass] - disc[i] < 5.0) && (i != maxclass) )
326
         fprintf(stderr,"%s ", sc->classdope[i]->name);
327
   }
328
   fprintf(stderr,"], ");
329
*/
330
        if(ap) {        /* calculate probability of non-ambiguity */
331
                for(denom = 0, i = 0; i < sc->nclasses; i++)
332
                        /* quick check to avoid computing negligible term */
333
                        if((d = disc[i] - disc[maxclass]) > -7.0)
334
                                denom += exp(d);
335
                *ap = 1.0 / denom;
336
        }
337
 
338
        if(dp)  /* calculate distance to mean of chosen class */
339
                *dp = MahalanobisDistance(fv, scd->average, sc->invavgcov);
340
 
341
        return scd;
342
}
343
 
344
/*
345
 Compute (v-u)' sigma (v-u)
346
 */
347
 
348
double
349
MahalanobisDistance(v, u, sigma)
350
register Vector v, u;
351
register Matrix sigma;
352
{
353
        register int i;
354
        static Vector space;
355
        double result;
356
 
357
        if(space == NULL || NROWS(space) != NROWS(v)) {
358
                if(space) FreeVector(space);
359
                space = NewVector(NROWS(v));
360
        }
361
        for(i = 0; i < NROWS(v); i++)
362
                space[i] = v[i] - u[i];
363
        result =  QuadraticForm(space, sigma);
364
        return result;
365
}
366
 
367
void
368
FixClassifier(sc, avgcov)
369
register sClassifier sc;
370
Matrix avgcov;
371
{
372
        int i;
373
        double det;
374
        BitVector bv;
375
        Matrix m, r;
376
 
377
        /* just add the features one by one, discarding any that cause
378
           the matrix to be non-invertible */
379
 
380
        CLEAR_BIT_VECTOR(bv);
381
        for(i = 0; i < sc->nfeatures; i++) {
382
                BIT_SET(i, bv);
383
                m = SliceMatrix(avgcov, bv, bv);
384
                r = NewMatrix(NROWS(m), NCOLS(m));
385
                det = InvertMatrix(m, r);
386
                if(fabs(det) <= EPS)
387
                        BIT_CLEAR(i, bv);
388
                FreeMatrix(m);
389
                FreeMatrix(r);
390
        }
391
 
392
        m = SliceMatrix(avgcov, bv, bv);
393
        r = NewMatrix(NROWS(m), NCOLS(m));
394
        det = InvertMatrix(m, r);
395
        if(fabs(det) <= EPS) {
396
                error("Can't fix classifier!");
397
                return;
398
            }
399
        DeSliceMatrix(r, 0.0, bv, bv, sc->invavgcov);
400
 
401
        FreeMatrix(m);
402
        FreeMatrix(r);
403
 
404
}
405
 
406
void
407
sDumpClassifier(sc)
408
register sClassifier sc;
409
{
410
        register sClassIndex c;
411
 
412
        printf("\n----Classifier %x, %d features:-----\n", (int)sc, sc->nfeatures);
413
        printf("%d classes: ", sc->nclasses);
414
        for(c = 0; c < sc->nclasses; c++)
415
                printf("%s  ", sc->classdope[c]->name);
416
        printf("Discrimination functions:\n");
417
        for(c = 0; c < sc->nclasses; c++) {
418
                PrintVector(sc->w[c], "%s: %g + ", sc->classdope[c]->name, sc->cnst[c]);
419
                printf("Mean vectors:\n");
420
                PrintVector(sc->classdope[c]->average, "%s: ", sc->classdope[c]->name);
421
            }
422
        if( sc->invavgcov != NULL ) {
423
            PrintMatrix(sc->invavgcov, "Inverse average covariance matrix:\n");
424
        }
425
        printf("\n---------\n\n");
426
}
427
 
428
void
429
sWrite(outfile, sc)
430
FILE *outfile;
431
sClassifier sc;
432
{
433
        int i;
434
        register sClassDope scd;
435
 
436
        fprintf(outfile, "%d classes\n", sc->nclasses);
437
        for(i = 0; i < sc->nclasses; i++) {
438
                scd = sc->classdope[i];
439
                fprintf(outfile, "%s\n", scd->name);
440
        }
441
        for(i = 0; i < sc->nclasses; i++) {
442
                scd = sc->classdope[i];
443
                OutputVector(outfile, scd->average);
444
                OutputMatrix(outfile, scd->sumcov);
445
                OutputVector(outfile, sc->w[i]);
446
        }
447
        OutputVector(outfile, sc->cnst);
448
        OutputMatrix(outfile, sc->invavgcov);
449
}
450
 
451
sClassifier
452
sRead(infile)
453
FILE *infile;
454
{
455
        int i, n;
456
        register sClassifier sc;
457
        register sClassDope scd;
458
        char buf[100];
459
 
460
 
461
        Z('a') printf("Reading classifier \n");
462
        sc = sNewClassifier();
463
        fgets(buf, 100, infile);
464
        if(sscanf(buf, "%d", &n) != 1) {
465
            error("Input error in classifier file");
466
            sFreeClassifier(sc);
467
            return(NULL);
468
        }
469
        Z('a') printf("  %d classes \n", n);
470
        for(i = 0; i < n; i++) {
471
                fscanf(infile, "%s", buf);
472
                scd = sAddClass(sc, buf);
473
                Z('a') printf("  %s \n", scd->name);
474
        }
475
        sc->w = allocate(sc->nclasses, Vector);
476
        for(i = 0; i < sc->nclasses; i++) {
477
                scd = sc->classdope[i];
478
                scd->average = InputVector(infile);
479
                scd->sumcov = InputMatrix(infile);
480
                sc->w[i] = InputVector(infile);
481
        }
482
        sc->cnst = InputVector(infile);
483
        sc->invavgcov = InputMatrix(infile);
484
        Z('a') printf("\n");
485
        return sc;
486
}
487
 
488
 
489
void
490
sDistances(sc, nclosest)
491
register sClassifier sc;
492
{
493
        register Matrix d = NewMatrix(sc->nclasses, sc->nclasses);
494
        register int i, j;
495
        double min, max = 0;
496
        int n, mi, mj;
497
 
498
        printf("-----------\n");
499
        printf("Computing %d closest pairs of classes\n", nclosest);
500
        for(i = 0; i < NROWS(d); i++) {
501
                for(j = i+1; j < NCOLS(d); j++) {
502
                        d[i][j] = MahalanobisDistance(
503
                                                sc->classdope[i]->average,
504
                                                sc->classdope[j]->average,
505
                                                sc->invavgcov);
506
                        if(d[i][j] > max) max = d[i][j];
507
                }
508
        }
509
 
510
        for(n = 1; n <= nclosest; n++) {
511
                min = max;
512
                mi = mj = -1;
513
                for(i = 0; i < NROWS(d); i++) {
514
                        for(j = i+1; j < NCOLS(d); j++) {
515
                                if(d[i][j] < min)
516
                                        min = d[mi=i][mj=j];
517
                        }
518
                }
519
                if(mi == -1)
520
                        break;
521
 
522
                printf("%2d) %10.10s to %10.10s d=%g nstd=%g\n",
523
                        n,
524
                        sc->classdope[mi]->name,
525
                        sc->classdope[mj]->name,
526
                        d[mi][mj],
527
                        sqrt(d[mi][mj]));
528
 
529
                d[mi][mj] = max+1;
530
        }
531
        printf("-----------\n");
532
        FreeMatrix(d);
533
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.