How does the Hill Climbing algorithm work? - c++

I'm learning Artificial Intelligence from a book, the book vaguely explains the code I'm about to post here, I assume because the author assumes everyone has experienced hill climbing algorithm before. The concept is rather straightforward, but I just don't understand some of the code below and I'd like someone to help me understand this algorithm a bit clearer before I move on.
I commented next to the parts that confuses me most, a summary of what these lines are doing would be very helpful to me.
int HillClimb::CalcNodeDist(Node* A, Node* B)
{
int Horizontal = abs(A->_iX - B->_iX);
int Vertical = abs(A->_iY - B->_iY);
return(sqrt(pow(_iHorizontal, 2) + pow(_iVertical, 2)));
}
void HillClimb::StartHillClimb()
{
BestDistance = VisitAllCities();
int CurrentDistance = BestDistance;
while (true)
{
int i = 0;
int temp = VisitAllCities();
while (i < Cities.size())
{
//Swapping the nodes
Node* back = Cities.back();
Cities[Cities.size() - 1] = Cities[i];
Cities[i] = back; // Why swap last city with first?
CurrentDistance = VisitAllCities(); // Why visit all nodes again?
if (CurrentDistance < BestDistance) // What is this doing?
{
BestDistance = CurrentDistance; //???
break;
}
else
{
back = Cities.back();
Cities[Cities.size() - 1] = Cities[i];
Cities[i] = back;
}
i++;
}
if (CurrentDistance == temp)
{
break;
}
}
}
int HillClimb::VisitAllCities()
{
int CurrentDistance = 0;
for (unsigned int i = 0; i < Cities.size(); i++)
{
if (i == Cities.size() - 1)//Check if last city, link back to first city
{
CurrentDistance += CalcNodeDist(Cities[i], Cities[0]);
}
else
{
CurrentDistance += CalcNodeDist(Cities[i], Cities[i + 1]);
}
}
return(CurrentDistance);
}
Also the book doesn't state what type of hill climb this is. I assume it's basic hill climb as it doesn't restart when it gets stuck?

Essentially, it does this in pseudo-code:
initialize an order of nodes (that is, a list) which represents a circle
do{
find an element in the list so that switching it with the last element of the
list results in a shorter length of the circle that is imposed by that list
}(until no such element could be found)
VisitAllCities is a helper that computes the length of that circle, CalcNodeDist is a helper that computes the distance between two nodes
the outer while loop is what I called do-until, the inner while loop iterates over all elements.
The if (CurrentDistance < BestDistance) part simply checks whether changing that list by swapping results in a smaller length, if so, update the distance, if not, undo that change.
Did I cover everything you wanted to know? Question about a particular part?

Related

Increment the value of a map

need your help and better if you can help me fast. It is very trivial problem but still can't understand what exactly i need to put in one line.
The following code i have
for (busRequest = apointCollection.begin(); busRequest != apointCollection.end(); busRequest++)
{
double Min = DBL_MAX;
int station = 0;
for (int i = 0; i < newStations; i++)
{
distance = sqrt(pow((apointCollection2[i].x - busRequest->x1), 2) + pow((apointCollection2[i].y - busRequest->y1), 2));
if (distance < Min)
{
Min = distance;
station = i;
}
}
if (people.find(station) == people.end())
{
people.insert(pair<int, int>(station, i));
}
else
{
how can i increment "i" if the key of my statation is already in the map.
}
}
Just briefly what i do , i take the first busrequest go to the second loop take the first station and find the minimum distance. After i go over the second loop , i add that station with minimum distance to my map . After i proceed with all my loops and if there is the same station , i need to increment it , so it means that that station is using two times and etc.
I need the help just give me hint or provide the line that i need to add.
I thank you in advance and waiting for your help.
And I think you meant Min Distance instead of i? Check and let me know.
for (busRequest = apointCollection.begin(); busRequest != apointCollection.end(); busRequest++)
{
double Min = DBL_MAX;
int station = 0;
for (int i = 0; i < newStations; i++)
{
distance = sqrt(pow((apointCollection2[i].x - busRequest->x1), 2) + pow((apointCollection2[i].y - busRequest->y1), 2));
if (distance < Min)
{
Min = distance;
station = i;
}
}
if (people.find(station) == people.end())
{
people.insert(pair<int, int>(station, i)); // here???
}
else
{
// This routine will increment the value if the key already exists. If it doesn't exist it will create it for you
YourMap[YourKey]++;
}
}
In C++ you can directly access a map key without inserting it. C++ will automatically create it with default value.
In your case, if a station is not present in people map and you will access people[station] then people[station] will automatically be set to 0 ( default value of int is 0 ).
So you can just do this:
if (people[station] == 0)
{
// Do something
people[station] = station; // NOTE: i is not accessible here! check ur logic
}
else
{
people[station]++;
}
Also: In your code i cannot be accessed inside IF condition to insert into people map.

Binary Search avoid unreadable entry (hole in list)

I have implemented a binary search function but I have an issue with a list entry that may become unreadable. It's implemented in C++ but ill just use some pseudo code to make it easier. Please to not focus on the unreadable or string implementation, it's just pseudo code. What matter is that there are unreadable entries in the list that have to be navigated around.
int i = 0;
int imin = 0;
int imax = 99;
string search = "test";
while(imin <= imax)
{
i = imin + (imax - imin) / 2;
string text = vector.at(i);
if(text.isUnreadable())
{
continue;
}
if(compare(text, search) = 0)
{
break;
}
else if(compare(text, search) < 0)
{
imin = i + 1;
}
else if(compare(text, search) > 0)
{
imax = i - 1;
}
}
The searching itself is working pretty well, but the problem I have is how to avoid getting an endless loop if the text is unreadable. Anyone has a time tested approach for this? The loop should not just exit when unreadable but rather navigate around the hole.
I had similar task in one of projects - lookup on sequence where some of items are non-comparable.
I am not sure is this the best possible implementation, in my case it looks like this:
int low = first_comparable(0,env);
int high = last_comparable(env.total() - 1,env);
while (low < high)
{
int mid = low + ((high - low) / 2);
int tmid = last_comparable(mid,env);
if( tmid < low )
{
tmid = first_comparable(mid,env);
if( tmid == high )
return high;
if( tmid > high )
return -1;
}
mid = tmid;
...
}
If vector.at(mid) item is non-comparable it does lookup in its neighborhood to find closest comparable.
first/last_comparable() functions return index of first comparable element from given index. Difference is in direction.
inline int first_comparable( int n, E& env)
{
int n_elements = env.total();
for( ; n < n_elements; ++n )
if( env.is_comparable(n) )
return n;
return n;
}
Create a list of pointers to your data items. Do not add "unreadable" ones. Search the resulting list of pointers.
the problem I have is how to avoid getting an endless loop if the text is unreadable.
Seems like that continue should be break instead, so that you break out of the loop. You'd probably want to set a flag or something to indicate the error to whatever code follows the loop.
Another option is to throw an exception.
Really, you should do almost anything other than what you're doing. Currently, when you read one of these 'unreadable' states, you simply continue the loop. But imin and imax still have the same values, so you end up reading the same string from the same place in the vector, and find that it's unreadable again, and so on. You need to decide how you want to respond to one of these 'unreadable' states. I guessed above that you'd want to stop the search, in which case either setting a flag and breaking out of the loop or throwing an exception to accomplish the same thing would be reasonable choices.

Selective Infinite Loop in Making a Tournament Tree

I want to write a program that randomly generates a tournament tree using only the number of challengers. I read into another such problem, but the answer described how ranks would take part and seeding the players, which went a little over head.
The problem I am facing is that my algorithm produces an infinite loop for values between 1 and 4 inclusively. For all values otherwise, the program runs as desired.
My approach was to take in an array of strings for the competitors' names. Then, I would iterate over each position and randomly select a competitor's name to take that spot. Because I am swapping the names, I have to check for duplicates in the array. I believe this is where my code is experiencing issues.
Here is the snippet that actually determines the tree
for(int i = 0; i < no_players;) {
int index = rand() % ((no_players - i) + i);
// randomly choose an element from the remainder
string temp = players[index];
bool unique = true;
// check all the elements before the current position
for(int j = 0; j < i; j++) {
// if the element is already there, it is not unique
if(players[j] == temp)
unique = false;
}
// only if the element is unique, perform the swap
if(unique) {
players[index] = players[i];
players[i] = temp;
i++;
}
}
Any help is much appreciated!

Need to find a logic error in a card shuffling method

I'm trying to write a method that takes an array of integers (0-51, in that order), cuts it into two separate arrays (A and B in the below function by using the cut method, which I know for sure works) and then re-fuses the two arrays together by randomly selecting 0, 1 or 2 cards from the BOTTOM of either A or B and then adding them to the deck.
(ps- by "array" I mean linked list, I just said array because I thought it would be conceptually easier)
This is my code so far, it works, but there's a definite bias when it comes to where the cards land. Can anybody spot my logic error?
[code]
void Deck::shuffle(){
IntList *A = new IntList();
IntList *B = new IntList();
cut(A, B);
IntListNode *aMarker = new IntListNode;
aMarker = A->getSentinel()->next;
//cout<< A->getSentinel()->prev->prev->data <<'\n'<<'\n';
IntListNode *bMarker = new IntListNode;
bMarker = B->getSentinel()->next;
//cout<< B->getSentinel()->prev->data;
deckList.clear();
srand(time(NULL));
int randNum = 0, numCards = 0, totalNumCards = 0;
bool selector = true, aisDone = false, bisDone = false;
while(totalNumCards < 52){
randNum = rand() % 3;
if(randNum == 0){
selector = !selector;
continue;
}
numCards = randNum;
if(!aisDone && !bisDone){
if(selector){
for(int i = 0; i < numCards; i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
selector = false;
}else{
for(int i = 0; i < numCards; i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
selector = true;
}
}
if(aisDone && !bisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(bMarker->data);
bMarker = (bMarker->next);
if(bMarker == B->getSentinel()){
bisDone = true;
break;
}
}
//return;
}
if(bisDone && !aisDone){
for(int i = 0; i < (52 - totalNumCards); i++){
deckList.push_back(aMarker->data);
aMarker = (aMarker->next);
if(aMarker == A->getSentinel()){
aisDone = true;
break;
}
}
//return;
}
totalNumCards += numCards;
}
int tempSum = 0;
IntListNode *tempNode = deckList.head();
for(int j = 0; j < 52; j++){
//cout<< (tempNode->data) << '\n';
tempSum += (tempNode->data);
tempNode = (tempNode ->next);
}
if(tempSum != 1326)
system("PAUSE");
return;
}
[/code]
What about just using std::random_shuffle? Yeah, it won't work for linked list, but you can change it to vector :)
If your instructor would have the moral to teach you programming the way it should be done then they'd encourage you to solve the problem like so, with four lines of code:
#include<algorithm>
#include<vector>
// ...
std::vector<int> cards; // fill it in ...
std::random_shuffle(cards.begin(), cards.end());
Using the standard library is the right way of doing things. Writing code on your own when you can solve the problem with the standard library is the wrong way of doing things. Your instructor doesn't teach you right. If they want to get a point across (say, have you practice using pointers) then they should be more attentive in selecting the exercise they give you.
That speech given, here is a solution worse than the above but better than your instructor's:
52 times do the following:
Choose two random none-equal integers in the range [0,52).
Swap the values in the array corresponding to these positions.
For most random number generators, the low bits are the least random ones. So your line
randNum = rand() % 3;
should be modified to get its value more from the high- to middle-order bits from rand.
Your expectations may be off. I notice that you swap the selector if your random value is 0. Coupled with the relative non-randomness of randNum, this may be your problem. Perhaps you need to make things less random to make them appear more random, such as swapping the selector every time through the loop, and always taking 1 or more cards from the selected deck.
Comments:
srand(time(NULL));
This should only be called once during an applications run. This it is usally best to call it in main() as you start.
int randNum = 0, numCards = 0, totalNumCards = 0;
bool selector = true, aisDone = false, bisDone = false;
One identifier per line. Every coding standard written has this rule. It also prevents some subtle errors that can creep in when using pointers. Get used to it.
randNum = rand() % 3;
The bottom bits of rand are the lest random.
rand Num = rand() / (MAX_RAND / 3.0);
Question:
if(!aisDone && !bisDone)
{
This can execute
and set one of the above to isDone
Example:
Exit state aisDone == false bsiDone == false // OK
Exit state aisDone == true bsiDone == false // Will run below
Exit state aisDone == false bsiDone == ture // Will run below
}
if(aisDone && !bisDone)
{
Is this allowed to run if the first block above is run?
}
if(bisDone && !aisDone)
{
Is this allowed to run if the first block above is run?
}
The rest is too complicated and I don't understand.
I can think of simpler techniques to get a good shuffle of a deck of cards:
for(loop = 0 .. 51)
{
rand = rand(51 - loop);
swap(loop, loop+rand);
}
The above simulates picking a card at random from the deck A and putting it on the top of deck B (deck B initially being empty). When the loop completes B is now A (as it was done in place).
Thus each card (from A) has the same probability of being placed at any position in B.

Shifting elements in an array C++

I've developed a method called "rotate" to my stack object class. What I did was that if the stack contains elements: {0,2,3,4,5,6,7} I would needed to rotate the elements forwards and backwards.
Where if i need to rotate forwards by 2 elements, then we would have, {3,4,5,6,7,0,2} in the array. And if I need to rotate backwards, or -3 elements, then, looking at the original array it would be, {5,6,7,0,2,3,4}
So the method that I have developed works fine. Its just terribly ineffecient IMO. I was wondering if I could wrap the array around by using the mod operator? Or if their is useless code hangin' around that I havent realized yet, and so on.
I guess my question is, How can i simplify this method? e.g. using less code. :-)
void stack::rotate(int r)
{
int i = 0;
while ( r > 0 ) // rotate postively.
{
front.n = items[top+1].n;
for ( int j = 0; j < bottom; j++ )
{
items[j] = items[j+1];
}
items[count-1].n = front.n;
r--;
}
while ( r < 0 ) // rotate negatively.
{
if ( i == top+1 )
{
front.n = items[top+1].n;
items[top+1].n = items[count-1].n; // switch last with first
}
back.n = items[++i].n; // second element is the new back
items[i].n = front.n;
if ( i == bottom )
{
items[count-1].n = front.n; // last is first
i = 0;
r++;
continue;
}
else
{
front.n = items[++i].n;
items[i].n = back.n;
if ( i == bottom )
{
i = 0;
r++;
continue;
}
}
}
}
Instead of moving all the items in your stack, you could change the definition of 'beginning'. Have an index that represents the first item in the stack, 0 at the start, which you add to and subtract from using modular arithmetic whenever you want to rotate your stack.
Note that if you take this approach you shouldn't give users of your class access to the underlying array (not that you really should anyway...).
Well, as this is an abstraction around an array, you can store the "zero" index as a member of the abstraction, and index into the array based on this abstract notion of the first element. Roughly...
class WrappedArray
{
int length;
int first;
T *array;
T get(int index)
{
return array[(first + index) % length];
}
int rotateForwards()
{
first++;
if (first == length)
first = 0;
}
}
You've gotten a couple of reasonable answers, already, but perhaps one more won't hurt. My first reaction would be to make your stack a wrapper around an std::deque, in which case moving an element from one end to the other is cheap (O(1)).
What you are after here is a circular list.
If you insist on storing items in an array just use top offset and size for access. This approach makes inserting elements after you reached allocated size expensive though (re-allocation, copying). This can be solved by using doubly-linked list (ala std::list) and an iterator, but arbitrary access into the stack will be O(n).
The function rotate below is based on reminders (do you mean this under the 'mod' operation?)
It is also quite efficient.
// Helper function.
// Finds GCD.
// See http://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
// Number of assignments of elements in algo is
// equal to (items.size() + gcd(items.size(),r)).
void rotate(std::vector<int>& items, int r) {
int size = (int)items.size();
if (size <= 1) return; // nothing to do
r = (r % size + size) % size; // fits r into [0..size)
int num_cycles = gcd(size, r);
for (int first_index = 0; first_index < num_cycles; ++first_index) {
int mem = items[first_index]; // assignment of items elements
int index = (first_index + r) % size, index_prev = first_index;
while (index != first_index) {
items[index_prev] = items[index]; // assignment of items elements
index_prev = index;
index = (index + r) % size;
};
items[index_prev] = mem; // assignment of items elements
}
}
Of course if it is appropriate for you to change data structure as described in other answers, you can obtain more efficient solution.
And now, the usual "it's already in Boost" answer: There is a Boost.CircularBuffer
If for some reason you'd prefer to perform actual physical rotation of array elements, you might find several alternative solutions in "Programming Pearls" by Jon Bentley (Column 2, 2.3 The Power of Primitives). Actually a Web search for Rotating Algorithms 'Programming Pearls' will tell you everything. The literal approach you are using now has very little practical value.
If you'd prefer to try to solve it yourself, it might help to try looking at the problem differently. You see, "rotating an array" is really the same thing as "swapping two unequal parts of an array". Thinking about this problem in the latter terms might lead you to new solutions :)
For example,
Reversal Approach. Reverse the order of the elements in the entire array. Then reverse the two parts independently. You are done.
For example, let's say we want to rotate abcdefg right by 2
abcdefg -> reverse the whole -> gfedcba -> reverse the two parts -> fgabcde
P.S. Slides for that chapter of "Programming Pearls". Note that in Bentley's experiments the above algorithm proves to be quite efficient (among the three tested).
I don't understand what the variables front and back mean, and why you need .n. Anyway, this is the shortest code I know to rotate the elements of an array, which can also be found in Bentley's book.
#include <algorithm>
std::reverse(array , array + r );
std::reverse(array + r, array + size);
std::reverse(array , array + size);