#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sstream>
#include <string>
#include <iostream>
#include <vector>
using namespace std;

#define BIAS                -1
#define ERROR_THRESHOLD     0.0002
#define LEARNING_RATE     0.1
#define COUNT_OF_TRAINSET 8

//计算布尔算术式:a + (b · c)
//定义神经网络的训练集

const double trainsets[COUNT_OF_TRAINSET][4]=
{
  1,0,1,1,//在这里,a=1,b=0,c=1,结果代入式子 a + (b · c),即为 1
  1,0,0,1,
  0,0,0,0,
  0,1,0,0,
  0,0,1,0,
  1,1,0,1,
  0,1,1,1,
  1,1,1,1,
};

//随机产生[0,1]的实数
inline double RandFloat()    
{
 return (rand())/(RAND_MAX+1.0);
}

//随机产生[-1,1]的实数
inline double RandomClamped()   
{
 return RandFloat() - RandFloat();
}

//S型函数:把(负无穷,正无穷)映射到实数域(0,1)上
double Sigmoid(double  input )
{
 return ( 1 / ( 1 + exp(-input / 1.0)));
}

//神经元结构
typedef struct SNeuron
{
 //这个神经元的输入个数
 int           num_input;
 
 //这个神经元各个输入的权
 vector<double> m_vecWeight;
 
 //这个神经元的激活阈值
 double          m_dActivation;
 
 //这个神经元的误差
 double          m_dError;
 
 //构造函数
 SNeuron(int NumInputs)
 {
  num_input=NumInputs+1;//添加了偏离值所以要加1
  m_dActivation=0;
  m_dError=0;
  for (int i=0; i<num_input; ++i)m_vecWeight.push_back(0);//RandomClamped());
  
 }
}SNeuron;


//神经网络层(所有层的抽象)
typedef struct SNeuronLayer
{
 //当前网络层的神经元数目
 int           m_iNumNeurons; 
 //各个神经元的数组
 vector<SNeuron>  m_vecNeurons;
 //构造函数
 SNeuronLayer(int NumNeurons, int NumInputsPerNeuron)
 {
  m_iNumNeurons=NumNeurons;
  for (int i=0; i<NumNeurons; ++i)m_vecNeurons.push_back(SNeuron(NumInputsPerNeuron)); 
 }
}SNeuronLayer;

 

 


int     m_iNumInputs;//有多少个输入
int     m_iNumOutputs;//有多少个输出
int     m_iNumHiddenLayers;//有多少个隐藏层
int     m_iNeuronsPerHiddenLyr;//隐藏层有多少个神经元
double      m_dErrorSum;//错误率,用来判断是否
int         m_iNumEpochs;//只是用来统计经过了多少代

//存储所有的网络层(顺序:输入层,隐藏层,输入层)
vector<SNeuronLayer> m_vecLayers;

 

//创建网络

void CreateNet()
{
 m_iNumInputs=3;
 m_iNumOutputs=1;
 m_iNumHiddenLayers=1;
 m_iNeuronsPerHiddenLyr=1;
 m_dErrorSum=9999;
 
 
 //创建输入层
 m_vecLayers.push_back(SNeuronLayer(m_iNeuronsPerHiddenLyr, m_iNumInputs));
 
 //创建隐藏层
 for (int i=0; i<m_iNumHiddenLayers-1; ++i)
  m_vecLayers.push_back(SNeuronLayer(m_iNeuronsPerHiddenLyr,m_iNeuronsPerHiddenLyr));
 
 //创建输出层
 m_vecLayers.push_back(SNeuronLayer(m_iNumOutputs, m_iNeuronsPerHiddenLyr));
 
}


//初始化网络
void InitializeNetwork()
{
 //对所有层
 for (int i=0; i<m_iNumHiddenLayers + 1; ++i)
 {
  //对所有神经元
  for (int n=0; n<m_vecLayers[i].m_iNumNeurons; ++n)
  {
   //对所有输入权
   for (int k=0; k<m_vecLayers[i].m_vecNeurons[n].num_input; ++k)
   {
    m_vecLayers[i].m_vecNeurons[n].m_vecWeight[k] =0;// RandomClamped();
   }
  }
 }
 
 m_dErrorSum  = 9999;
 m_iNumEpochs = 0;
 
}

 

//向前传递
vector<double> GoForward(vector<double> inputs)
{
 int cWeight = 0;
 vector<double> outputs; 
 
 //所有层都对权值加和起作用
 for (int i=0; i<m_iNumHiddenLayers + 1; ++i)
 { 
  if ( i > 0 )
  {
   inputs = outputs;
  }
  outputs.clear();
  
  cWeight = 0;
  
  //对所有的神经元
  
  SNeuronLayer CurrLayer=m_vecLayers[i];//当前网络层
  for (int n=0; n<CurrLayer.m_iNumNeurons; ++n)
  {
   SNeuron CurNeuron=CurrLayer.m_vecNeurons[n];//当前的网络层的神经元
   double netinput = 0;
   
   int count_input = CurNeuron.num_input;
   
   //对于每个输入的权重
   for (int k=0; k<count_input - 1; ++k)//不算上偏离值
   {
    //权值X输入的加和
    netinput += m_vecLayers[i].m_vecNeurons[n].m_vecWeight[k] * inputs[cWeight++];
   }
   
   //加上偏离值
   netinput += m_vecLayers[i].m_vecNeurons[n].m_vecWeight[count_input-1] * BIAS;//最后那个就是偏离值啦
   
   //更改激励值
   m_vecLayers[i].m_vecNeurons[n].m_dActivation =  Sigmoid(netinput);
   
   //保存每个神经元的输入
   outputs.push_back(m_vecLayers[i].m_vecNeurons[n].m_dActivation);
   
   cWeight = 0;
  }
 }
 
 return outputs;
}

//训练网络
bool NetworkTraining(vector< vector<double> > &SetIn,vector< vector<double> > &SetOut)
{
 //对所有的输入数据和期望的数据输入,网络会训练调整权值
 
 m_dErrorSum = 0;
 
 //对每一个训练集都进行输出层和隐藏层的训练
 for (int vec=0; vec<SetIn.size(); ++vec)
 {
  //产生实际的输入(主要和期望输出做对比)
  vector<double> outputs = GoForward(SetIn[vec]);

  /*****************开始调整输出层******************/
  for (int op=0; op<m_iNumOutputs; ++op)//此例是1
  {
   //计算当前某个输出向量的输出的误差
   double err = (SetOut[vec][op] - outputs[op]) * outputs[op] * (1 - outputs[op]);    
   
   //保存该隐藏层的误差
   m_vecLayers[1].m_vecNeurons[op].m_dError = err;
   
   //更新误差总值(当该总值低于一预设阈值时,即是完成训练)
   m_dErrorSum += (SetOut[vec][op] - outputs[op]) * (SetOut[vec][op] - outputs[op]);
   
   vector<SNeuron>::iterator curNrnHid = m_vecLayers[0].m_vecNeurons.begin();
   vector<double>::iterator curWeight ;
   
   //更新权重,不包括偏移    
   //此例是2次循环
   for(curWeight = m_vecLayers[1].m_vecNeurons[op].m_vecWeight.begin();
   curWeight != m_vecLayers[1].m_vecNeurons[op].m_vecWeight.end()-1;)
   {
    //基于BP规则计算新的权重
    *curWeight += err * LEARNING_RATE * curNrnHid->m_dActivation;
   //  cout<<curNrnHid->m_dActivation<<"\t";
    ++curNrnHid;
    ++curWeight;
   }

   
   //加上偏移值的权重
   *curWeight += err * LEARNING_RATE * BIAS;    
  }
  /*****************结束调整输出层******************/
  
  
  /*****************开始调整隐藏层******************/
  
  vector<SNeuron>::iterator curNrnHid;
  int n = 0;
  
  for(curNrnHid= m_vecLayers[0].m_vecNeurons.begin();curNrnHid != m_vecLayers[0].m_vecNeurons.end();++curNrnHid)
  {
   vector<SNeuron>::iterator curNrnOut;
   double err = 0;

   for(curNrnOut = m_vecLayers[1].m_vecNeurons.begin();curNrnOut != m_vecLayers[1].m_vecNeurons.end();++curNrnOut)
   {
    err += curNrnOut->m_dError * curNrnOut->m_vecWeight[n];
   }
   
   //计算误差
   err =err* curNrnHid->m_dActivation * (1 - curNrnHid->m_dActivation);    
   
   //基于误差计算每个权重
   for (int w=0; w<m_iNumInputs; ++w)
   {
      curNrnHid->m_vecWeight[w] += err * LEARNING_RATE * SetIn[vec][w];
   }
   
   //加上偏移量
   curNrnHid->m_vecWeight[m_iNumInputs] += err * LEARNING_RATE * BIAS;
 
   ++n;
  }
  /*****************结束调整隐藏层******************/
  
 
 }//结束当前一个训练集的训练
 return true;
}
double test(double a,double b,double c)
{
 vector<double> min;
 min.push_back(a);
 min.push_back(b);
 min.push_back(c);
 
 vector<double> mout=GoForward(min);
 return mout.at(0);
}


bool Train()
{
 
 vector<vector<double> > SetIn ;
 vector<vector<double> > SetOut;
 
 int i,j;
 for(i=0;i<COUNT_OF_TRAINSET;i++)
 {
  vector<double> tin;
  vector<double> tout;
  tin.push_back(trainsets[i][0]);
  tin.push_back(trainsets[i][1]);
  tin.push_back(trainsets[i][2]);
  
  tout.push_back(trainsets[i][3]);
  
  SetIn.push_back(tin);
  SetOut.push_back(tout);
  
 }
 
    //initialize all the weights to small random values
 InitializeNetwork();

 //一直训练到合标准为止
  while( m_dErrorSum > ERROR_THRESHOLD )
 {
    NetworkTraining(SetIn, SetOut);  
  ++m_iNumEpochs;
   
 }
 
 
 return true;
}

 

 

void main()
{
 clock_t a,b;
 a=clock();
 CreateNet();
 InitializeNetwork();
 Train();
  
 int i;
 char buf[1024];
 for(i=0;i<COUNT_OF_TRAINSET;i++)
 {

  sprintf(buf,"%d + (%d · %d) 结果约为: %f\n",
   (int)trainsets[i][0],(int)trainsets[i][1],(int)trainsets[i][2],
   test(trainsets[i][0],trainsets[i][1],trainsets[i][2]));
   cout<<buf;

 } b=clock();
 cout<<endl<<b-a;
system("pause");
}