How to write multidimensional vector data to a file in C++ - c++

I have a vector of objects obj (of class Holder) with N elements with members like x and y which are also vectors of double type with M elements. I would like to write a text file creating an MxN matrix from this. I have tried lots of different things to no avail up to now.
vector<Holder> obj(N);
void savedata(string filename, vector<Holder> obj, int M, int N) {
ofstream out(filename);
for(int i = 0; i < M; i++) {
for(int j = 0; j < N; j++) {
out << obj[i][j] << "\t" << endl;
}
}
}
But this just takes the last set of values. How can I create such an MxN matrix where rows are from the object member vector x and columns are from the object vector itself?
Thank you in advance.
--
The bigger version of the code is as follows:
//
//
#include <iostream>
#include <cmath>
#include <fstream>
#include <string>
#include <vector>
#include <random>
using namespace std;
typedef vector< vector<double> > Matrix;
// Particles making up the cell
class Particle{
public:
double x; // x position
double y; // y position
double vx; // velocity in the x direction
double vy; // velocity in the y direction
double Fx; // force in the x direction
double Fy; // force in the y direction
// Default constructor
Particle()
: x(0.0),y(0.0),vx(0.0),vy(0.0),Fx(0.0),Fy(0.0){
}
};
// Holder for storing data
class HoldPar{
public:
vector<double> x;
vector<double> y;
vector<double> vx;
vector<double> vy;
// Default constructor
HoldPar()
: x(0.0),y(0.0),vx(0.0),vy(0.0){
}
// Add elements to vectors
void add_Xelement(double a) {
x.push_back(a);
}
void add_Yelement(double a) {
y.push_back(a);
}
void add_VXelement(double a) {
vx.push_back(a);
}
void add_VYelement(double a) {
vy.push_back(a);
}
};
int main() {
// Initialization of x, v and F
const float pi = 3.14;
int N = 30; // Number of 'particles' that make up the cell
float theta = 2*pi/N; // Angle between two particles in radians
float x0 = 0; // Center of the cell [x]
float y0 = 0; // Center of the cell [y]
float R = 5e-6; // Radius of the cell
vector<Particle> particles(N); // particles
// Assigning the initial points onto the circle
for(int i = 0; i < N; i++) {
particles[i].x = x0 + R*cos(theta*i);
particles[i].y = y0 + R*sin(theta*i);
}
float k = 4.3e-7; // Spring constant connecting the particles
float m = 2e-8; // Mass of the particles
// Calculating the initial spring force between the particles on the cell
particles[0].Fx = -k*(particles[1].x - particles[N].x);
particles[0].Fy = -k*(particles[1].y - particles[N].y);
for(int i = 1; i < N-1; i++) {
particles[i].Fx = -k*(particles[i+1].x - particles[i-1].x);
particles[i].Fy = -k*(particles[i+1].y - particles[i-1].y);
}
particles[N].Fx = -k*(particles[0].x - particles[N-1].x);
particles[N].Fy = -k*(particles[0].y - particles[N-1].y);
// Initial velocities are given to each particle randomly from a Gaussian distribution
random_device rdx; // Seed
default_random_engine generatorx(rdx()); // Default random number generator
random_device rdy; // Seed
default_random_engine generatory(rdy()); // Default random number generator
normal_distribution<float> distributionx(0,1); // Gaussian distribution with 0 mean and 1 variance
normal_distribution<float> distributiony(0,1); // Gaussian distribution with 0 mean and 1 variance
for(int i = 0; i < N; i++) {
float xnumber = distributionx(generatorx);
float ynumber = distributiony(generatory);
particles[i].vx = xnumber;
particles[i].vy = ynumber;
}
// Molecular dynamics simulation with velocity Verlet algorithm
// 'Old' variables
vector<Particle> particles_old(N);
for(int i = 0; i < N; i++) {
particles_old[i].x = particles[i].x;
particles_old[i].y = particles[i].y;
particles_old[i].vx = particles[i].vx;
particles_old[i].vy = particles[i].vy;
particles_old[i].Fx = particles[i].Fx;
particles_old[i].Fy = particles[i].Fy;
}
// Sampling variables
int sampleFreq = 2;
int sampleCounter = 0;
// MD variables
float dt = 1e-4;
float dt2 = dt*dt;
float m2 = 2*m;
int MdS = 1e+5; // Molecular dynamics step number
// Holder variables
vector<HoldPar> particles_hold(N);
// MD
for(int j = 0; j < MdS; j++) {
// Update x
for(int i = 0; i < N; i++) {
particles[i].x = particles_old[i].x + dt*particles_old[i].vx + dt2*particles_old[i].Fx/m2;
particles[i].y = particles_old[i].y + dt*particles_old[i].vy + dt2*particles_old[i].Fy/m2;
}
// Update F
particles[0].Fx = -k*(particles[1].x - particles[N].x);
particles[0].Fy = -k*(particles[1].y - particles[N].y);
for(int i = 1; i < N-1; i++) {
particles[i].Fx = -k*(particles[i+1].x - particles[i-1].x);
particles[i].Fy = -k*(particles[i+1].y - particles[i-1].y);
}
particles[N].Fx = -k*(particles[0].x - particles[N-1].x);
particles[N].Fy = -k*(particles[0].y - particles[N-1].y);
// Update v
for(int i = 0; i < N; i++) {
particles[i].vx = particles_old[i].vx + dt*(particles_old[i].Fx + particles[i].Fx)/m2;
particles[i].vy = particles_old[i].vy + dt*(particles_old[i].Fy + particles[i].Fy)/m2;
}
// Copy new variables to old variables
for(int i = 0; i < N; i++) {
particles_old[i].x = particles[i].x;
particles_old[i].y = particles[i].y;
particles_old[i].vx = particles[i].vx;
particles_old[i].vy = particles[i].vy;
particles_old[i].Fx = particles[i].Fx;
particles_old[i].Fy = particles[i].Fy;
}
// Store variables
if(j % sampleFreq == 0) {
for(int i = 0; i < N; i++) {
particles_hold[i].add_Xelement( particles[i].x );
particles_hold[i].add_Yelement( particles[i].y );
particles_hold[i].add_VXelement( particles[i].vx );
particles_hold[i].add_VYelement( particles[i].vy );
}
sampleCounter += 1;
}
}
//* End of molecular dynamics simulation
}
//
//*
//
Essentially I'm trying to write a txt file where particles_hold elements (from 1 to N) are columns and members of particles_hold elements like x (from 1 to some value M) are rows.

If you mean visually then the way is put endl or "\n" to the outer loop and remove endl from inner loop.But i do not know anythig about your Holder object and if you have [] operator defined there that is the answer.
vector<Holder> obj(N);
void savedata(string filename, vector<Holder> obj, int M, int N) {
ofstream out(filename);
for(int i = 0; i < M; i++) {
for(int j = 0; j < N; j++) {
out << obj[i][j] << "\t";
}
out<< "\n";
}
}

Your method is ok, however, made some minor change so that you have M lines, each lines represent obj[i], i = 0.. M-1. So, each column (jth index) is printed as tab separated in each line
vector<Holder> obj(N);
void savedata(string filename, vector<Holder> obj, int M, int N) {
ofstream out(filename);
for(int i = 0; i < M; i++) {
for(int j = 0; j < N; j++) {
out << obj[i][j] << "\t";
}
out << endl;
}
}

Related

C++ find the second shortest path using Dijkstras algorithm?

I have a Dijkstras algorithm program below. My program reads a text file and finds the shortest path from the start node to the goal node. My question is once this shorest path is discovered, given my code, how can I store this path? Reason being I am required to also find the second shorest path. Thankyou
#include <iostream>
#include <fstream>
#include <vector>
#include <limits.h>
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <utility>
using namespace std;
#define INFINITY1 9999
int counter = 0;
int vcount = 0;
int ecount = 0;
int startVertex;
int endVertex;
int nVerticies;
int nEdges;
struct Vertex
{
int label;
int xcord;
int ycord;
};
struct Edge
{
int parent1;
int parent2;
int weight;
};
Vertex *vertArray = NULL;
Edge *edgeArray = NULL;
float distance(int x1, int y1, int x2, int y2)
{
// Calculating distance
return sqrt(pow(x2 - x1, 2) +
pow(y2 - y1, 2) * 1.0);
}
// Dijkstras
void dijkstra(vector<vector<int>> G, int n, int startnode)
{
// Get x and y cords of start node
int startx = vertArray[startnode].xcord;
int starty = vertArray[startnode].ycord;
// Get x and y cords of end node
int endx = vertArray[n].xcord;
int endy = vertArray[n].ycord;
int **cost = new int *[nVerticies];
for (int i = 0; i < nVerticies; ++i)
{
cost[i] = new int[nVerticies];
}
int distance[nVerticies], pred[nVerticies];
int visited[nVerticies], counter, mindistance, nextnode, i, j;
for (i = 0; i < nVerticies; i++)
for (j = 0; j < nVerticies; j++)
// If there is no weight, then set it to infinity
if (G[i][j] == 0)
cost[i][j] = INFINITY1;
else
{
cost[i][j] = G[i][j];
}
for (i = 0; i < nVerticies; i++)
{
distance[i] = cost[startnode][i];
pred[i] = startnode;
visited[i] = 0;
}
distance[startnode] = 0;
visited[startnode] = 1;
counter = 1;
while (counter < nVerticies - 1)
{
mindistance = INFINITY1;
for (i = 0; i < nVerticies; i++)
if (distance[i] < mindistance && !visited[i])
{
mindistance = distance[i];
nextnode = i;
}
visited[nextnode] = 1;
for (i = 0; i < nVerticies; i++)
if (!visited[i])
if (mindistance + cost[nextnode][i] < distance[i])
{
distance[i] = mindistance + cost[nextnode][i];
pred[i] = nextnode;
}
counter++;
}
for(i=n; i<n+1; i++)
if(i!=startnode)
{
cout<<"\nDistance of node "<<i+1<<"="<<distance[i];
cout<<"\nPath="<<i+1;
j=n;
do
{
j=pred[j+1];
cout<<"<-"<<j+1;
}
while(j!=startnode);
}
}
int main()
{
// Declaration for reading file
int a, b, c;
ifstream readFile;
string fileName;
// Ask for file name
cout << "Enter filename: ";
cin >> fileName;
readFile.open(fileName);
// Read last line and set start and goal vertex equal to file input
while (readFile >> startVertex >> endVertex)
{
}
readFile.close();
readFile.open(fileName);
// Read line 1 and set nVerticies and nEdges equal to file input
while (readFile >> nVerticies >> nEdges)
{
counter++;
break;
}
// Create array with size nVerticies
vertArray = new Vertex[nVerticies];
for (int i = 0; i < nVerticies; i++)
{
// Initialise all elements to zero
vertArray[i].label = 0;
vertArray[i].xcord = 0;
vertArray[i].ycord = 0;
}
// Create array with size nEdges
edgeArray = new Edge[nEdges];
for (int i = 0; i < nEdges; i++)
{
// Initialise all elements to zero
edgeArray[i].parent1 = 0;
edgeArray[i].parent2 = 0;
edgeArray[i].weight = 0;
}
vector<vector<int>> G(nVerticies, vector<int>(nVerticies, 0));
while (readFile >> a >> b >> c)
{
// Get vertex from file and add it to array
if (nVerticies >= counter)
{
vertArray[vcount].label = a;
vertArray[vcount].xcord = b;
vertArray[vcount].ycord = c;
vcount++;
counter++;
}
// Get edge from file and add it to array
else
{
G[a - 1][b - 1] = c;
G[b - 1][a - 1] = c;
edgeArray[ecount].parent1 = a;
edgeArray[ecount].parent2 = b;
edgeArray[ecount].weight = c;
ecount++;
counter++;
}
}
readFile.close();
dijkstra(G, endVertex - 1, startVertex - 1);
int n = 11;
int u = 0;
cout << endl;
cout << endl;
cout << endl;
return 0;
}
output from read file
Distance of node 1=46
Path=1<-2
Distance of node 3=65
Path=3<-1<-2
Distance of node 4=47
Path=4<-2
Distance of node 5=36
Path=5<-2
Distance of node 6=53
Path=6<-2
Distance of node 7=135
Path=7<-8<-6<-2
Distance of node 8=99
Path=8<-6<-2
Distance of node 9=95
Path=9<-4<-2
Distance of node 10=82
Path=10<-2
Distance of node 11=116
Path=11<-10<-2
Distance of node 12=76
Path=12<-2
Distance of node 13=85
Path=13<-2
Ive been guided to follow a similar pattern to the following
if you have a path of 1-->2 -->3 -->4
Set 2 to max and try again
Reset 2
Set 3 to max
Reset 3

Trying to implement Durand-Kerner-Method in C++ using Matrices

My implementation of the Durand-Kerner-Method (https://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method) does not seem to work. I believe (see following code) that I am not calculating new approximation correctly in the algorithm part itself. I cannot seem to be able to fix the problem. Very grateful for any advice.
#include <complex>
#include <cmath>
#include <vector>
#include <iostream>
#include "DurandKernerWeierstrass.h"
using namespace std;
using Complex = complex<double>;
using vec = vector<Complex>;
using Matrix = vector<vector<Complex>>;
//PRE: Recieves input value of polynomial, degree and coefficients
//POST: Outputs y(x) value
Complex Polynomial(vec Z, int n, Complex x) {
Complex y = pow(x, n);
for (int i = 0; i < n; i++){
y += Z[i] * pow(x, (n - i - 1));
}
return y;
}
/*PRE: Takes a test value, degree of polynomial, vector of coefficients and the desired
precision of polynomial roots to calculate the roots*/
//POST: Outputs the roots of Polynomial
Matrix roots(vec Z, int n, int iterations, const double precision) {
Complex z = Complex(0.4, 0.9);
Matrix P(iterations, vec(n, 0));
Complex w;
//Creating Matrix with initial starting values
for (int i = 0; i < n; i++) {
P[0][i] = pow(z, i);
}
//Durand Kerner Algorithm
for (int col = 0; col < iterations; col++) {
*//I believe this is the point where everything is going wrong*
for (int row = 0; row < n; row++) {
Complex g = Polynomial(Z, n, P[col][row]);
for (int k = 0; k < n; k++) {
if (k != row) {
g = g / (P[col][row] - P[col][k]);
}
}
P[col][row] -= g;
}
return P;
}
}
The following Code is the code I am using to test the function:
int main() {
//Initializing section
vec A = {1, -3, 3,-5 };
int n = 3;
int iterations = 10;
const double precision = 1.0e-10;
Matrix p = roots(A, n, iterations,precision);
for (int i = 0; i < iterations; i++) {
for (int j = 0; j < n; j++) {
cout << "p[" << i << "][" << j << "] = " << p[i][j] << " ";
}
cout << endl;
}
return 0;
}
Important to note the Durand-Kerner-Algorithm is connected to a header file which is not included in this code.
Your problem is that you do not transcribe the new values into the next data record with index col+1. Thus in the next loop you start again with a data set of zero entries. Change to
P[col+1][row] = P[col][row] - g;
If you want to use the new improved approximation immediately for all following approximations, then use
P[col+1][row] = (P[col][row] -= g);
Then the data sets all contain the next approximations, especially the first one will no longer contain the initially set powers.

Need assistance with Segmentation Error

The following code is giving me the following error
Error description :
Unhandled exception at 0x00DC5D81 in ImageComponent2.exe: 0xC0000005: Access violation reading location 0xCDCDCDD5.
// ImageComponents
#include <iostream>
#include "Position.h"
using namespace std;
void labelComponents(int size, int **pixel);
void outputImage(int size, int **pixel);
int main(){
int size = 0;
cout << "Enter image size: ";
cin >> size;
int ** pixel = new int *[size + 2];
for (int i = 1; i <= size; i++)
{
pixel[i] = new int[size + 2];
}
cout << "Enter the pixel array in row-major order:\n";
for (int i = 1; i <= size; i++)
for (int j = 1; j <= size; j++)
{
cin >> pixel[i][j];
}
labelComponents(size, pixel);
outputImage(size, pixel);
system("pause");
return (0);
}
void labelComponents(int size, int **pixel){
// initialize offsets
Position * offset = new Position[4];
offset[0] = Position(0, 1); // right
offset[1] = Position(1, 0); // down
offset[2] = Position(0, -1); // left
offset[3] = Position(-1, 0); // up
int numNbr = 4; // neighbors of a pixel position
Position * nbr = new Position(0, 0);
Position * Q = new Position[size * size];
int id = 1; // component id
int x = 0; // (Position Q)
// scan all pixels labeling components
for (int r = 1; r <= size; r++) // row r of image
for (int c = 1; c <= size; c++) // column c of image
{
if (pixel[r][c] == 1)
{// new component
pixel[r][c] = ++id; // get next id
Position * here = new Position(r, c);
do
{// find rest of component
for (int i = 0; i < numNbr; i++)
{// check all neighbors of here
nbr->setRow(here->getRow() + offset[i].getRow());
nbr->setCol(here->getCol() + offset[i].getCol());
if (pixel[nbr->getRow()][nbr->getCol()] == 1)
{// pixel is part of current component
pixel[nbr->getRow()][nbr->getCol()] = id;
Q[x] = *nbr;
x++;
}
}
// any unexplored pixels in component?
*here = Q[x]; // a component pixel
x--;
} while (here != NULL);
} // end of if, for c, and for r
}
} // end of labelComponents
void outputImage(int size, int **pixel){
cout << "The labeled image is: ";
for (int i = 1; i <= size; i++){
cout << endl;
for (int j = 1; j <= size; j++)
cout << pixel[i][j] << " ";
}
} // end of outputImage
//Position.h
#ifndef POSITION_H
#define POSITION_H
class Position
{
private:
int row; // row number of the position
int col;
// column number of the position
public:
Position(); // default
Position( int theRow, int theCol); // parameter
Position(const Position & aPosition); // copy
Position & operator = (const Position & aPosition); // overload =
// overload =
// mutators
void setRow (int r);
void setCol (int c);
//accessors
int getRow() const;
int getCol() const;
}; // end Position
Position::Position()
{
setRow(0);
setCol(0);
}
Position::Position(int r, int c)
{
setRow(r);
setCol(c);
}
Position::Position(const Position & aPosition)
{
setRow(aPosition.row);
setCol(aPosition.col);
}
Position & Position::operator=(const Position & aPosition)
{
this->row=aPosition.row;
this->col=aPosition.col;
return(*this);
}
void Position::setRow(int r)
{
this->row = r;
}
void Position::setCol(int c)
{
this->col = c;
}
int Position::getRow() const
{
return this->row;
}
int Position::getCol() const
{
return this->col;
}
#endif
In C/C++, arraw indexes go from 0 to n-1, not from 1 to n. All your for loops are wrong:
for (int i = 1; i <= size; i++)
Must be replaced by:
for (int i = 0; i < size; i++)
Else, you access array at sizeposition which is out of bound.
Using a debugger and/or working with smaller piece of code would have made it easier for you to figure this out ;-)

Unhandled exception with C++ class function

I am writing a program which will preform texture synthesis. I have been away from C++ for a while and am having trouble figuring out what I am doing wrong in my class. When I run the program, I get an unhandled exception in the copyToSample function when it tries to access the arrays. It is being called from the bestSampleSearch function when the unhandled exception occurs. The function has been called before and works just fine, but later on in the program it is called a second time and fails. Any ideas? Let me know if anyone needs to see more code. Thanks!
Edit1: Added the bestSampleSearch function and the compareMetaPic function
Edit2: Added a copy constructor
Edit3: Added main()
Edit4: I have gotten the program to work. However there is now a memory leak of some kind or I am running out of memory when I run the program. It seems in the double for loop in main which starts "// while output picture is unfilled" is the problem. If I comment this portion out the program finishes in a timely manner but only one small square is output. Something must be wrong with my bestSampleSearch function.
MetaPic.h
#pragma once
#include <pic.h>
#include <stdlib.h>
#include <cmath>
class MetaPic
{
public:
Pic* source;
Pixel1*** meta;
int x;
int y;
int z;
MetaPic();
MetaPic(Pic*);
MetaPic(const MetaPic&);
MetaPic& operator=(const MetaPic&);
~MetaPic();
void allocateMetaPic();
void copyPixelData();
void copyToOutput(Pic*&);
void copyToMetaOutput(MetaPic&, int, int);
void copyToSample(MetaPic&, int, int);
void freeMetaPic();
};
MetaPic.cpp
#include "MetaPic.h"
MetaPic::MetaPic()
{
source = NULL;
meta = NULL;
x = 0;
y = 0;
z = 0;
}
MetaPic::MetaPic(Pic* pic)
{
source = pic;
x = pic->nx;
y = pic->ny;
z = pic->bpp;
allocateMetaPic();
copyPixelData();
}
MetaPic::MetaPic(const MetaPic& mp)
{
source = mp.source;
x = mp.x;
y = mp.y;
z = mp.z;
allocateMetaPic();
copyPixelData();
}
MetaPic::~MetaPic()
{
freeMetaPic();
}
// create a 3 dimensional array from the original one dimensional array
void MetaPic::allocateMetaPic()
{
meta = (Pixel1***)calloc(x, sizeof(Pixel1**));
for(int i = 0; i < x; i++)
{
meta[i] = (Pixel1**)calloc(y, sizeof(Pixel1*));
for(int j = 0; j < y; j++)
{
meta[i][j] = (Pixel1*)calloc(z, sizeof(Pixel1));
}
}
}
void MetaPic::copyPixelData()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < x; i++)
{
for(int k = 0; k < z; k++)
meta[i][j][k] = source->pix[(j*z*x)+(i*z)+k];
}
}
}
void MetaPic::copyToOutput(Pic* &output)
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < x; i++)
{
for(int k = 0; k < z; k++)
output->pix[(j*z*x)+(i*z)+k] = meta[i][j][k];
}
}
}
// copy the meta data to the final pic output starting at the top left of the picture and mapped to 'a' and 'b' coordinates in the output
void MetaPic::copyToMetaOutput(MetaPic &output, int a, int b)
{
for(int j = 0; (j < y) && ((j+b) < output.y); j++)
{
for(int i = 0; (i < x) && ((i+a) < output.x); i++)
{
for(int k = 0; k < z; k++)
output.meta[i+a][j+b][k] = meta[i][j][k];
}
}
}
// copies from a source image to a smaller sample image
// *** Must make sure that the x and y coordinates have enough buffer space ***
void MetaPic::copyToSample(MetaPic &sample, int a, int b)
{
for(int j = 0; (j < sample.y) && ((b+j) < y); j++)
{
for(int i = 0; i < (sample.x) && ((a+i) < x); i++)
{
for(int k = 0; k < sample.z; k++)
{
**sample.meta[i][j][k] = meta[i+a][j+b][k];**
}
}
}
}
// free the meta pic data (MetaPic.meta)
// *** Not to be used outside of class declaration ***
void MetaPic::freeMetaPic()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < z; i++)
free(meta[i][j]);
}
for(int i = 0; i < x; i++)
free(meta[i]);
free(meta);
}
MetaPic MetaPic::operator=(MetaPic mp)
{
MetaPic newMP(mp.source);
return newMP;
}
main.cpp
#ifdef WIN32
// For VC++ you need to include this file as glut.h and gl.h refer to it
#include <windows.h>
// disable the warning for the use of strdup and friends
#pragma warning(disable:4996)
#endif
#include <stdio.h> // Standard Header For Most Programs
#include <stdlib.h> // Additional standard Functions (exit() for example)
#include <iostream>
// Interface to libpicio, provides functions to load/save jpeg files
#include <pic.h>
#include <string.h>
#include <time.h>
#include <cmath>
#include "MetaPic.h"
using namespace std;
MetaPic bestSampleSearch(MetaPic, MetaPic);
double compareMetaPics(MetaPic, MetaPic);
#define SAMPLE_SIZE 23
#define OVERLAP 9
// Texture source image (pic.h uses the Pic* data structure)
Pic *sourceImage;
Pic *outputImage;
int main(int argc, char* argv[])
{
char* pictureName = "reg1.jpg";
int outputWidth = 0;
int outputHeight = 0;
// attempt to read in the file name
sourceImage = pic_read(pictureName, NULL);
if(sourceImage == NULL)
{
cout << "Couldn't read the file" << endl;
system("pause");
exit(EXIT_FAILURE);
}
// *** For now set the output image to 3 times the original height and width ***
outputWidth = sourceImage->nx*3;
outputHeight = sourceImage->ny*3;
// allocate the output image
outputImage = pic_alloc(outputWidth, outputHeight, sourceImage->bpp, NULL);
Pic* currentImage = pic_alloc(SAMPLE_SIZE, SAMPLE_SIZE, sourceImage->bpp, NULL);
MetaPic metaSource(sourceImage);
MetaPic metaOutput(outputImage);
MetaPic metaCurrent(currentImage);
// seed the output image
int x = 0;
int y = 0;
int xupperbound = metaSource.x - SAMPLE_SIZE;
int yupperbound = metaSource.y - SAMPLE_SIZE;
int xlowerbound = 0;
int ylowerbound = 0;
// find random coordinates
srand(time(NULL));
while((x >= xupperbound) || (x <= xlowerbound))
x = rand() % metaSource.x;
while((y >= yupperbound) || (y <= ylowerbound))
y = rand() % metaSource.y;
// copy a random sample from the source to the metasample
metaSource.copyToSample(metaCurrent, x, y);
// copy the seed to the metaoutput
metaCurrent.copyToMetaOutput(metaOutput, 0, 0);
int currentOutputX = 0;
int currentOutputY = 0;
// while the output picture is unfilled...
for(int j = 0; j < yupperbound; j+=(SAMPLE_SIZE-OVERLAP))
{
for(int i = 0; i < xupperbound; i+=(SAMPLE_SIZE-OVERLAP))
{
// move the sample to correct overlap
metaSource.copyToSample(metaCurrent, i, j);
// find the best match for the sample
metaCurrent = bestSampleSearch(metaSource, metaCurrent);
// write the best match to the metaoutput
metaCurrent.copyToMetaOutput(metaOutput, i, j);
// update the values
}
}
// copy the metaOutput to the output
metaOutput.copyToOutput(outputImage);
// output the image
pic_write("reg1_output.jpg", outputImage, PIC_JPEG_FILE);
// clean up
pic_free(sourceImage);
pic_free(outputImage);
pic_free(currentImage);
// return success
cout << "Done!" << endl;
system("pause");
// return success
return 0;
}
// finds the best sample to insert into the image
// *** best must be the sample which consists of the overlap ***
MetaPic bestSampleSearch(MetaPic source, MetaPic best)
{
MetaPic metaSample(best);
double bestScore = 999999.0;
double currentScore = 0.0;
for(int j = 0; j < source.y; j++)
{
for(int i = 0; i < source.x; i++)
{
// copy the image starting at the top left of the source image
source.copyToSample(metaSample, i, j);
// compare the sample with the overlap
currentScore = compareMetaPics(best, metaSample);
// if best score is greater than current score then copy the better sample to best and continue searching
if( bestScore > currentScore)
{
metaSample.copyToSample(best, 0, 0);
bestScore = currentScore;
}
// otherwise, the score is less than current score then do nothing (a better sample has not been found)
}
}
return best;
}
// find the comparison score for the two MetaPics based on their rgb values
// *** Both of the meta pics should be the same size ***
double compareMetaPics(MetaPic pic1, MetaPic pic2)
{
float r1 = 0.0;
float g1 = 0.0;
float b1 = 0.0;
float r2 = 0.0;
float g2 = 0.0;
float b2 = 0.0;
float r = 0.0;
float g = 0.0;
float b = 0.0;
float sum = 0.0;
// take the sum of the (sqrt((r1-r2)^2 + ((g1-g2)^2 + ((b1-b2)^2))
for(int j = 0; (j < pic1.y) && (j < pic2.y); j++)
{
for(int i = 0; (i < pic1.x) && (i < pic2.x); i++)
{
r1 = PIC_PIXEL(pic1.source, i, j, 0);
r2 = PIC_PIXEL(pic2.source, i, j, 0);
g1 = PIC_PIXEL(pic1.source, i, j, 1);
g2 = PIC_PIXEL(pic2.source, i, j, 1);
b1 = PIC_PIXEL(pic1.source, i, j, 2);
b2 = PIC_PIXEL(pic2.source, i, j, 2);
r = r1 - r2;
g = g1 - g2;
b = b1 - b2;
sum += sqrt((r*r) + (g*g) + (b*b));
}
}
return sum;
}
I'm not sure if this is the root cause of the problem, but your assignment operator does not actually assign anything:
MetaPic MetaPic::operator=(MetaPic mp)
{
MetaPic newMP(mp.source);
return newMP;
}
This should probably look something like the following (based off of the code in your copy constructor):
edit: with credit to Alf P. Steinbach
MetaPic& MetaPic::operator=(MetaPic mp)
{
mp.swap(*this);
return *this;
}
It turns out that the deallocate function is incorrect. It should be freeing in the same manner that it was allocating.
void MetaPic::freeMetaPic()
{
for(int j = 0; j < y; j++)
{
for(int i = 0; i < z; i++)
free(meta[i][j]);
}
for(int i = 0; i < x; i++)
free(meta[i]);
free(meta);
}

Getting a simple Neural Network to work from scratch in C++

I have been trying to get a simple double XOR neural network to work and I am having problems getting backpropagation to train a really simple feed forward neural network.
I have been mostly been trying to follow this guide in getting a neural network but have at best made programs that learn at extremely slow rate.
As I understand neural networks:
Values are computed by taking the result of a sigmoid function from the sum of all inputs to that neuron. This is then fed to the next layer using the weight for each neuron
At the end of running the error is computed for the output neurons, then using the weights, error is back propagated back by simply multiplying the values and then summing at each Neuron
When all of the errors are computed the weights are adjusted by the delta = weight of connection * derivative of the sigmoid (value of Neuron weight is going to) * value of Neuron that connection is to * error of neuron * amount of output error of neuron going to * beta (some constant for learning rate)
This is my current muck of code that I am trying to get working. I have a lot of other attempts somewhat mixed in, but the main backpropagation function that I am trying to get working is on line 293 in Net.cpp
Have a look at 15 Steps to implement a Neural Network, it should get you started.
I wrote a simple a "Tutorial" that you can check out below.
It is a simple implementation of the perceptron model. You can imagine a perceptron as a neural network with only one neuron. There is of curse code that you can test out that I wrote in C++. I go through the code step by step so you shouldn't have any issues.
Although the perceptron isn't really a "Neural Network" it is really helpful if you want to get started and might help you better understand how a full Neural Network works.
Hope that helps!
Cheers! ^_^
In this example I will go through the implementation of the perceptron model in C++ so that you can get a better idea of how it works.
First things first it is a good practice to write down a simple algorithm of what we want to do.
Algorithm:
Make a the vector for the weights and initialize it to 0 (Don't forget to add the bias term)
Keep adjusting the weights until we get 0 errors or a low error count.
Make predictions on unseen data.
Having written a super simple algorithm let's now write some of the functions that we will need.
We will need a function to calculate the net's input (e.i *x * wT* multiplying the inputs time the weights)
A step function so that we get a prediction of either 1 or -1
And a function that finds the ideal values for the weights.
So without further ado let's get right into it.
Let's start simple by creating a perceptron class:
class perceptron
{
public:
private:
};
Now let's add the functions that we will need.
class perceptron
{
public:
perceptron(float eta,int epochs);
float netInput(vector<float> X);
int predict(vector<float> X);
void fit(vector< vector<float> > X, vector<float> y);
private:
};
Notice how the function fit takes as an argument a vector of vector< float >. That is because our training dataset is a matrix of inputs. Essentially we can imagine that matrix as a couple of vectors x stacked the one on top of another and each column of that Matrix being a feature.
Finally let's add the values that our class needs to have. Such as the vector w to hold the weights, the number of epochs which indicates the number of passes that we will do over the training dataset. And the constant eta which is the learning rate of which we will multiply each weight update in order to make the training procedure faster by dialing this value up or if eta is too high we can dial it down to get the ideal result( for most applications of the perceptron I would suggest an eta value of 0.1 ).
class perceptron
{
public:
perceptron(float eta,int epochs);
float netInput(vector<float> X);
int predict(vector<float> X);
void fit(vector< vector<float> > X, vector<float> y);
private:
float m_eta;
int m_epochs;
vector < float > m_w;
};
Now with our class set. It's time to write each one of the functions.
We will start from the constructor ( perceptron(float eta,int epochs); )
perceptron::perceptron(float eta, int epochs)
{
m_epochs = epochs; // We set the private variable m_epochs to the user selected value
m_eta = eta; // We do the same thing for eta
}
As you can see what we will be doing is very simple stuff. So let's move on to another simple function. The predict function( int predict(vector X); ). Remember that what the all predict function does is taking the net input and returning a value of 1 if the netInput is bigger than 0 and -1 otherwhise.
int perceptron::predict(vector<float> X)
{
return netInput(X) > 0 ? 1 : -1; //Step Function
}
Notice that we used an inline if statement to make our lives easier. Here's how the inline if statement works:
condition ? if_true : else
So far so good. Let's move on to implementing the netInput function( float netInput(vector X); )
The netInput does the following; multiplies the input vector by the transpose of the weights vector
*x * wT*
In other words, it multiplies each element of the input vector x by the corresponding element of the vector of weights w and then takes their sum and adds the bias.
*(x1 * w1 + x2 * w2 + ... + xn * wn) + bias*
*bias = 1 * w0*
float perceptron::netInput(vector<float> X)
{
// Sum(Vector of weights * Input vector) + bias
float probabilities = m_w[0]; // In this example I am adding the perceptron first
for (int i = 0; i < X.size(); i++)
{
probabilities += X[i] * m_w[i + 1]; // Notice that for the weights I am counting
// from the 2nd element since w0 is the bias and I already added it first.
}
return probabilities;
}
Alright so we are now pretty much done last thing we need to do is to write the fit function which modifies the weights.
void perceptron::fit(vector< vector<float> > X, vector<float> y)
{
for (int i = 0; i < X[0].size() + 1; i++) // X[0].size() + 1 -> I am using +1 to add the bias term
{
m_w.push_back(0); // Setting each weight to 0 and making the size of the vector
// The same as the number of features (X[0].size()) + 1 for the bias term
}
for (int i = 0; i < m_epochs; i++) // Iterating through each epoch
{
for (int j = 0; j < X.size(); j++) // Iterating though each vector in our training Matrix
{
float update = m_eta * (y[j] - predict(X[j])); //we calculate the change for the weights
for (int w = 1; w < m_w.size(); w++){ m_w[w] += update * X[j][w - 1]; } // we update each weight by the update * the training sample
m_w[0] = update; // We update the Bias term and setting it equal to the update
}
}
}
So that was essentially it. With only 3 functions we now have a working perceptron class that we can use to make predictions!
In case you want to copy-paste the code and try it out. Here is the entire class (I added some extra functionality such as printing the weights vector and the errors in each epoch as well as added the option to import/export weights.)
Here is the code:
The class header:
class perceptron
{
public:
perceptron(float eta,int epochs);
float netInput(vector<float> X);
int predict(vector<float> X);
void fit(vector< vector<float> > X, vector<float> y);
void printErrors();
void exportWeights(string filename);
void importWeights(string filename);
void printWeights();
private:
float m_eta;
int m_epochs;
vector < float > m_w;
vector < float > m_errors;
};
The class .cpp file with the functions:
perceptron::perceptron(float eta, int epochs)
{
m_epochs = epochs;
m_eta = eta;
}
void perceptron::fit(vector< vector<float> > X, vector<float> y)
{
for (int i = 0; i < X[0].size() + 1; i++) // X[0].size() + 1 -> I am using +1 to add the bias term
{
m_w.push_back(0);
}
for (int i = 0; i < m_epochs; i++)
{
int errors = 0;
for (int j = 0; j < X.size(); j++)
{
float update = m_eta * (y[j] - predict(X[j]));
for (int w = 1; w < m_w.size(); w++){ m_w[w] += update * X[j][w - 1]; }
m_w[0] = update;
errors += update != 0 ? 1 : 0;
}
m_errors.push_back(errors);
}
}
float perceptron::netInput(vector<float> X)
{
// Sum(Vector of weights * Input vector) + bias
float probabilities = m_w[0];
for (int i = 0; i < X.size(); i++)
{
probabilities += X[i] * m_w[i + 1];
}
return probabilities;
}
int perceptron::predict(vector<float> X)
{
return netInput(X) > 0 ? 1 : -1; //Step Function
}
void perceptron::printErrors()
{
printVector(m_errors);
}
void perceptron::exportWeights(string filename)
{
ofstream outFile;
outFile.open(filename);
for (int i = 0; i < m_w.size(); i++)
{
outFile << m_w[i] << endl;
}
outFile.close();
}
void perceptron::importWeights(string filename)
{
ifstream inFile;
inFile.open(filename);
for (int i = 0; i < m_w.size(); i++)
{
inFile >> m_w[i];
}
}
void perceptron::printWeights()
{
cout << "weights: ";
for (int i = 0; i < m_w.size(); i++)
{
cout << m_w[i] << " ";
}
cout << endl;
}
Also if you want to try out an example here is an example I made:
main.cpp:
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <string>
#include <math.h>
#include "MachineLearning.h"
using namespace std;
using namespace MachineLearning;
vector< vector<float> > getIrisX();
vector<float> getIrisy();
int main()
{
vector< vector<float> > X = getIrisX();
vector<float> y = getIrisy();
vector<float> test1;
test1.push_back(5.0);
test1.push_back(3.3);
test1.push_back(1.4);
test1.push_back(0.2);
vector<float> test2;
test2.push_back(6.0);
test2.push_back(2.2);
test2.push_back(5.0);
test2.push_back(1.5);
//printVector(X);
//for (int i = 0; i < y.size(); i++){ cout << y[i] << " "; }cout << endl;
perceptron clf(0.1, 14);
clf.fit(X, y);
clf.printErrors();
cout << "Now Predicting: 5.0,3.3,1.4,0.2(CorrectClass=-1,Iris-setosa) -> " << clf.predict(test1) << endl;
cout << "Now Predicting: 6.0,2.2,5.0,1.5(CorrectClass=1,Iris-virginica) -> " << clf.predict(test2) << endl;
system("PAUSE");
return 0;
}
vector<float> getIrisy()
{
vector<float> y;
ifstream inFile;
inFile.open("y.data");
string sampleClass;
for (int i = 0; i < 100; i++)
{
inFile >> sampleClass;
if (sampleClass == "Iris-setosa")
{
y.push_back(-1);
}
else
{
y.push_back(1);
}
}
return y;
}
vector< vector<float> > getIrisX()
{
ifstream af;
ifstream bf;
ifstream cf;
ifstream df;
af.open("a.data");
bf.open("b.data");
cf.open("c.data");
df.open("d.data");
vector< vector<float> > X;
for (int i = 0; i < 100; i++)
{
char scrap;
int scrapN;
af >> scrapN;
bf >> scrapN;
cf >> scrapN;
df >> scrapN;
af >> scrap;
bf >> scrap;
cf >> scrap;
df >> scrap;
float a, b, c, d;
af >> a;
bf >> b;
cf >> c;
df >> d;
X.push_back(vector < float > {a, b, c, d});
}
af.close();
bf.close();
cf.close();
df.close();
return X;
}
The way I imported the iris dataset isn't really ideal but I just wanted something that worked.
The data files can be found here.
I hope that you found this helpful!
Note: The code above is there only as an example. As noted by juzzlin it is important that you use const vector<float> &X and in general pass the vector/vector<vector> objects by reference because the data can be very large and passing it by value will make a copy of it (which is inefficient).
Sounds to me like you are struggling with backprop and what you describe above doesn't quite match how I understand it to work, and your description is a bit ambiguous.
You calculate the output error term to backpropagate as the diffrence between the prediction and the actual value multiplied by the derivative of the transfer function. It is that error value which you then propagate backwards. The derivative of a sigmoid is calculated quite simply as y(1-y) where y is your output value. There are lots of proofs of that available on the web.
For a node on the inner layer, you multiply that output error by the weight between the two nodes, and sum all those products as the total error from the outer layer being propagated to the node in the inner layer. The error associated with the inner node is then multiplied by the derivative of the transfer function applied to the original output value. Here's some pseudocode:
total_error = sum(output_errors * weights)
node_error = sigmoid_derivative(node_output) * total_error
This error is then propagated backwards in the same manner right back through the input layer weights.
The weights are adjusted using these error terms and the output values of the nodes
weight_change = outer_error * inner_output_value
the learning rate is important because the weight change is calculated for every pattern/row/observation in the input data. You want to moderate the weight change for each row so the weights don't get unduly changed by any single row and so that all rows have an effect on the weights. The learning rate gives you that and you adjust the weight change by multiplying by it
weight_change = outer_error * inner_output_value * learning_rate
It is also normal to remember these changes between epochs (iterations) and to add a fraction of it to the change. The fraction added is called momentum and is supposed to speed you up through regions of the error surface where there is not much change and slow you down where there is detail.
weight_change = (outer_error*inner_output_value*learning_rate) + (last_change*momentum)
There are algorithms for adjusting the learning rate and momentum as the training proceeds.
The weight is then updated by adding the change
new_weight = old_weight + weight_change
I had a look through your code, but rather than correct it and post that I thought it was better to describe back prop for you so you can code it up yourself. If you understand it you'll be able to tune it for your circumstances too.
HTH and good luck.
How about this open-source code. It defines a simple 1 hidden layer net (2 input, 2 hidden, 1 output) and solves XOR problem:
https://web.archive.org/web/20131105002125/http://www.sylbarth.com/mlp.php
What about a simple function approximation network like the one that predicts and fits a Sine Function. Also, I think, avoiding class during implementation is a must for getting the basics easily. Let's consider a single hidden layer network.
//Had a lot of trouble with shuffle
#include <iostream>
#include<vector>
#include <list>
#include <cstdlib>
#include <math.h>
#define PI 3.141592653589793238463
#define N
#define epsilon 0.1
#define epoch 2000
using namespace std;
// Just for GNU Plot issues
extern "C" FILE *popen(const char *command, const char *mode);
// Defining activation functions
//double sigmoid(double x) { return 1.0f / (1.0f + exp(-x)); }
//double dsigmoid(double x) { return x * (1.0f - x); }
double tanh(double x) { return (exp(x)-exp(-x))/(exp(x)+exp(-x)) ;}
double dtanh(double x) {return 1.0f - x*x ;}
double lin(double x) { return x;}
double dlin(double x) { return 1.0f;}
double init_weight() { return (2*rand()/RAND_MAX -1); }
double MAXX = -9999999999999999; //maximum value of input example
// Network Configuration
static const int numInputs = 1;
static const int numHiddenNodes = 7;
static const int numOutputs = 1;
// Learning Rate
const double lr = 0.05f;
double hiddenLayer[numHiddenNodes];
double outputLayer[numOutputs];
double hiddenLayerBias[numHiddenNodes];
double outputLayerBias[numOutputs];
double hiddenWeights[numInputs][numHiddenNodes];
double outputWeights[numHiddenNodes][numOutputs];
static const int numTrainingSets = 50;
double training_inputs[numTrainingSets][numInputs];
double training_outputs[numTrainingSets][numOutputs];
// Shuffling the data with each epoch
void shuffle(int *array, size_t n)
{
if (n > 1) //If no. of training examples > 1
{
size_t i;
for (i = 0; i < n - 1; i++)
{
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
// Forward Propagation. Only used after training is done.
void predict(double test_sample[])
{
for (int j=0; j<numHiddenNodes; j++)
{
double activation=hiddenLayerBias[j];
for (int k=0; k<numInputs; k++)
{
activation+=test_sample[k]*hiddenWeights[k][j];
}
hiddenLayer[j] = tanh(activation);
}
for (int j=0; j<numOutputs; j++)
{
double activation=outputLayerBias[j];
for (int k=0; k<numHiddenNodes; k++)
{
activation+=hiddenLayer[k]*outputWeights[k][j];
}
outputLayer[j] = lin(activation);
}
//std::cout<<outputLayer[0]<<"\n";
//return outputLayer[0];
//std::cout << "Input:" << training_inputs[i][0] << " " << training_inputs[i][1] << " Output:" << outputLayer[0] << " Expected Output: " << training_outputs[i][0] << "\n";
}
int main(int argc, const char * argv[])
{
///TRAINING DATA GENERATION
for (int i = 0; i < numTrainingSets; i++)
{
double p = (2*PI*(double)i/numTrainingSets);
training_inputs[i][0] = (p);
training_outputs[i][0] = sin(p);
///FINDING NORMALIZING FACTOR
for(int m=0; m<numInputs; ++m)
if(MAXX < training_inputs[i][m])
MAXX = training_inputs[i][m];
for(int m=0; m<numOutputs; ++m)
if(MAXX < training_outputs[i][m])
MAXX = training_outputs[i][m];
}
///NORMALIZING
for (int i = 0; i < numTrainingSets; i++)
{
for(int m=0; m<numInputs; ++m)
training_inputs[i][m] /= 1.0f*MAXX;
for(int m=0; m<numOutputs; ++m)
training_outputs[i][m] /= 1.0f*MAXX;
cout<<"In: "<<training_inputs[i][0]<<" out: "<<training_outputs[i][0]<<endl;
}
///WEIGHT & BIAS INITIALIZATION
for (int i=0; i<numInputs; i++) {
for (int j=0; j<numHiddenNodes; j++) {
hiddenWeights[i][j] = init_weight();
}
}
for (int i=0; i<numHiddenNodes; i++) {
hiddenLayerBias[i] = init_weight();
for (int j=0; j<numOutputs; j++) {
outputWeights[i][j] = init_weight();
}
}
for (int i=0; i<numOutputs; i++) {
//outputLayerBias[i] = init_weight();
outputLayerBias[i] = 0;
}
///FOR INDEX SHUFFLING
int trainingSetOrder[numTrainingSets];
for(int j=0; j<numInputs; ++j)
trainingSetOrder[j] = j;
///TRAINING
//std::cout<<"start train\n";
vector<double> performance, epo; ///STORE MSE, EPOCH
for (int n=0; n < epoch; n++)
{
double MSE = 0;
shuffle(trainingSetOrder,numTrainingSets);
std::cout<<"epoch :"<<n<<"\n";
for (int i=0; i<numTrainingSets; i++)
{
//int i = trainingSetOrder[x];
int x=i;
//std::cout<<"Training Set :"<<x<<"\n";
/// Forward pass
for (int j=0; j<numHiddenNodes; j++)
{
double activation=hiddenLayerBias[j];
//std::cout<<"Training Set :"<<x<<"\n";
for (int k=0; k<numInputs; k++) {
activation+=training_inputs[x][k]*hiddenWeights[k][j];
}
hiddenLayer[j] = tanh(activation);
}
for (int j=0; j<numOutputs; j++) {
double activation=outputLayerBias[j];
for (int k=0; k<numHiddenNodes; k++)
{
activation+=hiddenLayer[k]*outputWeights[k][j];
}
outputLayer[j] = lin(activation);
}
//std::cout << "Input:" << training_inputs[x][0] << " " << " Output:" << outputLayer[0] << " Expected Output: " << training_outputs[x][0] << "\n";
for(int k=0; k<numOutputs; ++k)
MSE += (1.0f/numOutputs)*pow( training_outputs[x][k] - outputLayer[k], 2);
/// Backprop
/// For V
double deltaOutput[numOutputs];
for (int j=0; j<numOutputs; j++) {
double errorOutput = (training_outputs[i][j]-outputLayer[j]);
deltaOutput[j] = errorOutput*dlin(outputLayer[j]);
}
/// For W
double deltaHidden[numHiddenNodes];
for (int j=0; j<numHiddenNodes; j++) {
double errorHidden = 0.0f;
for(int k=0; k<numOutputs; k++) {
errorHidden+=deltaOutput[k]*outputWeights[j][k];
}
deltaHidden[j] = errorHidden*dtanh(hiddenLayer[j]);
}
///Updation
/// For V and b
for (int j=0; j<numOutputs; j++) {
//b
outputLayerBias[j] += deltaOutput[j]*lr;
for (int k=0; k<numHiddenNodes; k++)
{
outputWeights[k][j]+= hiddenLayer[k]*deltaOutput[j]*lr;
}
}
/// For W and c
for (int j=0; j<numHiddenNodes; j++) {
//c
hiddenLayerBias[j] += deltaHidden[j]*lr;
//W
for(int k=0; k<numInputs; k++) {
hiddenWeights[k][j]+=training_inputs[i][k]*deltaHidden[j]*lr;
}
}
}
//Averaging the MSE
MSE /= 1.0f*numTrainingSets;
//cout<< " MSE: "<< MSE<<endl;
///Steps to PLOT PERFORMANCE PER EPOCH
performance.push_back(MSE*100);
epo.push_back(n);
}
// Print weights
std::cout << "Final Hidden Weights\n[ ";
for (int j=0; j<numHiddenNodes; j++) {
std::cout << "[ ";
for(int k=0; k<numInputs; k++) {
std::cout << hiddenWeights[k][j] << " ";
}
std::cout << "] ";
}
std::cout << "]\n";
std::cout << "Final Hidden Biases\n[ ";
for (int j=0; j<numHiddenNodes; j++) {
std::cout << hiddenLayerBias[j] << " ";
}
std::cout << "]\n";
std::cout << "Final Output Weights";
for (int j=0; j<numOutputs; j++) {
std::cout << "[ ";
for (int k=0; k<numHiddenNodes; k++) {
std::cout << outputWeights[k][j] << " ";
}
std::cout << "]\n";
}
std::cout << "Final Output Biases\n[ ";
for (int j=0; j<numOutputs; j++) {
std::cout << outputLayerBias[j] << " ";
}
std::cout << "]\n";
/* This part is just for plotting the results.
This requires installing GNU Plot. You can also comment it out.
*/
//Plot the results
vector<float> x;
vector<float> y1, y2;
//double test_input[1000][numInputs];
int numTestSets = numTrainingSets;
for (float i = 0; i < numTestSets; i=i+0.25)
{
double p = (2*PI*(double)i/numTestSets);
x.push_back(p);
y1.push_back(sin(p));
double test_input[1];
test_input[0] = p/MAXX;
predict(test_input);
y2.push_back(outputLayer[0]*MAXX);
}
FILE * gp = popen("gnuplot", "w");
fprintf(gp, "set terminal wxt size 600,400 \n");
fprintf(gp, "set grid \n");
fprintf(gp, "set title '%s' \n", "f(x) = x sin (x)");
fprintf(gp, "set style line 1 lt 3 pt 7 ps 0.1 lc rgb 'green' lw 1 \n");
fprintf(gp, "set style line 2 lt 3 pt 7 ps 0.1 lc rgb 'red' lw 1 \n");
fprintf(gp, "plot '-' w p ls 1, '-' w p ls 2 \n");
///Exact f(x) = sin(x) -> Green Graph
for (int k = 0; k < x.size(); k++) {
fprintf(gp, "%f %f \n", x[k], y1[k]);
}
fprintf(gp, "e\n");
///Neural Network Approximate f(x) = xsin(x) -> Red Graph
for (int k = 0; k < x.size(); k++) {
fprintf(gp, "%f %f \n", x[k], y2[k]);
}
fprintf(gp, "e\n");
fflush(gp);
///FILE POINTER FOR SECOND PLOT (PERFORMANCE GRAPH)
FILE * gp1 = popen("gnuplot", "w");
fprintf(gp1, "set terminal wxt size 600,400 \n");
fprintf(gp1, "set grid \n");
fprintf(gp1, "set title '%s' \n", "Performance");
fprintf(gp1, "set style line 1 lt 3 pt 7 ps 0.1 lc rgb 'green' lw 1 \n");
fprintf(gp1, "set style line 2 lt 3 pt 7 ps 0.1 lc rgb 'red' lw 1 \n");
fprintf(gp1, "plot '-' w p ls 1 \n");
for (int k = 0; k < epo.size(); k++) {
fprintf(gp1, "%f %f \n", epo[k], performance[k]);
}
fprintf(gp1, "e\n");
fflush(gp1);
system("pause");
//_pclose(gp);
return 0;
}
I too have been trying to learn simple (shallow) Neural Networks while avoiding any high level tools. I have tried to maintain some of my learning at this repository.