Great Gods of C++, Help A Poor Programmer

M

Matthew

Recently, I began to write a program that demostrates memory
representation as a network of concepts. AI is a hobby of mine and I
just began to throw the program together. I didn't use the best style,
but it still should have worked. (You can guess what's coming next!)
It didn't! At the debug() call the program starts printing random
data. I am running Mac OS X 10.3 using XCode. Here is the file, I hope
it isn't too long. Thank you for your help.

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

class Node
{
public:
Node(string repr) { rep = repr;}
void addConnection(Node * newc, bool typer) {
connections.push_back(newc); types.push_back(typer); }
string getRep() { return rep; }
void setRep(string newr) { rep = newr; }
void activate(int strength);

void debug();
private:
string rep;
vector<bool> types;
vector<Node*> connections;
};

vector<Node> memory;
bool temp;

void Node::activate(int strength)
{
cout << strength << "\t" << rep << endl;
srand(time(NULL));
int ns = strength-(1 + rand() % (memory.size()-1));
if(ns <= 0)
return;
for(int i = 0; i < connections.size(); ++i)
{
if(types)
cout << "Isa: ";
else
cout << "P: ";
(*connections).activate(ns);
}
}

void Node::debug()
{
cout << "!DEBUGing " << rep << endl;
for(int i = 0; i < connections.size(); ++i)
{
cout << i << " " << (*connections).getRep() << endl;
}
cout << "DEBUG!" << endl;
}

void addNewMem();
void actMem();
void addMem();
void gatherConnections(Node * newMemory);
void dumpMem();

int main()
{
int choice = 0;;
for(;;)
{
cout << "\nWhat to do?" << endl;
cout << " (1) Add new memory" << endl;
cout << " (2) Activate memory" << endl;
cout << " (3) Exit" << endl;
cin >> choice;
getchar();
switch(choice)
{
case 1:
addNewMem();
break;
case 2:
actMem();
break;
case 3:
cout << "Positronic Brains Coming Soon To A Store Near You!" <<
endl;
return 0;
default:
cout << "Butthead" << endl;
return 0;
}
}
return 0;
}

void addNewMem()
{
char input;
while(true)
{
addMem();
cout << "Do you want to create another memory? [yn]: ";
cin >> input;
getchar();
switch(input)
{
case 'y':
break;
case 'n':
return;
default:
return;
}
}
}

void addMem()
{
dumpMem();
string repr;
cout << "Enter stimulus: ";
getline(cin, repr);
Node newMemory(repr);
memory.push_back(newMemory);
gatherConnections(&(memory[memory.size()-1]));
dumpMem();
}

void gatherConnections(Node * newMemory)
{
char input;
char input2;
string minput;
string typs;
bool typer;
cout << "Do you wish to make connections? [yn]: ";
cin >> input2;
getchar();
switch(input2)
{
case 'y':
break;
case 'n':
return;
default:
return;
}
while(true)
{
cout << "Enter name of memory to connect: ";
getline(cin, minput);
cout << "Enter type of connection [isa/p]: ";
getline(cin, typs);
if(typs == "isa")
typer = true;
else
typer = false;
for(int i = 0; i < memory.size(); ++i)
{
if(memory.getRep() == minput)
{
(*newMemory).addConnection(&memory, typer);
memory.addConnection(newMemory, typer);
(*newMemory).debug();
memory.debug();
break;
}
}
cout << "Add another connection? [yn]: ";
cin >> input;
getchar();
switch(input)
{
case 'y':
break;
case 'n':
return;
default:
return;
}
}
}

void actMem()
{
string toAct;
cout << "Enter stimulus: ";
getline(cin, toAct);
for(int i = 0; i < memory.size(); ++i)
{
if(memory.getRep() == toAct)
{
cout << "Begin: ";
memory.activate(memory.size());
break;
}
}
}

void dumpMem()
{
for(int i = 0; i < memory.size(); ++i)
{
cout << i << " " << &memory << " " << memory.getRep() << endl;
}
}
 
K

Kai-Uwe Bux

Matthew said:
Recently, I began to write a program that demostrates memory
representation as a network of concepts. AI is a hobby of mine and I
just began to throw the program together. I didn't use the best style,
but it still should have worked. (You can guess what's coming next!)
It didn't! At the debug() call the program starts printing random
data. I am running Mac OS X 10.3 using XCode. Here is the file, I hope
it isn't too long. Thank you for your help.

.....

Hi,


I compiled the program. Running the executable, I am confronted with a
menu. Could you save me some time and tell me, how I reproduce that output
you a worried about?


Best

Kai-Uwe Bux
 
D

David Hilsee

Matthew said:
Recently, I began to write a program that demostrates memory
representation as a network of concepts. AI is a hobby of mine and I
just began to throw the program together. I didn't use the best style,
but it still should have worked. (You can guess what's coming next!)
It didn't! At the debug() call the program starts printing random
data. I am running Mac OS X 10.3 using XCode. Here is the file, I hope
it isn't too long. Thank you for your help.

The biggest flaw that I see is that you used a std::vector when it was
inappropriate. Adding elements to a vector will invalidate all of the
pointers to the elements when it reallocates its internal buffer. The
standard may be even more picky about it, but that's your problem, in a
nutshell. The pointers in "vector<Node*> connections" could eventually
point to a region of memory that has been deallocated by the
std::vector<Node> memory, yielding undefined behavior that could explain
garbage output. Consider using another container for the "memory", like a
std::list<Node> or std::deque<Node>. It would probably be the easier to
transition to std::deque<Node>, since it is more like a std::vector<Node>
than std::list<Node>.
 
M

Matthew

Oops! Sorry about that.

The program basically builds a little (or big) memory repository that
can be used to demonstrate remembering or used in later problem
solving programs. In the beginning menu you can add new memories,
simulate remembering, or exit. When you choose the first option you
can enter in the stimulus, in this case the program uses text as
sensory input. For example you could enter "animal". It then asks to
make connections to other memories. Since this is the first memory
there is nothing to connect it to, so "n". It then prints a little
dubugging message about the memory location of the new memory and then
asks to make another memory. In this case we do so "y". Another
dubugging message and we repeat. To get the problem I mentioned enter
in this: (Note that there are two types of connections that are
basically the same, besides the name. There are "isa" connections or
"type of" and "p" connections or "property of". )

What to do?
(1) Add new memory
(2) Activate memory
(3) Exit
1
Enter stimulus: animal
Do you wish to make connections? [yn]: n
0 0x1800e00 animal
Do you want to create another memory? [yn]: y
0 0x1800e00 animal
Enter stimulus: fish
Do you wish to make connections? [yn]: y
Enter name of memory to connect: animal
Enter type of connection [isa/p]: isa
!DEBUGing fish (More debugging: basically looks at an
object and reports the connections)
0 animal
DEBUG!
!DEBUGing animal
0 fish
DEBUG!
Add another connection? [yn]: n
0 0x1801120 animal
1 0x1801144 fish
Do you want to create another memory? [yn]: y
0 0x1801120 animal
1 0x1801144 fish
Enter stimulus: swim
Do you wish to make connections? [yn]: y
Enter name of memory to connect: fish
Enter type of connection [isa/p]: p
!DEBUGing swim
0 fish
DEBUG!
!DEBUGing fish
((((The messed up data has been deleted as google groups doesn't like
it))))
^^^^^^^^^^^^^^^^^
uhoh
Here is the problem. Somehow the vector that contains the connections
in "fish" is corrupted. The same thing happens if we delete the calls
to debug() and activate a memory with the second menu option. (For
reference activating means you conceptualize the memory then activate
or "prime" memories connected. The farther from the source memory the
weaker the activation, until there is no more left.)

I hope this helps.
 
K

Kai-Uwe Bux

Matthew said:
Oops! Sorry about that.

The program basically builds a little (or big) memory repository that
can be used to demonstrate remembering or used in later problem
solving programs. In the beginning menu you can add new memories,
simulate remembering, or exit. When you choose the first option you
can enter in the stimulus, in this case the program uses text as
sensory input. For example you could enter "animal". It then asks to
make connections to other memories. Since this is the first memory
there is nothing to connect it to, so "n". It then prints a little
dubugging message about the memory location of the new memory and then
asks to make another memory. In this case we do so "y". Another
dubugging message and we repeat. To get the problem I mentioned enter
in this: (Note that there are two types of connections that are
basically the same, besides the name. There are "isa" connections or
"type of" and "p" connections or "property of". )

What to do?
(1) Add new memory
(2) Activate memory
(3) Exit
1
Enter stimulus: animal
Do you wish to make connections? [yn]: n
0 0x1800e00 animal
Do you want to create another memory? [yn]: y
0 0x1800e00 animal
Enter stimulus: fish
Do you wish to make connections? [yn]: y
Enter name of memory to connect: animal
Enter type of connection [isa/p]: isa
!DEBUGing fish (More debugging: basically looks at an
object and reports the connections)
0 animal
DEBUG!
!DEBUGing animal
0 fish
DEBUG!
Add another connection? [yn]: n
0 0x1801120 animal
1 0x1801144 fish
Do you want to create another memory? [yn]: y
0 0x1801120 animal
1 0x1801144 fish
Enter stimulus: swim
Do you wish to make connections? [yn]: y
Enter name of memory to connect: fish
Enter type of connection [isa/p]: p
!DEBUGing swim
0 fish
DEBUG!
!DEBUGing fish
((((The messed up data has been deleted as google groups doesn't like
it))))
^^^^^^^^^^^^^^^^^
uhoh
Here is the problem. Somehow the vector that contains the connections
in "fish" is corrupted. The same thing happens if we delete the calls
to debug() and activate a memory with the second menu option. (For
reference activating means you conceptualize the memory then activate
or "prime" memories connected. The farther from the source memory the
weaker the activation, until there is no more left.)

I hope this helps.

It does: when I try the sequence above, I get a segfault -- usually that
indicates access to memory that has been returned. As David Hilsee has
pointed out, this is a result of the re(al)location of std::vector<Node> as
it grows. I replaced the line

vector<Node> memory;

by

deque<Node> memory;

and now, it seems to work. The standard [23.2.1.3] requires that inserts at
the ends of a deque are not supposed to invalidate references to elements
of the deque although iterators are invalidated. The std::list<> container
would be safer in that iterators and references are most stable, but since
you are using the size() method it might not be the best choice for your
problem.


Best

Kai-Uwe Bux
 
M

Matthew

Thanks for your help, guys!


David Hilsee said:
The biggest flaw that I see is that you used a std::vector when it was
inappropriate. Adding elements to a vector will invalidate all of the
pointers to the elements when it reallocates its internal buffer. The
standard may be even more picky about it, but that's your problem, in a
nutshell. The pointers in "vector<Node*> connections" could eventually
point to a region of memory that has been deallocated by the
std::vector<Node> memory, yielding undefined behavior that could explain
garbage output. Consider using another container for the "memory", like a
std::list<Node> or std::deque<Node>. It would probably be the easier to
transition to std::deque<Node>, since it is more like a std::vector<Node>
than std::list<Node>.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top