So, in advance, I have to admit that this is not quite as "good" a question as what is otherwise found here. It's not about a weird error, or something I can't figure out to do. I just get weird output. I've spent around 2 days simplifying the code, trying to pin down the error. I really can't.

The project concerns simulating neural networks, so the two classes in the script are neurons and networks. The neurons need to know which other neurons they are linked to, so one of their properties is an array of pointers to other neurons in the network. When I was checking whether the networking was working alright, I noticed that it was not. The neurons have a public function called "introduction()" which causes them to write their address in the grid and the address of all their connections.

Since this is the simplified version, all neurons talk to all neurons, including themselves. An address of (100,100) means that the neuron hasn't been placed on the grid yet.

I will comment more at the bottom.

the "pre-amble":

using namespace std;
#define DEBUG

#include <cstdlib>

#ifndef DEBUG
#define SHOW(x)
#define PRINT(x)
#else

#include <iostream>
#include <fstream>
#include <iomanip>

ofstream output;
//output.open ("output.txt");

#define SHOW(x) \
output << #x << std::setprecision(4) << ":\t" << x << std::endl;
#define PRINT(x) \
output << x << std::endl;
#endif

The neuron-class:

class neuron
{
public:
    int threshold;
    bool type;
           
    neuron** connections;
    int nconnect;
    int i;
    int j;


    neuron();
    neuron(neuron** incconnctions, int incnconnect);
    ~neuron();
    void introduction();
           
};

neuron::neuron(): i(100),j(100)
{
//booh 
}

neuron::neuron(neuron** incconnctions, int incnconnect):
nconnect(incnconnect)
{
    PRINT("Constructing neuron");
    connections=new neuron*[nconnect];
    for (int i=0;i<nconnect; i++) 
    {
        connections[i]=incconnctions[i];
    }
    
    PRINT("Connections:");       
    for (int ii=0;ii<nconnect;ii++)
    {
        output<< (*connections[ii]).i<<","<<(*connections[ii]).j<<"\n";              
    }
}



neuron::~neuron()
{
//    output<< "Destroying neuron " << i << "," << j <<"\n";
    delete[] connections;
}

void neuron::introduction()
{

    output<<"My name is "<< i <<"," <<j<<"\n";

    PRINT("I am connected to:");

    for (int ii=0;ii<nconnect;ii++)
    {
        output<< (*connections[ii]).i<<","<<(*connections[ii]).j<<"\n";              
    }
}

The network class:

class network
{
  public:
         int dimensions[2];
         int nneurons;
         network(int* dimensions);
         ~network();
         neuron* neurons;
         neuron** connections;
};

network::network(int* incdimensions)
{                         
     for (int i=0;i<2;i++)
     { 
         dimensions[i]=incdimensions[i];
     }

     nneurons=dimensions[0]*dimensions[1];
     neurons=new neuron[nneurons];
     
     connections = new neuron*[nneurons];
     
     
    for (int j=0;j<dimensions[1];j++) 
    {
        for (int i=0;i<dimensions[0];i++) 
        {
            
            for (int k=0;k<nneurons;k++)
            {
                 connections[k]=&(neurons[k]);
            }
     

            neurons[i+ j*dimensions[0]]=neuron(connections, nneurons); //counting down along the columns
            
            neurons[i+ j*dimensions[0]].i=i;
            neurons[i+ j*dimensions[0]].j=j;
            
            PRINT("Asking directly:");
            
            for (int k=0;k<neurons[i+ j*dimensions[0]].nconnect;k++)
            {
            SHOW((*(neurons[i+ j*dimensions[0]].connections[k])).i);
            SHOW((*(neurons[i+ j*dimensions[0]].connections[k])).j);
            }
            
            neurons[i+ j*dimensions[0]].introduction();            
            
            PRINT("Post-intro:");       
            for (int ii=0;ii<nneurons;ii++)
            {
                output<< (*connections[ii]).i<<","<<(*connections[ii]).j<<"\n";              
            }
        }
    }
    delete[] connections;
    connections=0;

    PRINT("Leaving network constructor");
}

network::~network()
{
    delete[] neurons; 
}

Main:

int main()
{ 
    output.open ("output.txt");
       
    int dimensions[]={2,2}; //#rows,#columns
    
    network net(dimensions); 


    output.close();
    return 1;
}

When run, the program writes quite a lot, since there are several loops involved. However, it's pretty much the same for every loop, and it suffices to simply look at the last iteration:

Constructing neuron
Connections:
0,0
1,0
0,1
100,100
Asking directly:
(*(neurons[i+ j*dimensions[0]].connections[k])).i:	0
(*(neurons[i+ j*dimensions[0]].connections[k])).j:	0
(*(neurons[i+ j*dimensions[0]].connections[k])).i:	4066937
(*(neurons[i+ j*dimensions[0]].connections[k])).j:	0
(*(neurons[i+ j*dimensions[0]].connections[k])).i:	0
(*(neurons[i+ j*dimensions[0]].connections[k])).j:	1
(*(neurons[i+ j*dimensions[0]].connections[k])).i:	1
(*(neurons[i+ j*dimensions[0]].connections[k])).j:	1
My name is 1,1
I am connected to:
0,0
4066937,0
0,1
1,1
Post-intro:
0,0
1,0
0,1
1,1
Leaving network constructor

As can be seen (especially comparing with the code above), the address of the second neuron, instead of being (1,0) which is the correct value, is read, by the other neurons, as (4066937,0). I have no idea why. 4066937 is of course a somewhat random value, which will change for every run, but it is always the first coordinate of the second neuron that is wrong, no matter how many neurons I have in my network (though I haven't checked beyond 16). I also see that the address is read correctly when the "connections"-array has just been loaded into the neuron, but when I have exited the neuron-constructor and ask again, I get this same, wrong value.
I can not for the life of me see what is special about entrance 1 - I have even done a textsearch for all 1's to see if any were in some weird places.

can anyone spot it? please. I know this post is really long, and I would myself have preferred it shorther, since I might have been able to spot the problem myself then, but these seem to be the necessary ingredients.

Neuron (1,0) introduces itself correctly (as 1,0).

Thanks for reading all of it =)

Recommended Answers

All 5 Replies

That garbage value is most likely caused by an uninitialized variable.

Any time I see '**':

neuron** connections;

I cringe...

Have you considered using:

std::vector<std::vector<neuron> > connections;

instead?

yes, I agree, it's probably unintialized. but how it manages to do that within a loop is beyond me...
I hadn't considered the vectors. have never quite become friendly with them, so try to stay away from them.

how would I use them here? presumably there should be at least one * in your suggestion, since it is addresses that I want to pass to my neurons?

Are you somehow not dereferencing a pointer properly? This would result in displaying the physical memory address instead of the data stored at the address.

My friend, you are suffering through pointer hell. The best way to avoid this is to use the standard template library. Vectors are infinitely nicer than dynamically allocated arrays of pointers. In order to understand your code, I had to work through it. In the process, i utilized the standard template library. The code worked almost immediately after eliminating compiler errors. Here it is:

#include <iostream>
#include <vector>

class neuron
{
public:
    // Other members and constructors omitted

    std::vector<neuron*> connections;

    void connect( const std::vector<neuron*>& inconnections )
    {
        connections.clear();
        for( unsigned int i=0; i<inconnections.size(); i++ )
        {
            if( this == inconnections[i] )
                continue;
            connections.push_back( inconnections[i] );
        }
    }

    //Printing functions ommitted
};


class network
{
public:
    std::vector<neuron*> neurons;


    neuron*& slot( int i, int j )
    {
        return neurons[ i * w + j ];
    }

    network( int w, int h ): w(w), h(h)
    {
        neurons = std::vector<neuron*>( w * h, NULL );
        for( int i=0; i<h; i++ )
        {
            for( int j=0; j<w; j++ )
            {
                slot( i, j ) = new neuron( i, j );
            }
        }
        for( unsigned int i=0; i<neurons.size(); i++ )
            neurons[i]->connect( neurons );
    }

    // Destructor and printing functions ommitted
};

using namespace std;

int main()
{
    network net(2,2);
    net.printNetwork();
    return 0;
}

Outut:

Network structure: 
-------------------
My name is: [0,0]
I am connected to: 
0,1
1,0
1,1
My name is: [0,1]
I am connected to: 
0,0
1,0
1,1
My name is: [1,0]
I am connected to: 
0,0
0,1
1,1
My name is: [1,1]
I am connected to: 
0,0
0,1
1,0

There really isn't anything ground shaking here. I've just tried to eliminate some of the incredibly confusing pointer work. std::vectors are very nice, very powerful, and easily available. If you are coding in c++, you might as well use them. They are extremely fast, and it is nice to use containers that know how many items they contain

thanks =) a lot
is there some way of sponsoring daniweb? I'm beginning to owe pretty heavily in here, and while I do look in likely looking threads, I haven't yet found something I was comfortable responding to (or which hadn't already been solved) =)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.