OK, turing.

<- leave blank

Fri Oct 12 16:38:25 EDT 2018

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdarg.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(Neuron*);
	double (*gradient)(Neuron*);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

double activation_sigmoid(Neuron*);
double gradient_sigmoid(Neuron*);
Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(Neuron*), double(*)(Neuron*));
Neuron *neuroninit(Neuron*, double (*)(Neuron*), double (*)(Neuron*), double);
Neuron *neuroncreate(double (*)(Neuron*), double (*)(Neuron*), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdouble(Weights*, double);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(Neuron *in)
{
	return 1.0/(1.0+exp(-in->sum));
}

double
gradient_sigmoid(Neuron *in)
{
	double y = in->value;
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(Neuron*), double (*gradient)(Neuron*),
double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 1.0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(Neuron*), double (*gradient)(Neuron*), double
steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(Neuron*),
double(*gradient)(Neuron*))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons+1, sizeof(Neuron*));
	for (i = 0; i <= ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = (((double)rand()/RAND_MAX) - 0.5) *
			4.0;

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs+1, sizeof(double*));
	for (i = 0; i <= inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));
	Neuron *O;

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			O = ann->layers[l]->neurons[o];
			O->sum =
			ann->weights[l-1]->values[ann->weights[l-1]->inputs][o];
			// bias
			for (i = 0; i < ann->layers[l-1]->n; i++)
				O->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			O->value = O->activation(O);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *error = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double acc, sum;
	int o, i, w, n;
	Neuron *O, *I;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		// error = outputs[o] - result
		error[o] -= outputs[o];
		error[o] = -error[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);
	for (i = 0; i < (ann->n-2); i++) {
		D = ann->deltas[i];
		weightsinitdouble(D, 1.0);
	}

	// backpropagate MSE
	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O) * O->steepness;
			sum = 1.0;
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
			}
			for (i = 0; i <= ann->layers[w]->n; i++) {
				D->values[i][o] *= acc * sum;
			}
		}

		D2 = D;
	}

	// update weights
	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i <= W->inputs; i++) {
			I = ann->layers[w]->neurons[i];
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate * I->value;
			}
		}
	}

	free(error);
}

int
main()
{
	int i, j, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);
		}

		counter++;
		error = 0;

		for (j = 0; j < 4; j++) {
			results = annrun(test, inputs[j]);
			error += pow(results[0] - outputs[j], 2.0);
			free(results);
		}
		printf("error: %f\n", error);
	}
	printf("error: %f, done after %d epochs\n", error, counter);
}


Fri Oct 12 16:21:41 EDT 2018
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdarg.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(Neuron*);
	double (*gradient)(Neuron*);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

double activation_sigmoid(Neuron*);
double gradient_sigmoid(Neuron*);
Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(Neuron*), double(*)(Neuron*));
Neuron *neuroninit(Neuron*, double (*)(Neuron*), double (*)(Neuron*), double);
Neuron *neuroncreate(double (*)(Neuron*), double (*)(Neuron*), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdouble(Weights*, double);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(Neuron *in)
{
	return 1.0/(1.0+exp(-in->sum));
}

double
gradient_sigmoid(Neuron *in)
{
	double y = in->value;
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(Neuron*), double (*gradient)(Neuron*),
double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 1.0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(Neuron*), double (*gradient)(Neuron*), double
steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(Neuron*),
double(*gradient)(Neuron*))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons+1, sizeof(Neuron*));
	for (i = 0; i <= ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = (double)rand()/RAND_MAX;

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs+1, sizeof(double*));
	for (i = 0; i <= inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));
	Neuron *O;

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			O = ann->layers[l]->neurons[o];
			O->sum =
			ann->weights[l-1]->values[ann->weights[l-1]->inputs][o];
			// bias
			for (i = 0; i < ann->layers[l-1]->n; i++)
				O->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			O->value = O->activation(O);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *error = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double acc, sum;
	int o, i, w, n;
	Neuron *O, *I;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		// error = outputs[o] - result
		error[o] -= outputs[o];
		error[o] = -error[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);
	for (i = 0; i < (ann->n-2); i++) {
		D = ann->deltas[i];
		weightsinitdouble(D, 1.0);
	}

	// backpropagate MSE
	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O) * O->steepness;
			sum = 1.0;
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
			}
			for (i = 0; i <= ann->layers[w]->n; i++) {
				D->values[i][o] *= acc * sum;
			}
		}

		D2 = D;
	}

	// update weights
	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i <= W->inputs; i++) {
			I = ann->layers[w]->neurons[i];
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate * I->value;
			}
		}
	}

	free(error);
}

int
main()
{
	int i, j, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);

			if (counter++ % 4 == 0) {
				error = 0;

				for (j = 0; j < 4; j++) {
					results = annrun(test, inputs[i]);
					error += pow(results[0] - outputs[i],
					2.0);
					free(results);
				}
				printf("error: %f\n", error);
			}
		}
	}
	printf("error: %f, done after %d epochs\n", error, counter);
}


Fri Oct 12 16:02:24 EDT 2018
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdarg.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(Neuron*);
	double (*gradient)(Neuron*);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

double activation_sigmoid(Neuron*);
double gradient_sigmoid(Neuron*);
Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(Neuron*), double(*)(Neuron*));
Neuron *neuroninit(Neuron*, double (*)(Neuron*), double (*)(Neuron*), double);
Neuron *neuroncreate(double (*)(Neuron*), double (*)(Neuron*), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdouble(Weights*, double);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(Neuron *in)
{
	return 1.0/(1.0+exp(-in->sum));
}

double
gradient_sigmoid(Neuron *in)
{
	double y = in->value;
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(Neuron*), double (*gradient)(Neuron*),
double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 1.0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(Neuron*), double (*gradient)(Neuron*), double
steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(Neuron*),
double(*gradient)(Neuron*))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons+1, sizeof(Neuron*));
	for (i = 0; i <= ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = (double)rand()/RAND_MAX;

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs+1, sizeof(double*));
	for (i = 0; i <= inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));
	Neuron *O;

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			O = ann->layers[l]->neurons[o];
			O->sum =
			ann->weights[l-1]->values[ann->weights[l-1]->inputs][o];
			// bias
			for (i = 0; i < ann->layers[l-1]->n; i++)
				O->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			O->value = O->activation(O);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *error = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double acc, sum;
	int o, i, w, n;
	Neuron *O, *I;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		// error = outputs[o] - result
		error[o] -= outputs[o];
		error[o] = -error[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	// backpropagate MSE
	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O) * O->steepness;
			sum = 1.0;
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
			}
			for (i = 0; i <= ann->layers[w]->n; i++) {
				D->values[i][o] *= acc * sum;
			}
		}

		D2 = D;
	}

	// update weights
	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i <= W->inputs; i++) {
			I = ann->layers[w]->neurons[i];
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate * I->value;
			}
		}
	}

	free(error);
}

int
main()
{
	int i, j, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);

			if (counter++ % 4 == 0) {
				error = 0;

				for (j = 0; j < 4; j++) {
					results = annrun(test, inputs[i]);
					error += pow(results[0] - outputs[i],
					2.0);
					free(results);
				}
				printf("error: %f\n", error);
			}
		}
	}
	printf("error: %f, done after %d epochs\n", error, counter);
}


Fri Oct 12 15:51:16 EDT 2018
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdarg.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(Neuron*);
	double (*gradient)(Neuron*);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

double activation_sigmoid(Neuron*);
double gradient_sigmoid(Neuron*);
Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(Neuron*), double(*)(Neuron*));
Neuron *neuroninit(Neuron*, double (*)(Neuron*), double (*)(Neuron*), double);
Neuron *neuroncreate(double (*)(Neuron*), double (*)(Neuron*), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdouble(Weights*, double);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(Neuron *in)
{
	return 1.0/(1.0+exp(-in->sum));
}

double
gradient_sigmoid(Neuron *in)
{
	double y = in->value;
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(Neuron*), double (*gradient)(Neuron*),
double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 1.0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(Neuron*), double (*gradient)(Neuron*), double
steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(Neuron*),
double(*gradient)(Neuron*))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons+1, sizeof(Neuron*));
	for (i = 0; i <= ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = (double)rand()/RAND_MAX;

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs+1, sizeof(double*));
	for (i = 0; i <= inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));
	Neuron *O;

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			O = ann->layers[l]->neurons[o];
			O->sum =
			ann->weights[l-1]->values[ann->weights[l-1]->inputs][o];
			// bias
			for (i = 0; i < ann->layers[l-1]->n; i++)
				O->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			O->value = O->activation(O);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *error = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double acc, sum;
	int o, i, w, n;
	Neuron *O, *I;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		// error = outputs[o] - result
		error[o] -= outputs[o];
		error[o] = -error[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	// backpropagate MSE
	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O) * O->steepness;
			sum = 1.0;
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
			}
			for (i = 0; i <= ann->layers[w]->n; i++) {
				D->values[i][o] *= acc * sum;
			}
		}

		D2 = D;
	}

	// update weights
	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i <= W->inputs; i++) {
			I = ann->layers[w]->neurons[i];
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate * I->value;
			}
		}
	}

	free(error);
}

int
main()
{
	int i, j, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.0001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);

			if (counter++ % 4 == 0) {
				error = 0;

				for (j = 0; j < 4; j++) {
					results = annrun(test, inputs[i]);
					error += pow(results[0] - outputs[i],
					2.0);
					free(results);
				}
				printf("error: %f\n", error);
			}
		}
	}
	printf("error: %f, done\n", error);
}


Fri Oct 12 14:04:41 EDT 2018
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <stdarg.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(double input);
	double (*gradient)(double input);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

double activation_sigmoid(double);
double gradient_sigmoid(double);
Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(double), double(*)(double));
Neuron *neuroninit(Neuron*, double (*)(double), double (*)(double), double);
Neuron *neuroncreate(double (*)(double), double (*)(double), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdouble(Weights*, double);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(double x)
{
	return 1.0/(1.0+exp(-x));
}

double
gradient_sigmoid(double x)
{
	double y = activation_sigmoid(x);
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(double input), double
(*gradient)(double input), double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 1.0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(double input), double (*gradient)(double input),
double steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(double),
double(*gradient)(double))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons+1, sizeof(Neuron*));
	for (i = 0; i <= ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = (double)rand()/RAND_MAX;

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs+1, sizeof(double*));
	for (i = 0; i <= inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i <= in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));
	Neuron *O;

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			O = ann->layers[l]->neurons[o];
			O->sum =
			ann->weights[l-1]->values[ann->weights[l-1]->inputs][o];
			// bias
			for (i = 0; i < ann->layers[l-1]->n; i++)
				O->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			O->value = O->activation(O->sum);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *error = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double acc, sum;
	int o, i, w, n;
	Neuron *O, *I;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		// error = outputs[o] - result
		error[o] -= outputs[o];
		error[o] = -error[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	// backpropagate MSE
	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O->sum) * O->steepness;
			sum = 1.0;
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
			}
			for (i = 0; i <= ann->layers[w]->n; i++) {
				D->values[i][o] *= acc * sum;
			}
		}

		D2 = D;
	}

	// update weights
	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i <= W->inputs; i++) {
			I = ann->layers[w]->neurons[i];
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate * I->value;
			}
		}
	}

	free(error);
}

int
main()
{
	int i, j, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.0001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);

			if (counter++ % 4 == 0) {
				error = 0;

				for (j = 0; j < 4; j++) {
					results = annrun(test, inputs[i]);
					error += pow(results[0] - outputs[i],
					2.0);
					free(results);
				}
				printf("error: %f\n", error);
			}
		}
	}
	printf("error: %f, done\n", error);
}


Fri Oct 12 06:07:35 EDT 2018
Hi,

My name is Randy and I was looking at a few different sites online and came across
your site okturing.com.  I must say - your website is very impressive.  I found
your website on the first page of the Search Engine.

Have you noticed that 70 percent of visitors who leave your website will never
return?  In most cases, this means that 95 percent to 98 percent of your marketing
efforts are going to waste, not to mention that you are losing more money in
customer acquisition costs than you need to.

As a business person, the time and money you put into your marketing efforts is
extremely valuable.  So why let it go to waste?  Our users have seen staggering
improvements in conversions with insane growths of 150 percent going upwards of
785 percent.  Are you ready to unlock the highest conversion revenue from each of
your website visitors?

TalkWithLead is a widget which captures a website visitor’s Name, Email address
and Phone Number and then calls you immediately, so that you can talk to the Lead
exactly when they are live on your website — while they're hot!  Best feature of
all, we offer FREE International Long Distance Calling!

Try the TalkWithLead Live Demo now to see exactly how it works.  Visit:
https://www.talkwithlead.com/Contents/LiveDemo.aspx

When targeting leads, speed is essential - there is a 100x decrease in Leads when
a Lead is contacted within 30 minutes vs being contacted within 5 minutes.

If you would like to talk to me about this service, please give me a call.  We do
offer a 14 days free trial.

Thanks and Best Regards,
Randy

Fri Oct 12 05:47:46 EDT 2018
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <time.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(double input);
	double (*gradient)(double input);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(double), double(*)(double));
Neuron *neuroninit(Neuron*, double (*)(double), double (*)(double), double);
Neuron *neuroncreate(double (*)(double), double (*)(double), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(double x)
{
	return 1.0/(1.0+exp(-x));
}

double
gradient_sigmoid(double x)
{
	double y = activation_sigmoid(x);
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(double input), double
(*gradient)(double input), double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(double input), double (*gradient)(double input),
double steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(double),
double(*gradient)(double))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons, sizeof(Neuron*));
	for (i = 0; i < ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = ((double)rand()/RAND_MAX);

	return in;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs, sizeof(double*));
	for (i = 0; i < inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			ann->layers[l]->neurons[o]->sum = 0;
			for (i = 0; i < ann->layers[l-1]->n; i++)
				ann->layers[l]->neurons[o]->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			ann->layers[l]->neurons[o]->value =
			ann->layers[l]->neurons[o]->activation(ann->layers[l]->neurons[o]->sum);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *results = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double *error = calloc(noutputs, sizeof(double));
	double acc, sum;
	int o, i, w, n;
	Neuron *O;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		error[o] = outputs[o] - results[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O->sum);
			for (i = 0; i < ann->layers[w]->n; i++) {
				D->values[i][o] *= acc;
			}
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
				for (i = 0; i < ann->layers[w]->n; i++)
					D->values[i][o] *= sum;
			}
		}

		D2 = D;
	}

	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i < W->inputs; i++) {
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate *
				ann->layers[w]->neurons[i]->value;
			}
		}
	}

	free(results);
	free(error);
}

int
main()
{
	int i, j, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.0001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);

			if (counter++ % 100 == 0) {
				error = 0;

				for (j = 0; j < 4; j++) {
					results = annrun(test, inputs[i]);
					error += pow(results[0] - outputs[i],
					2.0);
					free(results);
				}
				printf("error: %f\n", error);
			}
		}
	}
	printf("error: %f, done\n", error);
}


Fri Oct 12 05:47:38 EDT 2018
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <time.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(double input);
	double (*gradient)(double input);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(double), double(*)(double));
Neuron *neuroninit(Neuron*, double (*)(double), double (*)(double), double);
Neuron *neuroncreate(double (*)(double), double (*)(double), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(double x)
{
	return 1.0/(1.0+exp(-x));
}

double
gradient_sigmoid(double x)
{
	double y = activation_sigmoid(x);
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(double input), double
(*gradient)(double input), double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(double input), double (*gradient)(double input),
double steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(double),
double(*gradient)(double))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons, sizeof(Neuron*));
	for (i = 0; i < ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = ((double)rand()/RAND_MAX);

	return in;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs, sizeof(double*));
	for (i = 0; i < inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			ann->layers[l]->neurons[o]->sum = 0;
			for (i = 0; i < ann->layers[l-1]->n; i++)
				ann->layers[l]->neurons[o]->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			ann->layers[l]->neurons[o]->value =
			ann->layers[l]->neurons[o]->activation(ann->layers[l]->neurons[o]->sum);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *results = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double *error = calloc(noutputs, sizeof(double));
	double acc, sum;
	int o, i, w, n;
	Neuron *O;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		error[o] = outputs[o] - results[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O->sum);
			for (i = 0; i < ann->layers[w]->n; i++) {
				D->values[i][o] *= acc;
			}
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
				for (i = 0; i < ann->layers[w]->n; i++)
					D->values[i][o] *= sum;
			}
		}

		D2 = D;
	}

	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i < W->inputs; i++) {
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate *
				ann->layers[w]->neurons[i]->value;
			}
		}
	}

	free(results);
	free(error);
}

int
main()
{
	int i, j, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.0001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);

			if (counter++ % 100 == 0) {
				error = 0;

				for (j = 0; j < 4; j++) {
					results = annrun(test, inputs[i]);
					error += pow(results[0] - outputs[i],
					2.0);
					free(results);
				}
				printf("error: %f\n", error);
			}
		}
	}
	printf("error: %f, done\n", error);
}


Fri Oct 12 05:36:34 EDT 2018
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <time.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(double input);
	double (*gradient)(double input);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(double), double(*)(double));
Neuron *neuroninit(Neuron*, double (*)(double), double (*)(double), double);
Neuron *neuroncreate(double (*)(double), double (*)(double), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(double x)
{
	return 1.0/(1.0+exp(-x));
}

double
gradient_sigmoid(double x)
{
	double y = activation_sigmoid(x);
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(double input), double
(*gradient)(double input), double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(double input), double (*gradient)(double input),
double steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(double),
double(*gradient)(double))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons, sizeof(Neuron*));
	for (i = 0; i < ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = ((double)rand()/RAND_MAX);

	return in;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs, sizeof(double*));
	for (i = 0; i < inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			ann->layers[l]->neurons[o]->sum = 0;
			for (i = 0; i < ann->layers[l-1]->n; i++)
				ann->layers[l]->neurons[o]->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			ann->layers[l]->neurons[o]->value =
			ann->layers[l]->neurons[o]->activation(ann->layers[l]->neurons[o]->sum);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *results = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double *error = calloc(noutputs, sizeof(double));
	double acc, sum;
	int o, i, w, n;
	Neuron *O;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		error[o] = outputs[o] - results[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O->sum);
			for (i = 0; i < ann->layers[w]->n; i++) {
				D->values[i][o] *= acc;
			}
			if (D2 != D) {
				W = ann->weights[w + 1];
				sum = 0.0;
				for (n = 0; n < D2->outputs; n++)
					sum += D2->values[o][n] *
					W->values[o][n];
				for (i = 0; i < ann->layers[w]->n; i++)
					D->values[i][o] *= sum;
			}
		}

		D2 = D;
	}

	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i < W->inputs; i++) {
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate *
				ann->layers[w]->neurons[i]->value;
			}
		}
	}

	free(results);
	free(error);
}

int
main()
{
	int i, counter = 0;;
	Ann *test = anncreate(3, 2, 16, 1);
	test->rate = 4.0;
	double inputs[4][2] = { { 1.0, 1.0 }, {1.0, 0.0}, {0.0, 1.0}, {0.0, 0.0}};
	double outputs[4] = { 0.0, 1.0, 1.0, 0.0 };
	double *results;
	double error = 1000;
	while (error > 0.0001) {
		for (i = 0; i < 4; i++) {
			anntrain(test, inputs[i], &outputs[i]);

			if (counter++ % 100 == 0) {
				error = 0;

				results = annrun(test, inputs[i]);
				error += pow(results[0] - outputs[i], 2.0);
				free(results);
				printf("error: %f\n", error);
			}
		}
	}
	printf("error: %f, done\n", error);
}


Fri Oct 12 04:25:54 EDT 2018
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdarg.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(double input);
	double (*gradient)(double input);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(double), double(*)(double));
Neuron *neuroninit(Neuron*, double (*)(double), double (*)(double), double);
Neuron *neuroncreate(double (*)(double), double (*)(double), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(double x)
{
	return 1.0/(1.0+exp(-x));
}

double
gradient_sigmoid(double x)
{
	double y = activation_sigmoid(x);
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(double input), double
(*gradient)(double input), double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(double input), double (*gradient)(double input),
double steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(double),
double(*gradient)(double))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons, sizeof(Neuron*));
	for (i = 0; i < ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = ((double)rand()/RAND_MAX) - 0.5;

	return in;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs, sizeof(double*));
	for (i = 0; i < inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			ann->layers[l]->neurons[o]->sum = 0;
			for (i = 0; i < ann->layers[l-1]->n; i++)
				ann->layers[l]->neurons[o]->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			ann->layers[l]->neurons[o]->value =
			ann->layers[l]->neurons[o]->activation(ann->layers[l]->neurons[o]->sum);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *results = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double *error = calloc(noutputs, sizeof(double));
	double acc, sum;
	int o, i, w, n;
	Neuron *I, *O;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		error[o] = outputs[o] - results[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O->sum);
			for (i = 0; i < ann->layers[w]->n; i++) {
				D->values[i][o] *= acc;
				if (D != D2) {
					W = ann->weights[w+1];
					sum = 0.0;
					for (n = 0; n < W->outputs; n++)
						sum += D2->values[o][n] *
						W->values[o][n];
					D->values[i][o] *= sum;
				}
			}
		}

		D2 = D;
	}

	for (w = 0; w < ann->n-1; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i < W->inputs; i++) {
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate *
				ann->layers[w]->neurons[i]->value;
			}
		}
	}

	free(results);
	free(error);
}

void
main()
{
	int i;
	Ann *test = anncreate(3, 2, 16, 1);
	printf("Ann created\n");
	double input[2];
	input[0] = input[1] = 1.0;
	double output[1];
	output[0] = 0.0;
	double *results = annrun(test, input);
	printf("Ann has run\n");
	printf("%f\n", results[0]);
	for (i = 0; i < 1000000; i++)
		anntrain(test, input, output);
	printf("Ann has trained\n");
	free(results);
	results = annrun(test, input);
	printf("%f\n", results[0]);
}


Fri Oct 12 03:43:02 EDT 2018
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdarg.h>

typedef struct Ann Ann;
typedef struct Layer Layer;
typedef struct Neuron Neuron;
typedef struct Weights Weights;

struct Ann {
	int n;
	double rate;
	Layer **layers;
	Weights **weights;
	Weights **deltas;
};

struct Layer {
	int n;
	Neuron **neurons;
};

struct Neuron {
	double (*activation)(double input);
	double (*gradient)(double input);
	double steepness;
	double value;
	double sum;
};

struct Weights {
	int inputs;
	int outputs;
	double **values;
};

Ann *anncreate(int, ...);
Layer *layercreate(int, double(*)(double), double(*)(double));
Neuron *neuroninit(Neuron*, double (*)(double), double (*)(double), double);
Neuron *neuroncreate(double (*)(double), double (*)(double), double);
Weights *weightsinitrand(Weights*);
Weights *weightsinitdoubles(Weights*, double*);
Weights *weightscreate(int, int, int);
double *annrun(Ann*, double*);
void anntrain(Ann*, double*, double*);

double
activation_sigmoid(double x)
{
	return 1.0/(1.0+exp(-x));
}

double
gradient_sigmoid(double x)
{
	double y = activation_sigmoid(x);
	return y * (1.0 - y);
}

Neuron*
neuroninit(Neuron *in, double (*activation)(double input), double
(*gradient)(double input), double steepness)
{
	in->activation = activation;
	in->gradient = gradient;
	in->steepness = steepness;
	in->value = 0;
	in->sum = 0;
	return in;
}

Neuron*
neuroncreate(double (*activation)(double input), double (*gradient)(double input),
double steepness)
{
	Neuron *ret = calloc(1, sizeof(Neuron));
	neuroninit(ret, activation, gradient, steepness);
	return ret;
}

Layer*
layercreate(int num_neurons, double(*activation)(double),
double(*gradient)(double))
{
	Layer *ret = calloc(1, sizeof(Layer));
	int i;

	ret->n = num_neurons;
	ret->neurons = calloc(num_neurons, sizeof(Neuron*));
	for (i = 0; i < ret->n; i++) {
		ret->neurons[i] = neuroncreate(activation, gradient, 1.0);
	}
	return ret;
}

Weights*
weightsinitrand(Weights *in)
{
	int i, o;

	srand(time(0));
	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = ((double)rand()/RAND_MAX) - 0.5;

	return in;
}

Weights*
weightsinitdoubles(Weights *in, double *init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init[o];

	return in;
}

Weights*
weightsinitdouble(Weights *in, double init)
{
	int i, o;

	for (i = 0; i < in->inputs; i++)
		for (o = 0; o < in->outputs; o++)
			in->values[i][o] = init;

	return in;
}

Weights*
weightscreate(int inputs, int outputs, int initialize)
{
	int i;
	Weights *ret = calloc(1, sizeof(Weights));
	ret->inputs = inputs;
	ret->outputs = outputs;
	ret->values = calloc(inputs, sizeof(double*));
	for (i = 0; i < inputs; i++)
		ret->values[i] = calloc(outputs, sizeof(double));
	if (initialize)
		weightsinitrand(ret);
	else
		weightsinitdouble(ret, 1.0);
	return ret;
}

Ann*
anncreate(int num_layers, ...)
{
	Ann *ret = calloc(1, sizeof(Ann));
	va_list args;
	int arg;
	int i;

	va_start(args, num_layers);
	ret->n = num_layers;
	ret->rate = 0.25;
	ret->layers = calloc(num_layers, sizeof(Layer*));
	ret->weights = calloc(num_layers-1, sizeof(Weights*));
	ret->deltas = calloc(num_layers-1, sizeof(Weights*));

	for (i = 0; i < num_layers; i++) {
		arg = va_arg(args, int);
		if (arg < 0 || arg > 1000000)
			arg = 0;
		ret->layers[i] = layercreate(arg, activation_sigmoid,
		gradient_sigmoid);
		if (i > 0) {
			ret->weights[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 1);
			ret->deltas[i-1] =
			weightscreate(ret->layers[i-1]->n,
			ret->layers[i]->n, 0);
		}
	} va_end(args);

	return ret;
}

double*
annrun(Ann *ann, double *input)
{
	int l, i, o;
	int outputs = ann->layers[ann->n - 1]->n;
	double *ret = calloc(outputs, sizeof(double));

	for (i = 0; i < ann->layers[0]->n; i++)
		ann->layers[0]->neurons[i]->value = input[i];

	for (l = 1; l < ann->n; l++) {
		for (o = 0; o < ann->layers[l]->n; o++) {
			ann->layers[l]->neurons[o]->sum = 0;
			for (i = 0; i < ann->layers[l-1]->n; i++)
				ann->layers[l]->neurons[o]->sum +=
				ann->layers[l-1]->neurons[i]->value *
				ann->weights[l-1]->values[i][o];
			ann->layers[l]->neurons[o]->value =
			ann->layers[l]->neurons[o]->activation(ann->layers[l]->neurons[o]->sum);
		}
	}

	for (o = 0; o < outputs; o++)
		ret[o] = ann->layers[ann->n - 1]->neurons[o]->value;

	return ret;
}

void
anntrain(Ann *ann, double *inputs, double *outputs)
{
	double *results = annrun(ann, inputs);
	int noutputs = ann->layers[ann->n-1]->n;
	double *error = calloc(noutputs, sizeof(double));
	double acc, sum;
	int o, i, w, n;
	Neuron *I, *O;
	Weights *W, *D, *D2;

	for (o = 0; o < noutputs; o++) {
		error[o] = outputs[o] - results[o];
	}
	D = ann->deltas[ann->n-2];
	weightsinitdoubles(D, error);

	D2 = ann->deltas[ann->n-2];
	for (w = ann->n-2; w >= 0; w--) {
		D = ann->deltas[w];

		for (o = 0; o < ann->layers[w+1]->n; o++) {
			O = ann->layers[w+1]->neurons[o];
			acc = O->gradient(O->sum);
			for (i = 0; i < ann->layers[w]->n; i++) {
				I = ann->layers[w]->neurons[i];
				D->values[i][o] *= acc * I->value;
				if (w < (ann->n - 4)) {
					W = ann->weights[w + 2];
					sum = 0.0;
					for (n = 0; n < D2->outputs; n++)
						sum += D2->values[o][n] *
						W->values[o][n];
					D->values[i][o] *= sum;
				}
			}
		}

		D2 = D;
	}

	for (w = 0; w < ann->n-2; w++) {
		W = ann->weights[w];
		D = ann->deltas[w];

		for (i = 0; i < W->inputs; i++) {
			for (o = 0; o < W->outputs; o++) {
				W->values[i][o] += D->values[i][o] *
				ann->rate;
			}
		}
	}

	free(results);
	free(error);
}

void
main()
{
	int i;
	Ann *test = anncreate(3, 2, 16, 1);
	printf("Ann created\n");
	double input[2];
	input[0] = input[1] = 1.0;
	double output[1];
	output[0] = 0.0;
	double *results = annrun(test, input);
	printf("Ann has run\n");
	printf("%f\n", results[0]);
	for (i = 0; i < 1000000; i++)
		anntrain(test, input, output);
	printf("Ann has trained\n");
	free(results);
	results = annrun(test, input);
	printf("%f\n", results[0]);
}


prev | next