Im writing a program that simulates a vacuum cleaning a room. There is an initial state of dirty spots and I want to use various AI algorithms to find the best paths to clean the room. By making the algorithms separate from the actual problem I think my solution will be very modular.
Each algorithm only knows about States. Each state can be expanded to children states. Here is my first algorithm, UniformCost:
#include<iostream>
#include<set>
class State {
public:
State(){}
bool operator< (const State& s) const;
bool isGoal();
std::set<State> expand();
};
class UniformCost {
private:
State startState;
std::set<State> closedList; //list of no repeated states
public:
State start;
void setStart(State s);
State* getSolution();
};
void UniformCost::setStart(State st) {
start = st;
}
State* UniformCost::getSolution() {
closedList.insert(start);
while(!closedList.empty()) {
State cur = *closedList.begin();
if(cur.isGoal()) {
return &cur;
}
closedList.erase(cur);
std::set<State> children = cur.expand();
for (std::set<State>::iterator i = children.begin(); i != children.end(); ++i) {
closedList.insert(*i);
}
}
}
My main application creates the initial Node that is a child class of State.
class Node : public State {
public:
std::pair<int,int> loc;
int g_val;
std::set<std::pair<int,int> > dirt;
std::vector<char> path;
bool isGoal() {
return dirt.size() == 0;
}
bool operator< (const State& s) const {
Node n = (Node) s;
if(loc == n.loc) {
return false;
}
if(g_val <= n.g_val) {
return true;
}
return false;
}
std::set<State> expand() {
std::set<State> ret;
return ret;
}
};
How can I override the operator in the Node class that is expecting a "operator< (const State&)"? Or a more general question, how would I handle future "casting" of States?
Related
I have a working implementation for the classic "Queue using two stacks" data structure in C++ and am wondering what the best software engineering practice would be for handling const correctness.
The peek() function returns the value at the front of the queue, which may mean that we need to pop everything from one stack and copy it to the other. One way to use the copy function is to cast the constness away for this as shewn below. Is there a better way?
class MyQueue {
stack <int> s1;
stack <int> s2;
public:
MyQueue() {
}
void push(int x) {
s1.push(x);
}
void copy()
{
while (!s1.empty()) {
s2.push(s1.top());
s1.pop();
}
}
int pop() {
int res;
if (s2.empty()) copy();
if (! s2.empty()) {
res = s2.top();
s2.pop();
}
return res;
}
int peek() const {
if (s2.empty()) ((MyQueue*) (this))->copy();
return s2.top();
}
bool empty() const {
return s1.empty() && s2.empty();
}
};
It's better to adjust the design a bit, so that s2 is never empty unless the queue is empty. Then the difficult question goes away, and the code gets simpler, too:
class MyQueue {
stack <int> s1;
stack <int> s2;
public:
MyQueue() {
}
void push(int x) {
if (s2.empty()) {
// queue is empty
s2.push(x);
} else {
s1.push(x);
}
}
int pop() {
int res = s2.pop();
if (s2.empty())
copy();
return res;
}
int peek() const {
return s2.top();
}
bool empty() const {
return s2.empty();
}
private:
void copy()
{
while (!s1.empty()) {
s2.push(s1.pop());
}
}
};
I have a decision tree that includes node and answer that leads us to another nodes. Answers begin with ":" and nodes are the rest.
I have to do a function that delete a subtree from a specific node. For example If I want to delete node "brand?", I want that after that the tree will print from car-color? to blue-is-beautiful
I don't success doing this deletion in the right way because I think I have to delete also the answer red and don't know how to do that.
class Answer
{
public:
string ans;
Node* son;
Answer(string s, Node* p) { ans = s; son = p; }
};
class Node
{
public:
Node(string v) { isLeaf = true; value = v; }
list<Answer*> answersList;
string value;
bool isLeaf;
};
void Tree::del(Node* t)
{
if (t->isLeaf)
return;
for (list<Answer*>::iterator it = t->answersList.begin(); it != t->answersList.end(); it++)
{
del((*it)->son);
delete((*it));
*it = NULL;
}
if (t)
{
delete t;
t = NULL;
}
}
Now having understood the problems (highly restrictive requirements and what is causing your code to fail), I now have an answer for you.
The issue is, that you need to remove the node you've deleted from the collection it is stored in.
For this purpose, you need to use an alternate version of your search to detect, which child has the value you are looking for.
Due to the requirement of 'not adding any additional functions', there are two ways to go about this.
One is to employ recursion using an anonymous function, the other is 'check the child prior to diving into it'.
The following code fragment uses a DIY-Lambda-Functor, which employs the recursion method.
void Tree::deletefromNode(string val)
{
bool didFindValue = false;
std::function<bool (Node *, const string &)> functor;
class Functor
{
public:
Functor(Tree *owner, bool &didFindValue) : owner(owner), didFindValue(didFindValue)
{
}
bool deleteFromNode(Node *node, const string &value)
{
bool foundMatch = false;
if (node)
{
foundMatch = (node->value == value);
if (!foundMatch)
{
for (list<Answer*>::iterator it = node->answersList.begin(); it != node->answersList.end();)
{
Node *childNode = (*it)->son;
if (deleteFromNode(childNode, value))
{
owner->del(childNode);
it = node->answersList.erase(it);
didFindValue = true;
}
else
it++;
}
}
}
return foundMatch;
}
private:
Tree *owner;
bool &didFindValue;
};
Functor(this, didFindValue).deleteFromNode(root, val);
if (didFindValue)
cout << "Value not found" << endl;
}
So, as part of my assignment in Computer Science, which was to read tweets and put them into a custom Dictionary, I had to, you guessed it, create a dictionary. However, during testing with the dictionary, I encountered an error which I have been unable to fix, despite hours of attempted troubleshooting. I have narrowed it down, and determined that the error lies on line 144, somewhere in the statement cout<<j.get("name").getFront()->getText();, but I have been unable to determine which part of this causes issues, even when breaking it down by parts, except that it begins when I add in the ->getText(), however I heavily suspect that the problem starts earlier on.
I am sorry if I am not too specific, or if I ramble too much, I have just been having trouble with this for a while, and am beginning to get frustrated.
I understand not all the execution or style is the best, so I may ask you to refrain from leaving comments on the way things are done, unless it may directly relate to the problem at hand.
Thank you for any and all help.
/*********************************************************************************************************************
* [REDACTED] *
* CS 101-- Project 4 (Hashing Twitter) *
* This program stores Twitter posts in a hash table * *
*********************************************************************************************************************/
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;
class tweet {
private:
string create_at;
string text;
string screen_name;
public:
string getCreate_at() {
return create_at;
};
string getText() {
return text;
};
string getScreen_name() {
return screen_name;
};
void setCreate_at(string c) {
create_at=c;
};
void setText(string c) {
text=c;
};
void setScreen_name(string c) {
screen_name=c;
};
};
class LinkedList {
public:
tweet* getFront() {
return top;
};
LinkedList* getNext() {
return next;
};
void setNext(LinkedList* c) {
next = c;
};
void setTweet(tweet c) {
top = &c;
};
void setTweet(tweet* c) {
top = c;
};
void insertFront(tweet c) {
LinkedList temp;
temp.setTweet(top);
temp.setNext(next);
this->setTweet(c);
this->setNext(&temp);
};
tweet* removeFront() {
tweet* temp;
temp = top;
if(next != NULL){
top = next->getFront();
if(next->getNext() != NULL)
next = next->getNext();
}
return temp;
};
private:
tweet* top;
LinkedList* next;
};
class HashTable {
private:
vector<LinkedList> store [256];//access by firstcharacter of name as index of array then search through vector linearly until find key
LinkedList getLinkedList(string c) {
vector<LinkedList> temp=store[(int)c.c_str()[0]];
for(int i =0;i<temp.size();i++) {
if(temp.at(i).getFront()->getScreen_name()==c) {
return temp.at(i); //gets list of tweets
}
};
};
bool keyExists(string c) {
vector<LinkedList> temp = store[(int)c.c_str()[0]];
for(int i =0;i<temp.size();i++) {
if(temp.at(i).getFront()->getScreen_name()==c) {
return true; //gets list of tweets
}
};
return false;
};
void insertTweet(tweet c){
if(keyExists(c.getScreen_name())){
getLinkedList(c.getScreen_name()).insertFront(c);
} else {
LinkedList temp;
temp.setTweet(c);
store[c.getScreen_name().c_str()[0]].push_back(temp);
}
};
public:
void put(tweet c) {
insertTweet(c);
};
LinkedList get(string key) {
return getLinkedList(key);
};
bool contains(string key) {
return keyExists(key);
};
void remove(string key) {
vector<LinkedList> temp=store[key.c_str()[0]];
for(int i =0;i<temp.size();i++) {
if(temp.at(i).getFront()->getScreen_name()==key) {
temp.erase(temp.begin()+i); //gets list of tweets
}
};
};
};
HashTable parser(string filename) {
//backslashes
};
int main(int argc, char *argv[])
{
tweet hello;
hello.setText("hello");
hello.setScreen_name("user");
hello.setCreate_at("10211997");
tweet heyo;
heyo.setText("heyo");
heyo.setScreen_name("name");
heyo.setCreate_at("79912101");
LinkedList jerome;
jerome.insertFront(hello);
cout<<jerome.getFront()->getText()<<endl;
jerome.insertFront(heyo);
cout<<jerome.removeFront()->getText()<<endl;
HashTable j;
j.put(heyo);
cout<<j.get("name").getFront()->getText();
}
You are getting the addresses of temporaries:
void insertFront(tweet c) {
LinkedList temp;
temp.setTweet(top);
temp.setNext(next);
this->setTweet(c); //should be &c, but c is a temporary!
this->setNext(&temp); //temp is a temporary!
};
Also, in HashTable, you need put and insertTweet to have a tweet& parameter.
Finally, still in insertTweet, you should pass the address of c to setTweet.
Note that this code is very fragile, as you will have dangling pointers as soon as the tweet objects go out of scope.
So I have a project of which I want to switch to Astar due to speed reasons.
But C++ is not my strongest point. Could anyone help me (or tell me how to do the..) converting the algorythm from Dijkstra to Astar?
I found this Astar implementation:
http://code.google.com/p/a-star-algorithm-implementation/
But I don't know how to use it with my existing code.
Here is the graph file which got the algorithm:
#include "Graph.h"
#include <iostream>
#include <algorithm>
#include <stack>
Graph::Graph(void)
{
}
Graph::~Graph(void)
{
while(!mNodes.empty())
{
delete mNodes.back();
mNodes.pop_back();
}
}
void Graph::addNode(int name, bool exists, Node** NodeID )
{
Node* pStart = NULL;
mNodes.push_back(new Node(name,exists));
std::vector<Node*>::iterator itr;
itr = mNodes.begin()+mNodes.size()-1;
pStart = (*itr);
if(exists == true)pStart->DoesExist_yes();
*NodeID = pStart;
}
void Graph::connect_oneway(Node* pFirst, Node* pSecond, int moveCost)
{
if(pFirst != NULL && pSecond != NULL)
{
pFirst->createEdge(pSecond, moveCost);
}
}
#define MAX_NODES (32768)
#define MAX_CONNECTIONS (5)
#include <time.h>
int * Graph::findPath_r(Node* pStart, Node* pEnd)
{
int *arr = new int[MAX_NODES+2];
for (int i=0; i<MAX_NODES; i++)
arr[i] = -1;
arr[0] = 0;
if(pStart == pEnd)
{
return arr;
}
std::vector<Node*> openList;
openList.push_back(pStart);
Node* pCurrNode = NULL;
while(!openList.empty())
{
//Get best node from open list (lowest F value).
//Since we sort the list at the end of the previous loop we know
//the front node is the best
pCurrNode = openList.front();
//Exit if we're are the goal
if(pCurrNode == pEnd)
break;
//Remove the node from the open list and place it in the closed
openList.erase(openList.begin());
pCurrNode->setClosed(true); //We use a flag instead of a list for speed
//Test all of the edge nodes from the current node
std::vector<Edge*>* pEdges = pCurrNode->getEdges();
Node* pEdgeNode = NULL;
for(std::vector<Edge*>::iterator i = pEdges->begin(); i != pEdges->end(); ++i)
{
pEdgeNode = (*i)->pNode;
//If it's closed we've already analysed it
if(!pEdgeNode->getClosed() && pCurrNode->DoesExist() == true)
{
if(!inList(pEdgeNode,&openList))
{
openList.push_back(pEdgeNode);
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
else
{
//If this is a better node (lower G cost)
if(pEdgeNode->getGCost() > pCurrNode->getGCost()+(*i)->moveCost)
{
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
}
}
}
//Place the lowest F cost item in the open list at the top, so we can
//access it easily next iteration
std::sort(openList.begin(), openList.end(), Graph::compareNodes);
}
//Make sure we actually found a path
if(pEnd->getParent() != NULL)
{
//Output the path
//Use a stack because it is LIFO
std::stack<Node*> path;
while(pCurrNode != NULL)
{
path.push(pCurrNode);
pCurrNode = pCurrNode->getParent();
}
int counter = 0;
arr[1] = 0;
while(!path.empty())
{
arr[counter+2] = path.top()->getName();
counter++;
arr[1] += path.top()->getGCost();
path.pop();
}
arr[0] = counter;
return arr;
}
return arr;
}
bool Graph::inList(Node* pNode, std::vector<Node*>* pList)
{
for(std::vector<Node*>::iterator i = pList->begin(); i != pList->end(); ++i)
{
if((*i) == pNode)
{
return true;
}
}
return false;
}
bool Graph::compareNodes(Node* pFirst, Node* pSecond)
{
return pFirst->getFCost() < pSecond->getFCost();
}
void Graph::reset(void)
{
for(std::vector<Node*>::iterator i = mNodes.begin(); i != mNodes.end(); ++i)
{
(*i)->reset();
}
}
The function for finding the path is this one:
Graph::findPath_r
What I really want to do is preserve the edges (because they decide if the road is both or one-way).
Here are the other files:
Graph.h
#ifndef _GRAPH_H_
#define _GRAPH_H
#include "Node.h"
class Graph
{
public:
Graph(void);
~Graph(void);
//void addNode(int name, bool exists);
void addNode(int name, bool exists, Node** NodeID );
void connect_oneway(int ppFirst, int ppSecond, int moveCost);
void connect_oneway(Node* pFirst, Node* pSecond, int moveCost);
//int * findPath_r(int start, int end);
int * findPath_r(Node* pStart, Node* pEnd);
void reset(void);
private:
void findNodesx(int firstName, Node** ppFirstNode);
bool inList(Node* pNode, std::vector<Node*>* pList);
static bool compareNodes(Node* pFirst, Node* pSecond);
std::vector<Node*> mNodes;
};
#endif
Node.h
#ifndef _NODE_H_
#define _NODE_H_
#include <string>
#include <vector>
//Forward declare Node so Edge can see it
class Node;
struct Edge
{
Edge(Node* node, int cost) : pNode(node), moveCost(cost){}
Node* pNode;
int moveCost;
};
class Node
{
public:
Node(void);
Node(int name, bool exists);
~Node(void);
void createEdge(Node* pTarget, int moveCost);
void setGCost(int cost);
void setClosed(bool closed);
void setParent(Node* pParent);
int getGCost(void);
int getFCost(void);
bool getClosed(void);
Node* getParent(void);
int getName(void);
bool DoesExist(void);
bool DoesExist_yes(void);
std::vector<Edge*>* getEdges(void);
void calcFCost(void);
void reset(void);
private:
int mGCost;
int mTotal;
bool mClosed;
Node* mpParent;
int mName;
bool mHeur;
std::vector<Edge*> mEdges;
};
#endif
Node.cpp
#include "Node.h"
Node::Node(void)
{
}
Node::Node(/*const std::string&*/int name, bool exists) : mGCost(0), mTotal(0), mClosed(false), mpParent(NULL), mName(name), mHeur(exists)
{
}
Node::~Node(void)
{
while(!mEdges.empty())
{
delete mEdges.back();
mEdges.pop_back();
}
}
int Node::getName(void)
{
return mName;
}
void Node::createEdge(Node* pTarget, int moveCost)
{
mEdges.push_back(new Edge(pTarget, moveCost));
}
void Node::setClosed(bool closed)
{
mClosed = closed;
}
bool Node::getClosed(void)
{
return mClosed;
}
std::vector<Edge*>* Node::getEdges(void)
{
return &mEdges;
}
int Node::getGCost(void)
{
return mGCost;
}
void Node::setGCost(int cost)
{
mGCost = cost;
}
void Node::calcFCost(void)
{
mTotal = mGCost;
}
void Node::setParent(Node* pParent)
{
mpParent = pParent;
}
int Node::getFCost(void)
{
return mTotal;
}
bool Node::DoesExist(void)
{
return mHeur;
}
bool Node::DoesExist_yes(void)
{
mHeur = true;
return true;
}
Node* Node::getParent(void)
{
return mpParent;
}
void Node::reset(void)
{
mGCost = 0;
mTotal = 0;
mClosed = false;
mpParent = NULL;
}
You mentioned a library on GoogleCode. It is node clear what you want to do with, and I think the best is to write your implementation yourself.
First, you should know that Dijsktra is a special case of A*. In A*, you have an heuristic, named h; A* = possible implementation of Dijsktra when h is the null function.
Then, about your implementation, let's start with Node. It will need the following functions:
constructor, destructor
create/get edge
set/get parent
set/is closed (for speed)
set/get GCost
set/get FCost
set/is obstacle (name way more descriptive than 'DoesExist')
set/get position
reset
// optional method:
get name
Hopefully, this part of your code won't change a lot. The heuristic code will be placed in the pathfinder. The Edge class is left untouched.
Now the big one: Graph. You won't need to delete any of your public methods.
You will need a heuristic method. For the implementation which will be described, you will need an admissible consistent heuristic:
it must not over-estimate the distance to the goal (admissible)
it must be monotone (consistent)
The general case signature is int getHCost(Node* node);. If you always return 0, you will have a Dijsktra algorithm, which is not what you want. Here we will take the euclidiean distance between the node and the goal. Slower to compute than manhattan distance, but better results. You can change this afterwards.
int getHCost(Node* node, Note* goal);
This implies you must place your nodes in the 3d space. Note that the heuristic is a heuristic, ie, an estimation of the distance.
I won't write the code. I will write some pseudo-code adapted to your situation. The original pseudocode is located on the Wikipedia A* page. This pseudo-code is your findPath_r function:
function A*(start,goal)
set all nodes to not closed // The set of nodes already evaluated.
openset = {start} // The set of tentative nodes to be evaluated, initially containing the start node
start.gcost = 0 // Cost from start along best known path.
// Estimated total cost from start to goal through y.
start.fcost = start.gcost + getHCost(start, goal)
while openset is not empty
current = the node in openset having the lowest f_cost (usually the first if you use a sorted list)
if current == goal
return construct_path(goal)
remove current from openset
current.closed = true
for each neighbor in (node connected by edge in current.edges) // Here is the condition for one-way edges
if neighbor.closed or neighbor.obstacle
continue
gcost = current.gcost + dist_between(current,neighbor) // via edge distance
if neighbor not in openset
add neighbor to openset
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
else if gcost < neighbor.gcost
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
update neighbor position in openset
return failure
function construct_path(current_node)
std::vector<Node*> path
while current_node != 0
path.push_front(current_node)
current_node = current_node.parent
return path
The implementation above use one-way edges.
You were able to write Dijsktra algorithm in C++, so writing this pseudocode in C++ shouldn't be a problem.
Second part, performances. First, measure ;).
I have some hints that can improve performances:
use a memory pool for allocation deallocation
use an intrusive list for the open list (you can also make it auto-sorted with this technique)
I advise you to read A* for beginners, which is a useful reading, even if you don't use tilemap.
I'm developing a LRU-cache in C++, using boost mutexes and locks, in a multi-threaded environment.
The architecture is based on a boost::unordered_map + a lock-free-queue
Insertions work in non-blocking mode (try_lock), but removals should lock the map and proceed.
The problem is that very rarely, the cache-access deadlocks in the removal.
.h
typedef boost::function<std::string ( const std::string &key )> LoaderFunction;
class ListNode;
struct CacheEntry {
CacheEntry(std::string key="", std::string value="");
ListNode * createLruListNode() const;
ListNode * getLruListNode() const;
virtual ~CacheEntry();
const std::string key;
const std::string value;
private:
ListNode ** listNodePP;
};
struct ListNode {
ListNode(const CacheEntry* entry = NULL);
~ListNode();
void setCacheEntry(const CacheEntry* entry);
const CacheEntry * getCacheEntry();
void setDirty();
private:
const CacheEntry * cacheEntry;
bool dirty;
};
typedef LockFreeQueue<ListNode*> List;
typedef boost::unordered_map
< const string , const CacheEntry * >
Cache;
typedef Cache::iterator CacheIter;
.cpp
#include "LockFreeQueue.h"
#include <unistd.h>
using namespace std;
/* ... */
ListNode::ListNode(const CacheEntry* e2) : cacheEntry(e2) {
dirty=false;
}
void ListNode::setCacheEntry(const CacheEntry* entry) {
cacheEntry=entry;
}
const CacheEntry* ListNode::getCacheEntry() {
if(dirty) {
return NULL;
}
return cacheEntry;
}
void ListNode::setDirty() {
dirty=true;
}
std::string PeachCachePartition::get(const string key) {
CacheIter iter=cache->find(key);
string value;
if(iter!=cache->end()) {
__sync_fetch_and_add(_hits,1);
const CacheEntry* entry=iter->second;
value=(entry->value);
lruList->enqueue(entry->getLruListNode());
if(size() > max) { // removes some
int howMany = (int) ceil((*_misses)/(*_hits))+1;
int k=0;
ListNode removedListNode=ListNode();
ListNode * p=&removedListNode;
ListNode ** pp=&p;
while(size() > max && k<howMany) {
if(lruList->dequeue(pp)) {
const CacheEntry * toBeRemoved=p->getCacheEntry();
if(toBeRemoved) {
remove(toBeRemoved->key);
k++;
}
}
}
}
} else {
__sync_fetch_and_add(_misses,1);
value=loader(key);
if(value.size()>0) {
put(key,value);
}
}
return value;
}
void PeachCachePartition::remove(const std::string &key) {
try {
boost::lock_guard<boost::mutex> mapLockGuard(mapMutex);
CacheIter iter = cache->find(key);
if(iter!=cache->end()) {
const CacheEntry * toBeRemoved=iter->second;
if(toBeRemoved->getLruListNode()) {
toBeRemoved->getLruListNode()->setDirty();
}
delete(toBeRemoved);
cache->erase(iter);
__sync_sub_and_fetch(_size,1);
}
} catch (std::exception &e) {
Logger::err(e.what());
}
}
void PeachCachePartition::put(const std::string &key, std::string &value) {
try {
boost::unique_lock<boost::mutex> mapLockGuard(mapMutex,boost::try_to_lock);
if(mapLockGuard.owns_lock()) {
CacheIter iter=cache->find(key);
const CacheEntry * entry;
if(iter!=cache->end()) {
entry=iter->second;
entry->getLruListNode()->setDirty();
} else {
entry = new CacheEntry(key,value);
__sync_add_and_fetch(_size,1);
(*cache)[key] = entry;
}
entry->createLruListNode()->setCacheEntry(entry);
lruList->enqueue(entry->getLruListNode());
}
} catch (std::exception &e) {
Logger::err(e.what());
}
}
Can you explain me what's wrong? I'm almost sure it deadlocks in the removal as it is the only lock it must acquire.
Thanks everybody
edit: I'm using this cache in an apache module which runs mpm_prefork_module: could this be the problem? Should I use boost::interprocess instead of boost::thread?