// class is persistable sclass Perceptron implements IPred { srecord Example(double[] inputs, bool answer) { double getInput(int i) { ret i < inputs.length ? inputs[i] : 1; } } L examples = syncList(); double c = 1; bool randomizeC = true, startWithRandomWeights = false; long trainingRound; double error = -1; // -1 = not trained yet double[] weights; *() {} *(L *examples) {} ItIt trainingIterator() { if (empty(examples)) ret emptyItIt(); int n = l(first(examples).inputs)+1; if (weights == null) { weights = new double[n]; if (startWithRandomWeights) for i over weights: weights[i] = random(-1.0, 1.0); } ret iff(() -> { if (error == 0) ret endMarker(); ++trainingRound; double lastError = error; trainARound(); ret error != lastError ? error : null; }); } double trainARound() { double error = 0; int n = l(examples); if (n == 0) ret -1; for (Example e : concIter(examples)) error += abs(trainAnExample(e)); ret this.error = error/n; } int feedForward(double[] inputs) { double sum = last(weights); for i over inputs: sum += inputs[i] * weights[i]; ret activate(sum); } public Bool get(double[] inputs) { ret feedForward(inputs) > 0; } int activate(double s) { return s > 0 ? 1 : -1; } double recalcError() { double error = 0; int n = l(examples); if (n == 0) ret -1; for (Example e : concIter(examples)) error += abs(errorForExample(e)); ret this.error = error/n; } double errorForExample(Example e) { int guess = feedForward(e.inputs); ret (e.answer ? 1 : -1) - guess; } double trainAnExample(Example e) { double error = errorForExample(e); if (error != 0) { double cc = c/l(examples); for i over weights: weights[i] += (randomizeC ? rand(cc) : cc) * error * e.getInput(i); } ret error; } void printWithWeights { print("Error: " + error + ", round " + trainingRound + ", weights: " + sfu(weights)); } // scaling the weights doesn't make a difference // returns true if it worked (error did not increase) bool scaleWeights(double factor) { for i over weights: weights[i] *= factor; double lastError = error; if (recalcError() > lastError) ret false with warn("Error increased from \*lastError*/ to \*error*/ during scale weight with factor \*factor*/"); true; } void addExample(double[] inputs, bool answer) { examples.add(new Example(inputs, answer)); error = -1; } }