Voice recognition: "Yes" or "No"?

33

2

Task

Implement a program in minimum bytes of source or binary code that does voice recognition of a voice sample (me saying "yes", "yeah" or "no" in voice or in whisper, plainly or quirkily) based on training samples with maximum accuracy.

The program should read train/yes0.wav, train/no0.wav, train/yes1.wav and so on (there are 400 yeses and 400 noes in training dataset), then start reading inputs/0.wav, inputs/1.wav until it fails to find the file, analysing it and outputting "yes" or "no" (or other word for intermediate answer).

If you want, you may pre-train the program instead of reading train/, but the resulting data table counts towards the score (and beware of overfitting to training samples - they don't overlap with examination ones). Better to include the program used to produce the data table as an addendum in this case.

All sample files are little endian 16-bit stereo WAV files, just from laptop mic, without filtering/noise reduction.

Limits

Forbidden features:

  • Using network;
  • Trying to reach the answers file inputs/key;
  • Subverting the runner program that calculates accuracy;
  • Using existing recognition libraries. Linking to FFT implementation not allowed: only external math functions taking constant amount of information (like sin or atan2) are allowed; If you want FFT, just add it's implementation to your program source code (it can be multilingual if needed).

Resource limits:

  • The program should not take more than 30 minutes of CPU time on my i5 laptop. If it takes more, only output produced in the first 30 minutes are counted and eveything else is assumed a half-match;
  • Memory limit: 1GB (including any temporary files);

Tools

The tools/runner program automatically runs your solution and calculates the accuracy.

$ tools/runner solutions/example train train/key 
Accuracy: 548 ‰

It can examine the program using training data or using actual exam data. I'm going to try submitted answers on examination dataset and publish results (accuracy percentage) until I make the dataset public.

Scoring

There are 5 classes of solution depending on accuracy:

  • All samples guessed correctly: Class 0;
  • Accuracy 950-999: Class 1;
  • Accuracy 835-950: Class 2;
  • Accuracy 720-834: Class 3;
  • Accuracy 615-719: Class 4;

Inside each class, the score is number of bytes the solution takes.

Accepted answer: smallest solution in the best nonempty class.

Links

All samples should be considered CC-0 (Public Domain), scripts and programs should be considered MIT.

Example solution

It provides very poor quality of recognition, just shows how to read files and output answers

#define _BSD_SOURCE
#include <stdio.h>
#include <assert.h>
#include <endian.h>


#define Nvols 30

#define BASS_WINDOW 60
#define MID_WINDOW 4

struct training_info {
    double bass_volumes[Nvols];
    double mid_volumes[Nvols];
    double treble_volumes[Nvols];
    int n;
};


struct training_info yes;
struct training_info no;

static int __attribute__((const)) mod(int n, int d) {
    int m = n % d;
    if (m < 0) m+=d;
    return m;
}

// harccoded to 2 channel s16le
int get_file_info(const char* name, struct training_info *inf) {
    FILE* in = fopen(name, "rb");

    if (!in) return -1;

    setvbuf(in, NULL, _IOFBF, 65536);

    inf->n = 1;

    fseek(in, 0, SEEK_END);
    long filesize = ftell(in);
    fseek(in, 128, SEEK_SET);
    filesize -= 128; // exclude header and some initial samples

    int nsamples = filesize / 4; 

    double bass_a=0, mid_a=0;
    const int HISTSIZE  = 101;
    double xhistory[HISTSIZE];
    int histpointer=0;
    int histsize = 0;

    //FILE* out = fopen("debug.raw", "wb");

    int i;
    for (i=0; i<Nvols; ++i) {
        int j;

        double total_vol = 0;
        double bass_vol = 0;
        double mid_vol = 0;
        double treble_vol = 0;

        for (j=0; j<nsamples / Nvols; ++j) {
            signed short int l, r; // a sample
            if(fread(&l, 2, 1, in)!=1) break;
            if(fread(&r, 2, 1, in)!=1) break;
            double x = 1/65536.0 * ( le16toh(l) + le16toh(r) );


            bass_a += x;
            mid_a  += x;


            if (histsize == HISTSIZE-1) bass_a   -= xhistory[mod(histpointer-BASS_WINDOW,HISTSIZE)];
            if (histsize == HISTSIZE-1) mid_a    -= xhistory[mod(histpointer-MID_WINDOW ,HISTSIZE)];

            double bass = bass_a / BASS_WINDOW;
            double mid = mid_a / MID_WINDOW - bass;
            double treble = x - mid_a/MID_WINDOW;

            xhistory[histpointer++] = x;
            if(histpointer>=HISTSIZE) histpointer=0;
            if(histsize < HISTSIZE-1) ++histsize;

            total_vol  += bass*bass + mid*mid + treble*treble;
            bass_vol   += bass*bass;
            mid_vol    += mid*mid;
            treble_vol += treble*treble;


            /*
            signed short int y;
            y = 65536 * bass;

            y = htole16(y);
            fwrite(&y, 2, 1, out);
            fwrite(&y, 2, 1, out);
            */
        }

        inf->bass_volumes[i] = bass_vol / total_vol;
        inf->mid_volumes[i] = mid_vol / total_vol;
        inf->treble_volumes[i] = treble_vol / total_vol;

        //fprintf(stderr, "%lf %lf %lf    %s\n", inf->bass_volumes[i], inf->mid_volumes[i], inf->treble_volumes[i], name);
    }
    fclose(in);

    return 0;
}

static void zerotrdata(struct training_info *inf) {
    int i;
    inf->n = 0;
    for (i=0; i<Nvols; ++i) {
        inf->bass_volumes[i] = 0;
        inf->mid_volumes[i] = 0;
        inf->treble_volumes[i] = 0;
    }
}

static void train1(const char* prefix, struct training_info *inf) 
{
    char buf[50];

    int i;

    for(i=0;; ++i) {
        sprintf(buf, "%s%d.wav", prefix, i);
        struct training_info ti;
        if(get_file_info(buf, &ti)) break;

        ++inf->n;

        int j;
        for (j=0; j<Nvols; ++j) {
            inf->bass_volumes[j]   += ti.bass_volumes[j];
            inf->mid_volumes[j]    += ti.mid_volumes[j];
            inf->treble_volumes[j] += ti.treble_volumes[j];
        }
    }

    int j;
    for (j=0; j<Nvols; ++j) {
        inf->bass_volumes[j]   /= inf->n;
        inf->mid_volumes[j]    /= inf->n;
        inf->treble_volumes[j] /= inf->n;
    }
}

static void print_part(struct training_info *inf, FILE* f) {
    fprintf(f, "%d\n", inf->n);
    int j;
    for (j=0; j<Nvols; ++j) {
        fprintf(f, "%lf %lf %lf\n", inf->bass_volumes[j], inf->mid_volumes[j], inf->treble_volumes[j]);
    }
}

static void train() {
    zerotrdata(&yes);
    zerotrdata(&no);

    fprintf(stderr, "Training...\n");

    train1("train/yes", &yes);
    train1("train/no", &no);

    fprintf(stderr, "Training completed.\n");

    //print_part(&yes, stderr);
    //print_part(&no, stderr);

    int j;
    for (j=0; j<Nvols; ++j) {
        if (yes.bass_volumes[j]   > no.bass_volumes[j]) {   yes.bass_volumes[j] = 1;   no.bass_volumes[j] = 0; }
        if (yes.mid_volumes[j]    > no.mid_volumes[j]) {    yes.mid_volumes[j] = 1;    no.mid_volumes[j] = 0; }
        if (yes.treble_volumes[j] > no.treble_volumes[j]) { yes.treble_volumes[j] = 1; no.treble_volumes[j] = 0; }
    }
}


double delta(struct training_info *t1, struct training_info *t2) {
    int j;
    double d = 0;
    for (j=0; j<Nvols; ++j) {
        double rb = t1->bass_volumes[j] - t2->bass_volumes[j];
        double rm = t1->mid_volumes[j] - t2->mid_volumes[j];
        double rt = t1->treble_volumes[j] - t2->treble_volumes[j];
        d += rb*rb + rm*rm + rt*rt;
    }
    return d;
}

int main(int argc, char* argv[])
{
    (void)argc; (void)argv;

    train();


    int i;

    int yes_count = 0;
    int no_count = 0;

    for (i=0;; ++i) {
        char buf[60];
        sprintf(buf, "inputs/%d.wav", i);

        struct training_info ti;

        if(get_file_info(buf, &ti)) break;

        double dyes = delta(&yes, &ti);
        double dno = delta(&no, &ti);

        //printf("%lf %lf %s ", dyes, dno, buf);

        if (dyes > dno) {
            printf("no\n");
            ++no_count;
        } else  {
            printf("yes\n");
            ++yes_count;
        }
    }

    fprintf(stderr, "yeses: %d noes: %d\n", yes_count, no_count);

}

Vi.

Posted 2014-09-01T09:54:02.270

Reputation: 2 644

Are the test files will be taken out of the training files, or separate samples altogether? – John Dvorak – 2014-09-01T11:59:18.227

5no fft libraries? Why? – John Dvorak – 2014-09-01T12:02:46.070

Can we use WAV libraries (such as Python's wave)? – mnbvmar – 2014-09-01T12:11:55.343

@mnbvmar, Yes. – Vi. – 2014-09-01T12:13:28.427

1What about built-in FFT functions? What exactly counts as external? Also, what counts as a math library function? Are we allowed to use sum, or we need to use foldl (+) 0 (foldl not being math-specific, and + not being variadic)? – John Dvorak – 2014-09-01T12:14:03.890

@JanDvorak, Separate samples, but from the same larger dataset. Samples were shuffled, first 400 of each kind were marked as training, the rest are examination. – Vi. – 2014-09-01T12:14:35.370

Why is it a half-match if your program ran out of time? Why not a complete miss? – Claudiu – 2014-09-01T12:15:03.117

@Claudiu just assume the program starts guessing rapid-fire in desperation – John Dvorak – 2014-09-01T12:15:34.257

@JanDvorak, You can insert some FFT implementation into your code and optionally golf it down. If allow FFT, then somebody may ask to allow some other transformation, and it would be tricky to put a line between "Just FFT" and "Ready-made recognition library". So the rule "external math libraries should only provide constant input size functions". – Vi. – 2014-09-01T12:15:59.810

@JanDvorak, fold is not a math funciton. (+) takes constant-sized input, so is allowed. – Vi. – 2014-09-01T12:17:10.357

1still... you're effectively forbidding sum. I guess that's not your intention? – John Dvorak – 2014-09-01T12:17:22.760

1What's the exact definition of math functions? Those that are specialised to operate on numbers? What about a generic "sum" function that uses addition for numbers, but concatenation for strings? Is this sum now allowed? – John Dvorak – 2014-09-01T12:18:58.997

You can easily implement sum using other functions. "sum" allowed => "sum with coefficients" allowed => "sub with coefficients + filtering at the end" allowed => ... => neuron implementation allowed => ... – Vi. – 2014-09-01T12:19:06.120

@JanDvorak, Yes, functions for processing numbers, unrelated to input/output. – Vi. – 2014-09-01T12:20:47.240

1What about J's vector operations? Are they disallowed? – John Dvorak – 2014-09-01T12:20:48.547

@JanDvorak, (Looking up what is J's vector... Can't find it easily). If it's a speedy processing of a fixed block of data (i.e. 32 floats array), it looks more or less OK. – Vi. – 2014-09-01T12:21:11.430

1Operations in J, K and other APL derivatives have an implicit rank (dimension they operate on). If you apply them to a data structure with a larger dimension, they perform an implicit iteration. + can mean (+), zipWith (+), zipWith $ zipWith (+)... – John Dvorak – 2014-09-01T12:22:56.763

@JanDvorak, Consider that this "implicit iteration" is not a part of mathematical function, just a special zero-byte-consuming part of your program. The inner function being iterated takes const-sized input. – Vi. – 2014-09-01T12:25:17.200

zipWith is not a mathematical function, it's list-processing function. And (+) is OK. If there were a library cozysum = zipWith (+), then this library whould be forbidden (because of both zipWith and (+) is outsourced to the library). – Vi. – 2014-09-01T12:25:47.603

I guess that stuff like J's +/ (plus-over = fold with addition = sum) and *\ (times-table = table of multiplications) are fine, then? / and \ are separate entities (adverbs = functions on functions). – John Dvorak – 2014-09-01T12:29:36.650

@JanDvorak, "/ and \ are separate entities" -> So it's OK. In general, the rule is to forbid big simplification like ready-made FFT, ready-made OCR, ready-made noise reduction, not some "elementary " language iteration features. Just a sum probably would not be that noticable (and such minor "violations" are probably easy fixable if needed). – Vi. – 2014-09-01T12:31:21.277

How does a polymorphic sum (fold an arbitrary list with the + operator, whatever it does) fare? – John Dvorak – 2014-09-01T12:34:58.420

This polymorphic sum can be viewed as a fold by other name (hence a control function, not math one), unless the overridden + can take an array of numbers or something like that. Even if + processes arrays, if implementation of such + is in your code then it's OK. If not, it can be not OK. You can post both "common sense" and "100% compliant" solutions if you want. A real problem is when they diverge too much. – Vi. – 2014-09-01T12:38:11.347

@JanDvorak, BTW how do I run an APL program on my Linux Debian? It's not feasible to use some online runner because of there is a big blob of input data. – Vi. – 2014-09-01T12:40:15.457

I've never used APL, but I've used J. IIRC, there is a J runtime for linux. – John Dvorak – 2014-09-01T12:41:39.800

Can you train the program prior to submitting, then remove all training code? – Nic Robertson – 2014-09-01T22:26:04.390

@NicRobertson, Yes. But it's better include the training part as an addendum. – Vi. – 2014-09-02T00:20:28.157

Does all training set/examination set have the same sample rate? ie. 2 channels, 16 bits per sample , 44.1 khz sample rate. – Nic Robertson – 2014-09-02T03:51:27.823

@NicRobertson, All audio files (training and examination samples) have the same format (the one you mentioned), the one of arecord -f cd > file.wav. Training samples are just random subset taken off from examination samples. – Vi. – 2014-09-02T10:14:45.920

Answers

27

C++11 (gcc; 1639 1625 1635 bytes, Class 1, score=983, 960)

Let's get it started. It's probably the longest code I've ever shortened...

#include <bits/stdc++.h>
#define $ complex<double>
#define C vector<$>
#define I int
#define D double
#define P pair<D,I>
#define Q pair<D,D>
#define E vector<D>
#define V vector<P>
#define W vector<Q>
#define S char*
#define Z(x)if(fread(&x,2,1,y)!=1)break;
#define B push_back
#define F(i,f,t)for(I i=f;i<t;i++)
#define _ return
#define J first
#define L second
const I K=75,O=16384;using namespace std;C R(C&i,I s,I o=0,I d=1){if(!s)_ C(1,i[o]);C l=R(i,s/2,o,d*2),h=R(i,s/2,o+d,d*2);C r(s*2);$ b=exp($(0,-M_PI/s)),f=1;F(k,0,s){r[k]=l[k]+f*h[k];r[k+s]=l[k]-f*h[k];f*=b;}_ r;}C T(C&i){_ R(i,i.size()/2);}char b[O];E U(S m){FILE*y;if(!(y=fopen(m,"r")))_ E();setvbuf(y,b,0,O);fseek(y,0,2);I z=ftell(y)/4-32;fseek(y,128,0);C p;F(i,0,z){short l,r;Z(l);Z(r);if(i&1)p.B($(0.5/O*le16toh(l),0));}p.resize(O);E h(O),n(O);p=T(p);F(j,0,O)h[j]=norm(p[j])/O;F(i,1,O-1)n[i]=(h[i-1]+h[i+1]+h[i]*8)/10;fclose(y);_ n;}W G(E&d){V p;F(i,3,O/2-3)if(d[i]==*max_element(d.begin()+i-3,d.begin()+i+4))p.B({d[i],i});sort(p.begin(),p.end(),greater<P>());W r;F(i,3,K+3)r.B({D(p[i].L)/O*22050,log(p[i].J)+10});D s=0;F(i,0,K)s+=r[i].L;F(i,0,K)r[i].L/=s;_ r;}char m[O];I X(S p,W&r){E t(O),h(t);I f=0;while(1){sprintf(m,"%s%d.wav",p,f++);h=U(m);if(!h.size())break;F(j,0,O)t[j]+=h[j];}F(j,0,O)t[j]/=f;r=G(t);}D Y(W&a,W&b){D r=0;F(i,0,K){D d=b[i].L;F(j,0,K)if(abs((b[i].J-a[j].J)/b[i].J)<0.015)d=min(d,abs(b[i].L-a[j].L));r+=d;}_ r;}I H(S p,W&y,W&n){I f=0;while(1){sprintf(m,"%s%d.wav",p,f++);E h=U(m);if(!h.size())break;W p=G(h);D q=Y(p,y),r=Y(p,n);printf(abs(q-r)<=0.01?"?\n":q<r?"yes\n":"no\n");}}I main(){W y,n;X("train/yes",y);X("train/no",n);H("inputs/",y,n);}

"Ungolfed" (although it's hard to call an over 1.5K source code golfed):

#include <iostream>
#include <stdio.h>
#include <string>
#include <algorithm>
#include <vector>
#include <math.h>
#include <complex>
#include <endian.h>
#include <functional>

using namespace std;

typedef complex<double> CD;

vector<CD> run_fft(vector<CD>& input, int offset, int size, int dist){
    if(size == 1){
        return vector<CD>(1, input[offset]);
    }
    vector<CD> partLow = run_fft(input, offset, size/2, dist*2),
               partHi  = run_fft(input, offset+dist, size/2, dist*2);

    vector<CD> result(size);
    CD factorBase = exp(CD(0, (inv?2:-2)*M_PI/size)), factor = 1;

    for(int k = 0; k < size/2; k++){
        result[k] = partLow[k] + factor*partHi[k];
        result[k+size/2] = partLow[k] - factor*partHi[k];
        factor *= factorBase;
    }
    return result;
}

vector<CD> fft(vector<CD>& input){
    int N = input.size();
    return run_fft(input, 0, N, 1);
}



const int MAX_BUF = 65536;
const int PWR_TWO = 16384;
const int NUM_CHECK = 75;
int sampling;

char buf[MAX_BUF];
vector<double> read_data(char* filenam){
    FILE* fp = fopen(filenam, "r");
    if(!fp)
        return vector<double>();
    setvbuf(fp, buf, _IOFBF, MAX_BUF);

    fseek(fp, 0, SEEK_END);
    int filesiz = ftell(fp);
    fseek(fp, 128, SEEK_SET);
    filesiz -= 128;

    int insamp = filesiz / 4;
    int freqsamp = 2,
        act_mod = 0;
    sampling = 44100 / freqsamp;
    int inputSize;

    vector<CD> input;

    for(int i = 0; i < insamp; i++){
        signed short int l, r;
        if(fread(&l, 2, 1, fp) != 1) break;
        if(fread(&r, 2, 1, fp) != 1) break;

        double act = 1/32768.0 * (le16toh(l));

        if((++act_mod) == freqsamp){
            inputSize++;
            input.push_back(CD(act,0));
            act_mod = 0;
        }
    }
    inputSize = input.size();

    //printf("%s\n", filenam);
    int numParts = (inputSize+PWR_TWO-1)/PWR_TWO;
    double partDelta = (double)inputSize / numParts, actDelta = 0;
    vector<CD> ndata(PWR_TWO);
    for(int i = 0; i < numParts; i++){
        vector<CD> partInput(PWR_TWO);
        int from = floor(actDelta),
            to = floor(actDelta)+PWR_TWO;

        for(int j = from; j < to; j++)
            partInput[j-from] = input[j];

        vector<CD> partData = fft(partInput);
        for(int j = 0; j < PWR_TWO; j++)
            ndata[j] += partData[j]*(1.0/numParts);
    }


    vector<double> height(PWR_TWO);
    for(int i = 0; i < PWR_TWO; i++)
        height[i] = norm(ndata[i])/PWR_TWO;

    vector<double> nheight(height);
    nheight[0] = (height[0]*0.8 + height[1]*0.1)/0.9;
    nheight[PWR_TWO-1] = (height[PWR_TWO]*0.8 + height[PWR_TWO-1]*0.1)/0.9;
    for(int i = 1; i < PWR_TWO-1; i++)
        nheight[i] = height[i-1]*0.1 + height[i]*0.8 + height[i+1]*0.1;

    fclose(fp);

    return nheight;
}


vector< pair<double,double> > get_highest_peaks(vector<double>& freqData){
    vector< pair<double,int> > peaks;

    for(int i = 3; i < PWR_TWO/2-3; i++){
        if(freqData[i] == *max_element(freqData.begin()+i-3, freqData.begin()+i+4)){
            peaks.push_back(make_pair(freqData[i], i));
        }
    }

    sort(peaks.begin(), peaks.end(), greater< pair<double,int> >());

    vector< pair<double,double> > res;
    for(int i = 3; i < NUM_CHECK+3; i++){
        res.push_back(make_pair((double)(peaks[i].second)/PWR_TWO*sampling, log(peaks[i].first)+10));
    }

    double sum_res = 0;
    for(int i = 0; i < NUM_CHECK; i++)
        sum_res += res[i].second;
    for(int i = 0; i < NUM_CHECK; i++)
        res[i].second /= sum_res;

    /*for(int i = 0; i < NUM_CHECK; i++)
        printf("%12lf %12lf\n", res[i].first, res[i].second);
    printf("\n");*/

    return res;
}


void train(char* dir, const char* type, vector< pair<double,double> >& res){
    vector<double> result(PWR_TWO), height(PWR_TWO);

    int numFile = 0;
    while(true){
        char filenam[256];
        snprintf(filenam, 255, "%s/%s%d.wav", dir, type, numFile);
        height = read_data(filenam);

        if(height.size() == 0)
            break;

        for(int j = 0; j < PWR_TWO; j++)
            result[j] += height[j];

        numFile++;
    }
    fprintf(stderr, "trained %s on %d files\n", type, numFile);

    for(int j = 0; j < PWR_TWO; j++)
        result[j] /= numFile;

    res = get_highest_peaks(result);
}


double dist_ab(vector< pair<double,double> >& A, vector< pair<double,double> >& B){
    double result = 0;
    for(int i = 0; i < NUM_CHECK; i++){
        double add = B[i].second;

        for(int j = 0; j < NUM_CHECK; j++){
            double dist = (B[i].first-A[j].first)/B[i].first;
            if(abs(dist) < 0.015)
                add = min(add, abs(B[i].second - A[j].second));
        }
        result += add;
    }
    return result;
}


void trial(char* dir, const char* pref, vector< pair<double,double> >& yes,
                                        vector< pair<double,double> >& no){
    int numFile = 0;
    int numYes = 0, numDunno = 0, numNo = 0;
    while(true){
        char filenam[256];
        snprintf(filenam, 255, "%s/%s%d.wav", dir, pref, numFile);

        vector<double> height = read_data(filenam);
        if(height.size() == 0)
            break;

        vector< pair<double,double> > peaks = get_highest_peaks(height);


        double distYes = dist_ab(peaks, yes),
               distNo = dist_ab(peaks, no);

        if(abs(distYes-distNo) <= 0.01){
            printf("dunno\n");
            numDunno++;
        } else if(distYes < distNo){
            printf("yes\n");
            numYes++;
        } else {
            printf("no\n");
            numNo++;
        }
        //printf(" (%lf %lf)\n", distYes, distNo);

        numFile++;
    }
}


int main(int argc, char** argv){
    vector< pair<double,double> > yes, no;


    train("train", "yes", yes);
    train("train", "no", no);

    trial("inputs", "", yes, no);
}

I have no freaking idea if it will work correctly on real data set (I bet it won't, but I must have a try).

How it works:

  1. Take N=214 samples from left channel, each in equal time span. Normalize them so that min value=0 and max value=1.
  2. Process them using FFT. Now we switched from time domain to frequency domain. We might say that 0th cell of resulting array is 0Hz equivalent and 213-1st cell is 22050Hz equivalent (that is because I took every other sample from L channel, so my sampling is 22050Hz instead of WAV's frequency, 44100Hz).
  3. Find the mean of all such signals - call it "mean frequency distribution". Find K highest peaks in such distribution (here K=75), omitting first few (probably noise) and find their strength. I used log(mean distribution)+10 and then normalized so that the sum of the biggest peaks was 1.
  4. We have two "peak distributions" - one for Yes, second for No. If we have a WAV to test, we transform it in the same way as before (steps 1, 2, 3) and get distribution D. Then we have to check which distribution (Y/N) D is more similar to. I used the following approach: for each peak in Y/N, try to find it in D. If we find it (approximately), the score for this peak is absolute difference between Y/N's and D's strength; in opposite case, it's Y/N's strength (we assume it's always positive). Better (smaller) score wins. If the results are very close (I used 0.01 absolute difference), output dunno.

As I said, probably on final tests it will be classified as "even worse than random". Of course, I hope it won't :D

Edit: fixed bug (forgot to close the files).

mnbvmar

Posted 2014-09-01T09:54:02.270

Reputation: 1 146

Wouldn't typedef be better than #define, at least for some types? – Mega Man – 2016-08-01T08:56:18.407

1You are in luck if it performs worse than random. You literally only need to change one byte - distYes > distNo, and it will do better than random. Or to put it another way, it would be quite astonishing if you could guess the outcome of a coin flip incorrectly 100 times in a row! And it's not unheard of that simple algorithms out-perform than more complex ones, so +1 and I wish you good luck. – blutorange – 2014-09-02T16:06:27.797

Testing... It terminates prematurely due to EMFILE (Too many open files)... Trying to fix... – Vi. – 2014-09-02T16:39:18.313

Bumped maximum open file counter, now it works. Results: training dataset: Accuracy: 983 ‰; Time: 0m27.570s;; examination dataset: Accuracy: 960 ‰; Time: 0m32.957s. Good job. – Vi. – 2014-09-02T16:44:56.493

Okay, I fixed this. 10 bytes more. :) – mnbvmar – 2014-09-02T17:56:06.910

Incredible use of #defines :P – qwr – 2014-09-06T22:49:37.513