I am working on a very simple feed forward neural network to practice my programming skills. There are 3 classes :
Neural::Net ; builds the network, feeds forward input values (no backpropagation for the moment)
Neural::Neuron ; has characteristics of the neuron (index, output, weight etc)
Neural::Connection ; a structure-like class that randomizes the weights and hold the output, delta weight etc..
The program is very basic: I build the network with 2 hidden layers and randomized weights, then ask it to feed forward the same input values.
My problem is: It is expected that the program ends up with different output values after every run, yet the output are always the same. I tried placing markers everywhere to understand why it is calculating the same thing over and over again but I can't put my finger on the error.
Here is the code:
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <vector>
#include "ConsoleColor.hpp"
using namespace std;
namespace Neural {
class Neuron;
typedef vector<Neuron> Layer;
// ******************** Class: Connection ******************** //
class Connection {
public:
Connection();
void setOutput(const double& outputVal) { myOutputVal = outputVal; }
void setWeight(const double& weight) { myDeltaWeight = myWeight - weight; myWeight = weight; }
double getOutput(void) const { return myOutputVal; }
double getWeight(void) const { return myWeight; }
private:
static double randomizeWeight(void) { return rand() / double(RAND_MAX); }
double myOutputVal;
double myWeight;
double myDeltaWeight;
};
Connection::Connection() {
myOutputVal = 0;
myWeight = Connection::randomizeWeight();
myDeltaWeight = myWeight;
cout << "Weight: " << myWeight << endl;
}
// ******************** Class: Neuron ************************ //
class Neuron {
public:
Neuron();
void setIndex(const unsigned int& index) { myIndex = index; }
void setOutput(const double& output) { myConnection.setOutput(output); }
unsigned int getIndex(void) const { return myIndex; }
double getOutput(void) const { return myConnection.getOutput(); }
void feedForward(const Layer& prevLayer);
void printOutput(void) const;
private:
inline static double transfer(const double& weightedSum);
Connection myConnection;
unsigned int myIndex;
};
Neuron::Neuron() : myIndex(0), myConnection() { }
double Neuron::transfer(const double& weightedSum) { return 1 / double((1 + exp(-weightedSum))); }
void Neuron::printOutput(void) const { cout << "Neuron " << myIndex << ':' << myConnection.getOutput() << endl; }
void Neuron::feedForward(const Layer& prevLayer) {
// Weight sum of the previous layer's output values
double weightedSum = 0;
for (unsigned int i = 0; i < prevLayer.size(); ++i) {
weightedSum += prevLayer[i].getOutput()*myConnection.getWeight();
cout << "Neuron " << i << " from prevLayer has output: " << prevLayer[i].getOutput() << endl;
cout << "Weighted sum: " << weightedSum << endl;
}
// Transfer function
myConnection.setOutput(Neuron::transfer(weightedSum));
cout << "Transfer: " << myConnection.getOutput() << endl;
}
// ******************** Class: Net *************************** //
class Net {
public:
Net(const vector<unsigned int>& topology);
void setTarget(const vector<double>& targetVals);
void feedForward(const vector<double>& inputVals);
void backPropagate(void);
void printOutput(void) const;
private:
vector<Layer> myLayers;
vector<double> myTargetVals;
};
Net::Net(const vector<unsigned int>& topology) : myTargetVals() {
assert(topology.size() > 0);
for (unsigned int i = 0; i < topology.size(); ++i) { // Creating the layers
myLayers.push_back(Layer(((i + 1) == topology.size()) ? topology[i] : topology[i] + 1)); // +1 is for bias neuron
// Setting each neurons index inside layer
for (unsigned int j = 0; j < myLayers[i].size(); ++j) {
myLayers[i][j].setIndex(j);
}
// Console log
cout << red;
if (i == 0) {
cout << "Input layer (" << myLayers[i].size() << " neurons including bias neuron) created." << endl;
myLayers[i].back().setOutput(1);
}
else if (i < topology.size() - 1) {
cout << "Hidden layer " << i << " (" << myLayers[i].size() << " neurons including bias neuron) created." << endl;
myLayers[i].back().setOutput(1);
}
else { cout << "Output layer (" << myLayers[i].size() << " neurons) created." << endl; }
cout << white;
}
}
void Net::setTarget(const vector<double>& targetVals) { assert(targetVals.size() == myLayers.back().size()); myTargetVals = targetVals; }
void Net::feedForward(const vector<double>& inputVals) {
assert(myLayers[0].size() - 1 == inputVals.size());
for (unsigned int i = 0; i < inputVals.size(); ++i) { // Setting input vals to input layer
cout << yellow << "Setting input vals...";
myLayers[0][i].setOutput(inputVals[i]); // myLayers[0] is the input layer
cout << "myLayer[0][" << i << "].getOutput()==" << myLayers[0][i].getOutput() << white << endl;
}
for (unsigned int i = 1; i < myLayers.size() - 1; ++i) { // Updating hidden layers
for (unsigned int j = 0; j < myLayers[i].size() - 1; ++j) { // - 1 because bias neurons do not have input
cout << "myLayers[" << i << "].size()==" << myLayers[i].size() << endl;
cout << green << "Updating neuron " << j << " inside layer " << i << white << endl;
myLayers[i][j].feedForward(myLayers[i - 1]); // Updating the neurons output based on the neurons of the previous layer
}
}
for (unsigned int i = 0; i < myLayers.back().size(); ++i) { // Updating output layer
cout << green << "Updating output neuron " << i << ": " << white << endl;
const Layer& prevLayer = myLayers[myLayers.size() - 2];
myLayers.back()[i].feedForward(prevLayer); // Updating the neurons output based on the neurons of the previous layer
}
}
void Net::printOutput(void) const {
for (unsigned int i = 0; i < myLayers.back().size(); ++i) {
cout << blue; myLayers.back()[i].printOutput(); cout << white;
}
}
void Net::backPropagate(void) {
}
}
int main(int argc, char* argv[]) {
vector<unsigned int> myTopology;
myTopology.push_back(3);
myTopology.push_back(4);
myTopology.push_back(2);
myTopology.push_back(2);
cout << myTopology.size() << endl << endl; // myTopology == {3, 4, 2 ,1}
vector<double> myTargetVals= {0.5,1};
vector<double> myInputVals= {1, 0.5, 1};
Neural::Net myNet(myTopology);
myNet.feedForward(myInputVals);
myNet.printOutput();
return 0;
}
Edit: I figured that the bias neuron in the input layer was correctly set to output 1 while the ones in the hidden layers are set to 0 and I fixed that. But the outputs are still the same every run. I did the math on a sheet of paper and it works out. Here is the output (Color coded for clarity) :
I have expected the values to be random just like the weights. Shouldn't that be the case ? I am confused.
I found my mistake. I thought that rand() initialized its seed automatically. I knew it was a dumb thing. I added srand(time(NULL)); at the beginning of the program and now it works as it should.
Related
What is wrong with this code? It detects whether I've reached the coordinates of a monster but only one of them, or the closest one at least. If I travel to other coordinates it doesn't tell me the monster has appeared. Don't know why because I am looping through the monster vector every time I type 'north'.
Here is the code.
Monster Class:
class Monster
{
public:
std::vector<std::string> names;
std::vector<double> posx; // North - South
std::vector<double> posy; // East - West
bool compareCoords(double monsterPosX, double monsterPosY);
void cMonster(std::string monsterName, double monsterPosX, double monsterPosY);
void randomSpawn();
protected:
private:
};
compareCoords to detect whether a monster already exists at those coordinates and the cMonster (create monster) functions:
void Monster::cMonster(std::string monsterName, double monsterPosX, double monsterPosY)
{
if (compareCoords(monsterPosX, monsterPosY) == false)
{
names.push_back(monsterName);
posx.push_back(monsterPosX);
posy.push_back(monsterPosY);
std::cout << "Monster " << monsterName << " has been created at X: " << monsterPosX << " Y: " << monsterPosY << std::endl;
}
}
bool Monster::compareCoords(double monsterPosX, double monsterPosY)
{
for (unsigned int i = 0; i < posx.size(); i++)
{
if (monsterPosX == posx[i] && monsterPosY == posy[i])
{
return true;
}
}
return false;
}
Main:
int main()
{
srand(time(0));
Monster newenemy;
Character newplayer;
newenemy.cMonster("Weezo", 1, 0);
newenemy.cMonster("Weezo", 2, 0);
newplayer.posx.push_back(0);
newplayer.posy.push_back(0);
home:
std::cout << "-->> ";
std::string userInput;
std::cin.clear();
getline(std::cin, userInput);
if (!userInput.compare("north"))
{
newplayer.headNorth();
for (unsigned int i = 0; i < newenemy.names.size(); i++)
{
if (newplayer.posx[i] == newenemy.posx[i] && newplayer.posy[i] == newenemy.posy[i])
{
std::cout << "A " << newenemy.names[i] << " has appeared." << std::endl;
}
}
}
else if (!userInput.compare("south"))
{
newplayer.headSouth();
for (unsigned int i = 0; i < newenemy.posx.size(); i++)
{
if (newplayer.posx[i] == newenemy.posx[i] && newplayer.posy[i] == newenemy.posy[i])
{
std::cout << "A " << newenemy.names[i] << " has appeared." << std::endl;
}
}
}
else
{
std::cout << "You have entered an invalid command." << std::endl;
}
}
^ As you can see here, it shows when I'm at the coordinates of Gorilla but not the second monster, Donald Trump. It just ignores the second one.
I've been stuck here for hours, I don't understand what could be wrong. Thank you!
I have a problem in my OOP homework. I have to code a 1 v 1 battle.
This is a Survival Game where in the player fights continuously with enemies until the player dies. The Player gets stronger as he advances through. The enemy also grows stronger every round.
I have created two Classes, The Unit and the Spawner.
We cannot use Inheritance nor Polymorphism.
We Have to use only the simple definition of the class.
My problem is that i cannot think of a SIMPLE way to make the class Spawner spawn a stronger enemy every round.
I have thought of overloading the Unit's Contructor but i have trouble manipulating that.
Would anyone please help?
Here's my Unit Header file (Unit.h):
#pragma once
#include <string>
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
// Class Types
const string CLASS_WARRIOR = "Warrior" ;
const string CLASS_ASSASSIN = "Assassin";
const string CLASS_MAGE = "Mage" ;
// Class Choices
const int CHOICE_WARRIOR = 1;
const int CHOICE_ASSASSIN = 2;
const int CHOICE_MAGE = 3;
// Multipliers
const double MULTIPLIER_DAMAGE = 0.50f;
const double MULTIPLER_HEAL = 0.30f;
// Advantage
const bool ADVANTAGE = true;
// Win Bonus
const int BONUS_THREE = 3;
const int BONUS_FIVE = 5;
// Minimum and maximum values
const int HIT_RATE_MAX = 80;
const int HIT_RATE_MIN = 20;
const int DAMAGE_MIN = 1;
// Hit or miss
const bool ATTACK_HIT = true;
const bool ATTACK_MISS = false;
class Unit
{
public:
// Constructors
Unit(string name, int classChoice);
// Getters and setters
string getName();
string getClass();
int getHp();
int getMaxHp();
int getPower();
int getVitality();
int getAgility();
int getDexterity();
int getDamage();
int getHeal();
int getBonusDamage();
bool getFirstToAttack();
bool getHit();
void setClassStats(const int classChoice);
// Primary Actions
void attack(Unit* target);
// Secondary Actions
void check(const Unit* target); // Inspects the enemy
void lvlUp(); // Grants this Unit Bonus Stats on Victory
private:
// Info
string mName;
string mClass;
// Basic Stats
int mHp;
int mMaxHp;
int mPower;
int mVitality;
int mAgility;
int mDexterity;
// Derived Stats
int mDamage;
int mHitrate;
int mHeal;
int mBonusDamage;
// Miscellaneous
bool mAdvantage; // If the player has the advantage
string mTargetClass;// This Unit keeps in mind the class of this Unit's Opponent for reference
int mChanceOfHit; // The random chance if the attack will Hit/Miss
bool mFirstToAttack;//if this unit will attack first
bool mHit; // if the attack is a hit or miss
};
Here's my Unit.cpp file (Unit.cpp):
#include "Unit.h"
Unit::Unit(string name, int classChoice)
{
mName = name;
setClassStats(classChoice);
}
string Unit::getName()
{
return mName;
}
string Unit::getClass()
{
return mClass;
}
int Unit::getHp()
{
return mHp;
}
int Unit::getMaxHp()
{
return mMaxHp;
}
int Unit::getPower()
{
return mPower;
}
int Unit::getVitality()
{
return mVitality;
}
int Unit::getAgility()
{
return mAgility;
}
int Unit::getDexterity()
{
return mDexterity;
}
int Unit::getDamage()
{
return mDamage;
}
int Unit::getHeal()
{
return mHeal;
}
int Unit::getBonusDamage()
{
return mBonusDamage;
}
bool Unit::getFirstToAttack()
{
return mFirstToAttack;
}
bool Unit::getHit()
{
return mHit;
}
void Unit::setClassStats(const int classChoice)
{
if (classChoice == CHOICE_WARRIOR) {
mClass = CLASS_WARRIOR;
mMaxHp = 20;
mHp = mMaxHp;
mPower = 15;
mVitality = 10;
mAgility = 7;
mDexterity = 7;
return;
}
else if (classChoice == CHOICE_ASSASSIN) {
mClass = CLASS_ASSASSIN;
mMaxHp = 15;
mHp = mMaxHp;
mPower = 17;
mVitality = 8;
mAgility = 12;
mDexterity = 10;
return;
}
else if (classChoice == CHOICE_MAGE) {
mClass = CLASS_MAGE;
mMaxHp = 30;
mHp = mMaxHp;
mPower = 12;
mVitality = 12;
mAgility = 9;
mDexterity = 8;
return;
}
throw exception("Error! Class not part of this game. ");
}
void Unit::attack(Unit * target)
{
// Determine Whether the attack will Hit/Miss Based on the hit rate
mChanceOfHit = rrand() % 100 + 1;
if (mChanceOfHit > mHitrate) {
mHit = ATTACK_MISS;
return;
}
// Deducts the targets Hp by the Damage given by this Unit (if the attack didn't miss)
target->mHp -= mDamage;
mHit = ATTACK_HIT;
// if target HP is negative, set it to zero
if (target->mHp < 0) target->mHp = 0;
}
void Unit::check(const Unit * target)
{
// The Unit Keeps in Mind his target's Class
if (target->mClass == CLASS_WARRIOR) mTargetClass = CLASS_WARRIOR;
else if (target->mClass == CLASS_ASSASSIN) mTargetClass = CLASS_ASSASSIN;
else if (target->mClass == CLASS_MAGE) mTargetClass = CLASS_MAGE;
// Checks if the Unit is Advantageous Against his Target
if (mClass == CLASS_WARRIOR) {
if (target->mClass == CLASS_ASSASSIN) mAdvantage = ADVANTAGE;
else mAdvantage = false;
}
else if (mClass == CLASS_ASSASSIN) {
if (target->mClass == CLASS_MAGE) mAdvantage = ADVANTAGE;
else mAdvantage = false;
}
else if (mClass == CLASS_MAGE) {
if (target->mClass == CLASS_WARRIOR) mAdvantage = ADVANTAGE;
else mAdvantage = false;
}
// Determine if this Unit Will Attack first
if (mAgility >= target->mAgility) mFirstToAttack = true;
else mFirstToAttack = false;
// Determines Damage, Bonus Damage ( If Applicable ), and Hit Rate Based on targets stats
mDamage = mPower - target->mVitality;
if (mDamage < DAMAGE_MIN) mDamage = DAMAGE_MIN;
mBonusDamage = mDamage * MULTIPLIER_DAMAGE;
// Evaluates Damage Based on advantage
if (mAdvantage) mDamage += mBonusDamage;
mHitrate = ((float)mDexterity / (float)target->mAgility) * 100;
// Clamps the Hit Rate within the Hit Rate Range
if (mHitrate > HIT_RATE_MAX) mHitrate = HIT_RATE_MAX;
else if (mHitrate < HIT_RATE_MIN) mHitrate = HIT_RATE_MIN;
}
void Unit::lvlUp()
{
// Determine Win Bonus Based on the target that he kept in mind
if (mTargetClass == CLASS_WARRIOR) {
mMaxHp += BONUS_THREE;
mVitality += BONUS_THREE;
}
else if (mTargetClass == CLASS_ASSASSIN) {
mAgility += BONUS_THREE;
mDexterity += BONUS_THREE;
}
else if (mTargetClass == CLASS_MAGE) {
mPower += BONUS_FIVE;
}
// Heals the player 30% of his Maximum HP
mHeal = mMaxHp * MULTIPLER_HEAL;
mHp += mHeal;
}
Here's my Spawner Header file (Spawner.h):
#pragma once
#include "Unit.h"
class Spawner
{
public:
Spawner();
~Spawner();
void spawn(Unit*& unit);
private:
Unit* mUnit;
int mRandomClass;
};
Here's my Spawner.cpp file (Spawner.cpp):
#include "Spawner.h"
Spawner::Spawner()
{
}
Spawner::~Spawner()
{
delete mUnit;
mUnit = NULL;
}
void Spawner::spawn(Unit *& unit)
{
mRandomClass = rand() % 3 + 1;
unit = new Unit("Enemy", mRandomClass);
mUnit = unit;
}
And finally here is my main.cpp:
#include "Unit.h"
#include "Spawner.h"
// Create player
Unit* createPlayer();
// Display Stats
void displayStats(Unit* unit);
// Play 1 round
void playRound(Unit*player, Unit* enemy);
// Simulate 1 attack (implement Higher agility gets to atttack first)
void combat(Unit* player, Unit* enemy);
void main()
{
srand(time(NULL));
Unit* player = createPlayer();
Unit* enemy = NULL;
Spawner *spawner = new Spawner();
int round = 1;
while (true) {
cout << "Round " << round << endl;
spawner->spawn(enemy);
player->check(enemy);
enemy->check(player);
playRound(player, enemy);
// if player is dead, end the game
if (player->getHp() == 0) break;
// else, add stats
player->lvlUp();
delete enemy;
enemy = NULL;
cout << "You defeted an enemy" << endl;
system("pause>nul");
system("cls");
round++;
}
cout << "You were defeted! " << endl;
cout << "You survived until Round " << round << endl;
displayStats(player);
delete player;
player = NULL;
delete spawner;
spawner = NULL;
system("pause>nul");
system("cls");
}
Unit* createPlayer()
{
Unit* unit = NULL;
string name;
int classChoice;
cout << "Enter your Name: ";
getline(cin, name);
system("cls");
cout << "Pick a class: " << endl
<< "\t [ 1 ] Warrior" << endl
<< "\t [ 2 ] Assassin" << endl
<< "\t [ 3 ] Mage" << endl
<< endl;
cin >> classChoice;
while (classChoice > 3 || classChoice <= 0) {
cout << "INVALID INPUT! Please try again" << endl;
cout << "Pick a class: " << endl
<< "\t [ 1 ] Warrior" << endl
<< "\t [ 2 ] Assassin" << endl
<< "\t [ 3 ] Mage" << endl
<< endl;
cin >> classChoice;
}
unit = new Unit(name, classChoice);
return unit;
}
void displayStats(Unit* unit)
{
cout << "=========================================================================================" << endl
<< "Name: " << unit->getName() << " \t \t \t HP: " << unit->getHp() << " / " << unit->getMaxHp() << endl
<< "Class: " << unit->getClass() << endl
<< "==========================================================================================" << endl
<< "POW: " << unit->getPower() << endl
<< "VIT: " << unit->getVitality() << endl
<< "AGI: " << unit->getAgility() << endl
<< "DEX: " << unit->getDexterity() << endl
<< endl;
}
void playRound(Unit*player, Unit* enemy)
{
while (player->getHp() > 0 && enemy->getHp() > 0) {
displayStats(player);
displayStats(enemy);
system("pause>nul");
combat(player, enemy);
system("cls");
}
}
void combat(Unit* player, Unit* enemy)
{
if (player->getFirstToAttack()) {
player->attack(enemy);
if (player->getHit() == ATTACK_MISS) cout << player->getName() << "'s Attack Missed! " << endl;
else if (player->getHit() == ATTACK_HIT) cout << player->getName() << " dealt " << player->getDamage() << " Damage" << endl;
system("pause>nul");
if (enemy->getHp() == 0) return;
enemy->attack(player);
if (enemy->getHit() == ATTACK_MISS) cout << enemy->getName() << "'s Attack Missed! " << endl;
else if (enemy->getHit() == ATTACK_HIT) cout << enemy->getName() << " dealt " << enemy->getDamage() << " Damage" << endl;
system("pause>nul");
return;
}
else if (enemy->getFirstToAttack()) {
enemy->attack(player);
if (enemy->getHit() == ATTACK_MISS) cout << enemy->getName() << "'s Attack Missed! " << endl;
else if (enemy->getHit() == ATTACK_HIT) cout << enemy->getName() << " dealt " << enemy->getDamage() << " Damage" << endl;
system("pause>nul");
if (player->getHp() == 0) return;
player->attack(enemy);
if (player->getHit() == ATTACK_MISS) cout << player->getName() << "'s Attack Missed! " << endl;
else if (player->getHit() == ATTACK_HIT) cout << player->getName() << " dealt " << player->getDamage() << " Damage" << endl;
system("pause>nul");
return;
}
}
Add a "level" to the Unit class, and use the level to increase the stats of the unit (for example level 2 could mean the stats are multiplied by 1.5 or some such). Pass the level as an argument to the constructor similar to the units class.
You need to make your spawner aware of how many enemies it has spawned:
// this belongs into your class definition, it should start at zero
int mCurrentSpawn;
So set it to zero in your constructor:
Spawner::Spawner()
{
mCurrentSpawn = 0;
}
Then reference it when you spawn an enemy:
void Spawner::spawn(Unit *& unit)
{
mRandomClass = rand() % 3 + 1;
unit = new Unit("Enemy", mRandomClass);
mUnit = unit;
mCurrentSpawn++;
int levelUps = mCurrentSpawn - 1;
while(levelUps > 0)
{
mUnit->lvlUp();
levelUps--;
}
}
So I am working on an implementation of a backprop neural network :
I made this 'NEURON' class , as every beginner in neural network do .
However, I am having weird results : you see, when the dataset is small (like in the case of a XOR function, where there can be only 4 possible permutations (00, 11, 01, 10) for the dataset), the output neuron gives me very close result, no matter how many training iteration (epoch) takes place.
Ex: 1 XOR 1 gives me 0.987, and 1 XOR 0 gives me 0.986, shouldn't they be far apart ?
Here is the class code, in case :
#pragma once
#include <vector>
#include <iostream>
#include "Math.h"
#include "RandomizationUtils.h"
using namespace std;
class ClNeuron
{
public:
enum NEURON_TYPE { NEURON_TYPE_INPUT=1,NEURON_TYPE_HIDDEN=2,NEURON_TYPE_OUTPUT=3 };
private:
static const int CONST_DEFAULT_INPUT_NUMBER_PER_NEURON = 20;
static const double CONST_DEFAULT_MOMENTUM_VALUE = 0.4;
//Connection between 2 neurons
struct NEURON_CONNECTION
{
double m_weight;
double m_data;
//Last modification done to the weight
double m_weight_last_delta;
double m_momentum_value;
ClNeuron* m_source_neuron;
ClNeuron* m_target_neuron;
};
//Initialization function
void Init(unsigned long p_uid,NEURON_TYPE p_type);
bool m_initialized;
//All of the output connection of this neuron
vector<NEURON_CONNECTION*> m_output_connections;
//Al of the input connection of this neuron
vector<NEURON_CONNECTION*> m_input_connections;
//Tmp internal result buffer (containing all weights multiplicated by their inputs)
double m_result_buffer;
//special weight that always has an input of 1.0
NEURON_CONNECTION m_bias;
public:
//the type of this neuron
NEURON_TYPE m_type;
ClNeuron(NEURON_TYPE p_type);
ClNeuron(unsigned long p_uid,NEURON_TYPE p_type);
ClNeuron(unsigned long p_uid);
ClNeuron();
//Connect this neuron's output to another / others neurons' input
bool AddOutputConnection(ClNeuron* p_neuron);
//This neuron got a request to have a new input
NEURON_CONNECTION* InputConnectionRequest(ClNeuron* p_source_neuron);
//Tell the neuron to fire the sum of the processed inputs
double Fire();
//Tell the neuron to fire a particular data
double Fire(double p_data);
//Function updating all of the current neuron's weight of the OUTPUT connections , depending on an error ratio
void UpdateWeights(double p_wanted_output);
//Sum all the weight * their respective inputs into an internal buffer
void ProcessInputs();
//Print neuron & connections & weights
void PrintNeuronData();
//Unique ID of this neuron
unsigned long m_uid;
//This neuron's calculated error_delta
double m_error_gradient;
};
ClNeuron::NEURON_CONNECTION* ClNeuron::InputConnectionRequest(ClNeuron* p_neuron)
{
NEURON_CONNECTION* connection = new NEURON_CONNECTION;
if(!connection)
{
cout << "Error creating new connection, memory full ?" << endl << flush;
return NULL;
}
connection->m_weight = GetRandomDouble(-1,1);
connection->m_data = 0;
connection->m_momentum_value = CONST_DEFAULT_MOMENTUM_VALUE;
connection->m_source_neuron = p_neuron;
connection->m_target_neuron = this;
m_input_connections.push_back(connection);
return connection;
}
bool ClNeuron::AddOutputConnection(ClNeuron* p_neuron)
{
//If the remote neuron accept the us as a new input, then we add it to output list
NEURON_CONNECTION* connection = p_neuron->InputConnectionRequest(this);
if(!connection)
{
return false;
}
m_output_connections.push_back(connection);
return true;
}
double ClNeuron::Fire()
{
return Fire(m_result_buffer);
}
double ClNeuron::Fire(double p_data)
{
if(m_output_connections.size()==0)
{
cout << "Final neuron " << m_uid << " return " << p_data << endl;
return p_data;
}
for(unsigned long i=0;i<m_output_connections.size();i++)
{
m_output_connections[i]->m_data = p_data;
}
return 1;
}
void ClNeuron::ProcessInputs()
{
m_result_buffer = 0;
for(unsigned long i=0;i<m_input_connections.size();i++)
{
m_result_buffer += m_input_connections[i]->m_weight * m_input_connections[i]->m_data;
}
m_result_buffer += m_bias.m_weight ;
//sigmoid the sum
m_result_buffer = Sigmoid(m_result_buffer);
}
void ClNeuron::UpdateWeights(double p_wanted_output)
{
//Update weights from neuron to all of its inputs NOTE : p_wanted_output is the output of THIS neuron (in case their is many output neuron in the network)
if(m_type == NEURON_TYPE_OUTPUT)
{
m_error_gradient = (p_wanted_output - m_result_buffer) * SigmoidDerivative(m_result_buffer);
//Adjust the bias of this neuron
double weight_delta = 1 * m_error_gradient * 1 ;
double momentum = m_bias.m_weight_last_delta * m_bias.m_momentum_value;
m_bias.m_weight += weight_delta + momentum;
m_bias.m_weight_last_delta = weight_delta;
}
else if(m_type == NEURON_TYPE_HIDDEN)
{
double error_deriative = SigmoidDerivative(m_result_buffer);
double tmpBuffer = 0.00;
for(unsigned long i=0;i<m_output_connections.size();i++)
{
tmpBuffer += (m_output_connections[i]->m_target_neuron->m_error_gradient * m_output_connections[i]->m_weight);
}
m_error_gradient = error_deriative * tmpBuffer;
//Adjust the weights for this neuron's OUTPUT connections
for(unsigned long i=0;i<m_output_connections.size();i++)
{
double weight_delta = 1 * m_output_connections[i]->m_target_neuron->m_error_gradient * m_result_buffer ;
double momentum = m_output_connections[i]->m_weight_last_delta * m_output_connections[i]->m_momentum_value;
m_output_connections[i]->m_weight += weight_delta + momentum;
m_output_connections[i]->m_weight_last_delta = weight_delta;
}
//Adjust the bias of this neuron
double weight_delta = 1 * m_error_gradient * 1 ;
double momentum = m_bias.m_weight_last_delta * m_bias.m_momentum_value;
m_bias.m_weight += weight_delta + momentum;
m_bias.m_weight_last_delta = weight_delta;
}
if(m_type == NEURON_TYPE_INPUT)
{
//Adjust the weights for this neuron's OUTPUT connections
for(unsigned long i=0;i<m_output_connections.size();i++)
{
double weight_delta = 1 * m_output_connections[i]->m_target_neuron->m_error_gradient * m_result_buffer ;
double momentum = m_output_connections[i]->m_weight_last_delta * m_output_connections[i]->m_momentum_value;
m_output_connections[i]->m_weight += weight_delta + momentum;
m_output_connections[i]->m_weight_last_delta = weight_delta;
}
}
}
void ClNeuron::PrintNeuronData()
{
cout << endl << "========================================" << endl;
cout << "Neuron #" << m_uid << " has " << m_input_connections.size() << " input connection" << endl << endl;
for(unsigned long i=0;i<m_input_connections.size();i++)
{
cout << "----> " << "conn." << i << " | Src ID: " << m_input_connections[i]->m_source_neuron->m_uid << " | W: "<< m_input_connections[i]->m_weight << " | D: "<< m_input_connections[i]->m_data << " | RB : " << m_result_buffer << " | EF: " << endl;
}
cout << "Neuron #" << m_uid << " has " << m_output_connections.size() << " output connection" << endl << endl;
for(unsigned long i=0;i<m_output_connections.size();i++)
{
cout << "----> " << "conn." << i << " | Dst ID: " << m_output_connections[i]->m_target_neuron->m_uid << " | W: "<< m_output_connections[i]->m_weight << " | D: "<< m_output_connections[i]->m_data << " | RB : " << m_result_buffer << " | EF: " << endl;
}
cout << endl << "========================================" << endl;
}
void ClNeuron::Init(unsigned long p_uid,NEURON_TYPE p_type)
{
m_initialized = false;
m_output_connections.clear();
m_input_connections.clear();
m_input_connections.reserve(CONST_DEFAULT_INPUT_NUMBER_PER_NEURON);
m_type = p_type;
m_uid = rand() % RAND_MAX;
m_result_buffer = 0;
m_bias.m_weight = GetRandomDouble(-1,1);
m_bias.m_data = 0;
m_bias.m_momentum_value = CONST_DEFAULT_MOMENTUM_VALUE;
m_bias.m_source_neuron = NULL;
m_bias.m_target_neuron = this;
m_initialized = true;
}
ClNeuron::ClNeuron(unsigned long p_uid,NEURON_TYPE p_type)
{
Init(p_uid,p_type);
}
ClNeuron::ClNeuron(NEURON_TYPE p_type)
{
Init(0,p_type);
}
ClNeuron::ClNeuron(unsigned long p_uid)
{
Init(p_uid,NEURON_TYPE_HIDDEN);
}
ClNeuron::ClNeuron()
{
Init(0,NEURON_TYPE_HIDDEN);
}
The problem was the BIAS weight value for each neuron :
More precisely, the error gradient was always 0 for the bias, (causing the weight_delta of 0), which finally was causing the bias not to update its output weights.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
//Class for a card deck:
class CardDeck
{
public:
CardDeck(int theValue, string theSuit);
CardDeck(){}
// Setters--Don't think we will need
void setValue(int theValue);
void setSuit(string theSuit);
// Getters
int getValue();
string getSuit();
private:
int value;
string suit;
};// end CardDeck class
int main()
{
int i = 0;
int gameInPlay = 1;
const string DR = "Dragons";
const string MG = "Mages";
const string WR = "Warriors";
const string CF = "Confessors";
vector<CardDeck> startDeck(52);
vector<CardDeck> tempCards(1);
// Dragons Suit
for (i = 0; i < 13; i++)
{
startDeck[i].setValue(i - 12);
startDeck[i].setSuit("Dragons");
//startDeck[i].setValue(i+1);
// startDeck[i].setSuit("Dragons");
}
// Mages Suit
for (i = 13; i < 26; i++)
{
startDeck[i].setValue(i - 12);
startDeck[i].setSuit("Mages");
}
for (i = 26; i < 39; i++)
{
startDeck[i].setValue(i - 25);
startDeck[i].setSuit("Warriors");
}
for (i = 39; i < 52; i++)
{
startDeck[i].setValue(i - 38);
startDeck[i].setSuit("Confessors");
}
// Output for de-bug
cout << "The first card is " << startDeck[0].getValue() << " of " << startDeck[0].getSuit() << endl;
cout << "The second card is " << startDeck[1].getValue() << " of " << startDeck[1].getSuit() << "\n\n";
//****************************************************************************
// Shuffle the deck
int shuffleTimes = (rand() % 120) + 1;
// Need to shuffle a random # of times, else deck is
// "shuffled" in same order every time
for (int i = 0; i < shuffleTimes; i++)
{
srand(time(0));
for (i = 0; i < startDeck.size(); i++)
{
int second = rand() % startDeck.size();
CardDeck temp = startDeck[i];
startDeck[i] = startDeck[second];
startDeck[second] = temp;
}
}
//*******************************************************************************
// Verify cards are shuffled for de-bug
cout << "After shuffling:\n Value \t Suit\n";
// Output for de-bug
cout << "The first card is " << startDeck[0].getValue() << " of " << startDeck[0].getSuit() << endl;
cout << "The second card is " << startDeck[1].getValue() << " of " << startDeck[1].getSuit() << endl;
// Creat human deck
vector<CardDeck> humanDeck(26);
for (i = 0; i< 26; i++)
{
humanDeck[i] = startDeck[i];
}
// Creat computer deck
vector<CardDeck> computerDeck(26);
for (i = 0; i< 26; i++)
{
computerDeck[i] = startDeck[i + 26];
}
// Output for de-bug
cout << "The first human card is " << humanDeck[0].getValue() << " of " << humanDeck[0].getSuit() << endl;
cout << "The second human card is " << humanDeck[1].getValue() << " of " << humanDeck[1].getSuit() << "\n\n";
cout << "The first computer card is " << computerDeck[0].getValue() << " of " << computerDeck[0].getSuit() << endl;
cout << "The second computer card is " << computerDeck[1].getValue() << " of " << computerDeck[1].getSuit() << "\n\n";
getchar();
return 0;
} // end main
// Functions for CardDeck class
CardDeck::CardDeck(int theValue, string theSuit)
{
value = theValue;
suit = theSuit;
}
void CardDeck::setValue(int theValue)
{
value = theValue;
}
void CardDeck::setSuit(string theSuit)
{
suit = theSuit;
}
int CardDeck::getValue()
{
return value;
}
string CardDeck::getSuit()
{
return suit;
}
Obviously not done with the game, and I am new to C++ and programming so any help will do
I would like some help trying to figure out how to get only positive numbers instead of negative. Also would like to figure out why they return values of the first two outputs are always the same.
Thank you
You probably meant to do this:
for (i = 0; i < 13; i++)
{
startDeck[i].setValue(i+1);
startDeck[i].setSuit("Dragons");
//startDeck[i].setValue(i+1);
// startDeck[i].setSuit("Dragons");
}
Otherwise, startDeck[i].setValue(i-12); will set negative values for i < 12, which is most of that loop.
I'm wondering why you have the correct code there and commented out...what was the issue with it?
I'm working on a program involving Dijkstra's algorithm.
After searching long and far, I have only found help pertaining to Dijkstra's algorithm using Queues or Heaps, however, I am not using these. I have been tasked to used a vector of pointers to Vertex objects (a custom class I have defined).
I have attempted to convert the Queue pseudo code (from my textbook) to the best of my ability below:
void Dijkstra(vector<Vertex*> & V, int startNum)
{
vector<Vertex*> sortedVertices = V;
sortedVertices[startNum]->setDV(0);
insertionSort(sortedVertices);
while(sortedVertices.size() != 0)
{
sortedVertices[sortedVertices.size() - 1]->setKnown(true);
sortedVertices.pop_back();
insertionSort(sortedVertices);
Vertex * v = V[1]; // Will always bring the first element off the list
v->setKnown(true);
for(int m = 0; m < sortedVertices->getAdjacentVertices().size(); m++)
{
int dist = getAdjacentVertices()[m].getWeight();
if((sortedVertices[1].getDV() + dist) < sortedVertices[m+1]->getAdjacentVertices()[m].getDV())
{
//WE WILL DECREASE THE VALUE HERE by finding the distance between two vertices
cout << "It works so far" << endl;
// BOOK has this, somehow need to change it: w.path = v
}
}
}
}
However, when I attempt to compile, I keep receiving the following errors:
Main.cpp: In function 'void Dijkstra(std::vector<Vertex*>&, int)':
Main.cpp:154:42: error: base operand of '->' has non-pointer type 'std::vector<Vertex*>'
Main.cpp:156:44: error: 'getAdjacentVertices' was not declared in this scope
Main.cpp:157:35: error: request for member 'getDV' in 'sortedVertices.std::vector<_Tp, _Alloc>::operator[]<Vertex*, std::allocator<Vertex*> >(1ul)', which is of pointer type '__gnu_cxx::__alloc_traits<std::allocator<Vertex*> >::value_type {aka Vertex*}' (maybe you meant to use '->' ?)
Main.cpp:157:99: error: '__gnu_cxx::__alloc_traits<std::allocator<Edge> >::value_type' has no member named 'getDV'
I am trying to reduce the amount of Code in this post, but if need to be, my entire code is below:
Main.cpp:
#include "Vertex.h"
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <fstream>
using namespace std;
void shortestPath(vector<Vertex> & v);
template <typename Comparable>
void insertionSort(vector<Comparable> & a);
template <typename Comparable>
void insertionSort( vector<Comparable> & a, int left, int right );
///overload the less than operator in order to use the stl sort for vector
///print out the path for each vertex
int main()
{
/////READ ALL THE STUFF INTO THE GRAPH////
ifstream file;
file.open("graph.txt");
cout << "Opening file..." << endl;
if(!file)
{
cout << "System failed to open file.";
}
else
{
cout << "File successfully opened" << endl;
}
int numVertices;
int numEdges;
int num;
int adjacentVertex;
int weight;
file >> numVertices;
cout << "The number of vertices that are being read into the graph from the file: " << numVertices;
cout << endl;
vector<Vertex*> vertices;
//vector<Vertex> vertices(numVertices + 1);
Vertex * newVertex;
vertices.push_back(NULL);
cout << "SIZE: " << vertices.size() << endl;
cout << "NUM VERTICES: " << numVertices << endl;
for(int i=1;i < numVertices + 1; i++)
{
file >> numEdges;
cout << "At vertex " << i << " the number of edges is " << numEdges << endl;
newVertex = new Vertex();
//Using the i counter variable in the outer for loop to identify
//the what vertex what are currently looking at in order to read in the correct adjacent vertex and weight
cout << "LENGTH OF VERTICES[i]: " << vertices.size() << endl;
newVertex->setVertexNum(i);
//newVertex.setVertexNum(i);
for(int j=1;j<=numEdges;j++)
{
file >> adjacentVertex;
cout << "The adjacent vertex is: " << adjacentVertex << endl;
file >> weight;
cout << "The weight is: " << weight << endl;
cout << endl;
newVertex->setAdjacentVertex(adjacentVertex, weight);
}
//cout << "LENGTH OF VERTICES[i]: " << vertices.size() << endl;
vertices.push_back(newVertex);
}
file.close();
vector<Vertex*> sortedVertices = vertices;
insertionSort(sortedVertices);
cout << "SIZE: " << vertices.size() << endl;
for(int i=0;i<vertices.size();i++)
{
cout << "V" << i << ": ";
cout << endl;
if(vertices[i] != NULL)
{
cout << "DV Value: " << vertices[i]->getDV();
cout << endl;
cout << "Known Value: " << vertices[i]->getKnown();
cout << endl;
}
}
cout << "Sorted: " << endl;
for(int i=0;i<sortedVertices.size();i++)
{
cout << "V" << i << ": ";
cout << endl;
if(vertices[i] != NULL)
{
cout << "DV Value: " << sortedVertices[i]->getDV();
cout << endl;
cout << "Known Value: " << sortedVertices[i]->getKnown();
cout << endl;
}
}
//CALL THE SHORTEST PATH FUNCTION ON THE GRAPH/////
}
/*
const bool myFunction(const Vertex & x, const Vertex & y)
{
return (x.getDV() >= y.getDV());
}
*/
bool operator < (const Vertex & v1, const Vertex & v2)
{
return v1.getDV() > v2.getDV();
}
void Dijkstra(vector<Vertex*> & V, int startNum)
{
vector<Vertex*> sortedVertices = V;
sortedVertices[startNum]->setDV(0);
insertionSort(sortedVertices);
while(sortedVertices.size() != 0)
{
sortedVertices[sortedVertices.size() - 1]->setKnown(true);
sortedVertices.pop_back();
insertionSort(sortedVertices);
Vertex * v = V[1]; // Will always bring the first element off the list
v->setKnown(true);
for(int m = 0; m < sortedVertices->getAdjacentVertices().size(); m++)
{
int dist = getAdjacentVertices()[m].getWeight();
if((sortedVertices[1].getDV() + dist) < sortedVertices[m+1]->getAdjacentVertices()[m].getDV())
{
//WE WILL DECREASE THE VALUE HERE by finding the distance between two vertices
cout << "It works so far" << endl;
// BOOK has this, somehow need to change it: w.path = v
}
}
}
}
////////INSERTION SORT////////////
template <typename Comparable>
void insertionSort( vector<Comparable> & a )
{
for( int p = 1; p < a.size( ); ++p )
{
Comparable tmp = std::move( a[ p ] );
int j;
for( j = p; j > 0 && tmp < a[ j - 1 ]; --j )
a[ j ] = std::move( a[ j - 1 ] );
a[ j ] = std::move( tmp );
}
}
template <typename Comparable>
void insertionSort( vector<Comparable> & a, int left, int right )
{
for( int p = left + 1; p <= right; ++p )
{
Comparable tmp = std::move( a[ p ] );
int j;
for( j = p; j > left && tmp < a[ j - 1 ]; --j )
a[ j ] = std::move( a[ j - 1 ] );
a[ j ] = std::move( tmp );
}
}
Vertex.h:
#include "Edge.h"
#include <vector>
#include <climits>
#include <fstream>
using namespace std;
class Vertex
{
private:
int vertexNum; //number of the vertex for identification purposes
int degree;
bool known;
vector<Edge> adjacentVertices; //vector of vertices that are adjacent to the vertex we are currently looking at
int dv; //distance
int pv; //previous vertex
Vertex *vertex;
public:
Vertex()
{
dv = INT_MAX;
known = false;
}
void setKnown(bool Known)
{
known = Known;
}
bool getKnown()
{
return known;
}
void setVertexNum(int VertexNum)
{
vertexNum = VertexNum;
}
void setDegree(int Degree)
{
degree = Degree;
}
vector<Edge> & getAdjacentVertices()
{
return adjacentVertices;
}
int getVertexNum()
{
return vertexNum;
}
int getDegree()
{
return degree;
}
int getDV() const
{
return dv;
}
int setDV(int Dv)
{
dv = Dv;
}
void setAdjacentVertex(int AdjacentVertex, int Weight)
{
Edge newEdge;
newEdge.setWeight(Weight);
newEdge.setAdjVertex(AdjacentVertex);
adjacentVertices.push_back(newEdge);
}
friend ostream & operator <<(ostream & outstream, Vertex *vertex)
{
outstream << vertex->getVertexNum() << endl;
outstream << vertex->getDegree() << endl;
outstream << vertex->getKnown() << endl;
vector<Edge> E = vertex->getAdjacentVertices();
for(int x=0;x<E.size();x++)
{
outstream << E[x].getAdjVertex() << endl;
outstream << E[x].getWeight() << endl;
}
return outstream;
}
friend bool operator < (const Vertex & v1, const Vertex & v2);
};
Edge.h:
#include <cstdlib>
class Edge
{
private:
int adjVertex; //represents the vertex that the edge leads to
int weight;
public:
Edge()
{
adjVertex = 0;
weight = 0;
}
void setWeight(int Weight)
{
weight = Weight;
}
void setAdjVertex(int adjacent)
{
adjVertex = adjacent;
}
int getAdjVertex()
{
return adjVertex;
}
int getWeight()
{
return weight;
}
};
From g++ to English:
Main.cpp: In function 'void Dijkstra(std::vector<Vertex*>&, int)':
Main.cpp:154:42: error: base operand of '->' has non-pointer type 'std::vector<Vertex*>'
Main.cpp:156:44: error: 'getAdjacentVertices' was not declared in this scope
Main.cpp:157:35: error: request for member 'getDV' in 'sortedVertices.std::vector<_Tp, _Alloc>::operator[]<Vertex*, std::allocator<Vertex*> >(1ul)', which is of pointer type '__gnu_cxx::__alloc_traits<std::allocator<Vertex*> >::value_type {aka Vertex*}' (maybe you meant to use '->' ?)
Main.cpp:157:99: error: '__gnu_cxx::__alloc_traits<std::allocator<Edge> >::value_type' has no member named 'getDV'
Explanation:
for(int m = 0; m < sortedVertices->getAdjacentVertices().size(); m++) <- this is 154. sortedVertices is not a pointer. It is a std::vector of some pointers.
int dist = getAdjacentVertices()[m].getWeight(); <- 156. What is getAdjacentVertices?
sortedVertices[1].getDV() <- 157 sortedVertices[1] is a pointer. Look at operator[]
sortedVertices[m+1]->getAdjacentVertices() is a vector of Edge. Edge does not have a getDV() method defined.
Is this really your code?
As an author you should not have trouble understanding the error messages. Those are simple mistakes, that took 5 minutes for a stranger to understand. You need to put more effort in understanding what you write, and what compiler tells you. Or get some sleep to get some focus.
I would also suggest to spend some time working out what std::vector really is and how to understand std::vector<Vertex*> vector_of_vertices; object.
vector<Vertex*> sortedVertices = V;
sortedVertices[startNum]->setDV(0)
Here you create variable of type vector<Vertex*> on the stack. This is not a pointer. This is a container containing pointers of type Vertex* and that's completely different. You use -> operator which is only used on pointers.