DEVC++ is showing a duplicate code in the output window, while other C++ give me the right ouput. What am I doing wrong? (Random Number Generator) - c++

As default, I use DevC++ to write programs for my computer science class. I am really new to all of this. For this program, we are told to use a random number generator to display values using loops. We used for, while, and do..while loops. I was able to do the for loop (Set1) and while loop (Set2) with no struggle. Once I got to do.. while loop (Set3), and finished it, the output window shows a repeat of Set 2, which is the while loop. I ran it through onlinegdb and it gave me the right output. Is it something with DevC++ or is there something wrong in my code that I haven't been able to see?
The coding for my program:
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
using namespace std;
//declare constant doubles for the program
#define NUM_ONE 30
#define MAX_NUM_TWO 75
#define MAX_NUM_THREE 155
#define MIN_RAND_DOUBLE_VAL 0.0
#define MAX_RAND_DOUBLE_VAL 100.0
#define VAL_DISPLAY 7
int main()
{
//input the seed value of 12 into the random number generator
srand(12);
//declare integer values
int random_num;
int cnt;
int per_line;
per_line = 0;
//start the random number generator for the first set
cout << "Set 1 -- " << NUM_ONE << " values" << endl;
for (cnt = 1; cnt <= NUM_ONE; cnt++) {
random_num = rand();
cout << setw(13) << random_num;
per_line++;
if (per_line % VAL_DISPLAY == 0) {
cout << endl;
}
}
cout << endl
<< endl;
//form the formula to start the random number generator for the second set (1-75)
int random_num2;
random_num2 = rand() % MAX_NUM_TWO + 1;
//start the random number generator for the second set
cout << "Set 2 -- " << random_num2 << " values" << endl;
int cnt2;
int per_line2;
cnt2 = 1;
per_line2 = 0;
while (cnt2 <= random_num2) {
random_num = rand();
cnt2++;
cout << setw(13) << random_num;
per_line2++;
if (per_line2 % VAL_DISPLAY == 0) {
cout << endl;
}
}
cout << endl
<< endl;
//start the random number generator for the third set
int random_num3 = rand() % MAX_NUM_THREE + 1;
cout << "Set 3 -- " << random_num3 << " values" << endl;
double double_random_num;
int cnt3;
int per_line3;
cnt3 = 1;
per_line3 = 0;
do {
double_random_num = MIN_RAND_DOUBLE_VAL + (rand() / (RAND_MAX / (MAX_RAND_DOUBLE_VAL MIN_RAND_DOUBLE_VAL)));
cout << fixed << setprecision(5) << setw(13) << double_random_num;
cnt3++;
per_line3++;
if (per_line3 % VAL_DISPLAY == 0) {
cout << endl;
}
}
while (cnt3 <= random_num3);
cout << endl;
return 0;
}
On DevC++ the output is supposed to look like this:
Set 1 -- 30 values
77 5628 6232 29052 1558 26150 12947
29926 11981 22371 4078 28629 4665 2229
24699 27370 3081 18012 24965 2064 8285
21054 5225 11777 29853 2956 22439 3341
31337 14755
Set 2 -- 65 values
24855 4173 32304 292 5344 15512 12952
1868 10888 19581 13463 32652 3409 28353
26151 14598 12455 26295 25763 26040 8285
27502 15148 4945 26170 1833 5196 9794
26804 2831 11993 2839 9979 27428 6684
4616 30265 5752 32051 10443 9240 8095
28084 26285 8838 18784 6547 7905 8373
19377 18502 27928 13669 25828 30502 28754
32357 2843 5401 10227 22871 20993 8558
10009 6581
Set 3 -- 87 values
39.08811 14.20026 75.05417 65.71551 28.70876 20.87466 92.68166
7.11081 0.00916 85.52507 67.95251 58.98312 55.28123 55.23850
47.74316 66.31062 52.77261 25.62334 84.13038 6.10981 11.68859
38.34346 4.33363 90.12421 66.59139 30.37812 25.38835 33.32011
24.34767 75.70421 91.63793 53.89264 26.74642 9.94293 63.23130
20.26124 71.88940 78.69503 33.71685 10.81576 97.50053 0.06714
4.85549 1.96539 79.29014 82.14972 96.79250 50.13276 47.45933
85.93097 21.68950 83.30638 74.52010 74.41633 98.99594 67.82434
37.49199 38.45637 40.39125 65.93829 7.67846 39.96399 82.64412
49.83978 71.09287 63.16111 96.37745 87.76513 32.64565 14.43525
48.99747 67.77551 7.29698 61.47343 49.82147 74.88327 51.20396
52.24464 55.53758 87.09067 36.05152 4.54726 64.19263 6.03656
But it is giving me:
Set 1 -- 30 values
77 5628 6232 29052 1558 26150 12947
29926 11981 22371 4078 28629 4665 2229
24699 27370 3081 18012 24965 2064 26890
21054 5225 11777 29853 2956 22439 3341
31337 14755
Set 2 -- 65 values
24855 4173 32304 292 5344 15512 12952
1868 10888 19581 13463 32652 3409 28353
26151 14598 12455 26295 25763 26040 8285
27502 15148 4945 26170 1833 5196 9794
26804 2831 11993 2839 9979 27428 6684
4616 30265 5752 32051 10443 9240 8095 Set 2 -- 65 values
24855 4173 32304 292 5344 15512 12952
1868 10888 19581 13463 32652 3409 28353
26151 14598 12455 26295 25763 26040 8285
27502 15148 4945 26170 1833 5196 9794
26804 2831 11993 2839 9979 27428 6684
4616 30265 5752 32051 10443 9240 8095
28084 26285 8838 18784 6547 7905 8373
19377 18502 27928 13669 25828 30502 28754
32357 2843 5401 10227 22871 20993 8558
10009 6581
Set 3 -- 87 values
39.08811 14.20026 75.05417 65.71551 28.70876 20.87466 92.68166
7.11081 0.00916 85.52507 67.95251 58.98312 55.28123 55.23850
47.74316 66.31062 52.77261 25.62334 84.13038 6.10981 11.68859
38.34346 4.33363 90.12421 66.59139 30.37812 25.38835 33.32011
24.34767 75.70421 91.63793 53.89264 26.74642 9.94293 63.23130
20.26124 71.88940 78.69503 33.71685 10.81576 97.50053 0.06714
4.85549 1.96539 79.29014 82.14972 96.79250 50.13276 47.45933
85.93097 21.68950 83.30638 74.52010 74.41633 98.99594 67.82434
37.49199 38.45637 40.39125 65.93829 7.67846 39.96399 82.64412
49.83978 71.09287 63.16111 96.37745 87.76513 32.64565 14.43525

Related

Binary tree benchmark results

I stumbled upon a website making benchmakrs.
In this case Golang vs C++, binary trees.
The C++ solution does A LOT better than golang using allocation of a memory pool.
I can get behind that but wondered how an implementation without that would fare. So I modified it to look more like the Golang-Code and removed concurrency for both.
In this example and on my machine the golang code runs in around 24 seconds.
The C++ code takes an average of 126 seconds. I did not expect this result at all. I expected C++ to still be faster or maybe be a bit slower but not by a factor of 5.
Did I make some huge mistake? Or do you know the reason for this? Code for both programs is below:
Built with:
mingw32-g++.exe -Wall -fexceptions -O2 -c D:\TMP\Test\main.cpp -o
obj\Release\main.o
mingw32-g++.exe -o bin\Release\Test.exe obj\Release\main.o -s
#include <iostream>
using namespace std;
class Node {
public:
Node(uint64_t d);
~Node();
int Check();
private:
Node* l;
Node* r;
};
Node::Node(uint64_t d){
if (d > 0){
l = new Node(d - 1);
r = new Node(d - 1);
} else {
l = 0;
r = 0;
}
}
Node::~Node(){
if(l){
delete l;
delete r;
}
}
int Node::Check(){
if (l) {
return l->Check() + 1 + r->Check();
} else {
return 1;
}
}
int main()
{
uint64_t min_depth = 4;
uint64_t max_depth = 21;
for (uint64_t d = min_depth; d <= max_depth; d += 2) {
uint64_t iterations = 1 << (max_depth - d + min_depth);
uint64_t c = 0;
for (uint64_t i = 1; i < iterations; i++) {
Node* a = new Node(d);
c += a->Check();
delete a; // I tried commenting this line but it made no big impact
}
cout << iterations << " trees of depth " << d << " check: " << c << "\n";
}
return 0;
}
Golang:
go version go1.7.1 windows/amd64
package main
import(
"fmt"
)
type Node struct {
l *Node
r *Node
}
func (n *Node) check() int {
if n.l != nil {
return n.l.check() + 1 + n.r.check()
} else {
return 1
}
}
func make(d uint) *Node {
root := new(Node)
if d > 0 {
root.l = make(d-1)
root.r = make(d-1)
}
return root
}
func main(){
min_depth := uint(4)
max_depth := uint(21)
for d := min_depth; d <= max_depth; d += 2 {
iterations := 1 << (max_depth - d + min_depth)
c := 0
for i := 1; i < iterations; i++ {
a := make(d)
c += a.check()
}
fmt.Println(iterations, " trees of depth ", d, " check: ", c)
}
}
It's something with your computer your ran on, because I'm getting the expected result where C++ is twice as fast as go.
C++
time cmake-build-debug/main
2097152 trees of depth 4 check: 65011681
524288 trees of depth 6 check: 66584449
131072 trees of depth 8 check: 66977281
32768 trees of depth 10 check: 67074049
8192 trees of depth 12 check: 67092481
2048 trees of depth 14 check: 67074049
512 trees of depth 16 check: 66977281
128 trees of depth 18 check: 66584449
32 trees of depth 20 check: 65011681
cmake-build-debug/main 21.09s user 0.02s system 99% cpu 21.113 total
GO
jonny#skyhawk  ~/Projects/benchmark  time ./main  ✔  2604  02:34:29
2097152 trees of depth 4 check: 65011681
524288 trees of depth 6 check: 66584449
131072 trees of depth 8 check: 66977281
32768 trees of depth 10 check: 67074049
8192 trees of depth 12 check: 67092481
2048 trees of depth 14 check: 67074049
512 trees of depth 16 check: 66977281
128 trees of depth 18 check: 66584449
32 trees of depth 20 check: 65011681
./main 48.72s user 0.52s system 197% cpu 24.905 total
I built the C++ main.cpp with CLion's mose basic / default settings (this CMakeLists.txt that will build a main.cpp)
cmake_minimum_required(VERSION 3.3)
project(test_build)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(BUILD_1 main)
set(SOURCE_FILES_1 main.cpp)
add_executable(${BUILD_1} ${SOURCE_FILES_1})

program works for small iterations but throws vector subscript out of range during large iterations

here is my code. i am trying to find min distance(diff in indices) b/w 2 equal elements:
#include<iostream>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
vector<string> split_string(string);
int n;
int minimumDistances(vector<int> a) {
int mn=n,flag=0,mch,pos,diff=0;
for (int i = 0;i < n-1;i++) {
//mch = a[i];
for (int j = i + 1;j < n;j++) {
if (a[j]==a[i]) {
flag = 1;
pos = j;
diff = j - i;
}
}
if (diff<mn) {
mn = diff;
}
}
if (flag==0) {
return -1;
}
return mn;
}
int main()
{
cin >> n;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
string a_temp_temp;
getline(cin, a_temp_temp);
vector<string> a_temp = split_string(a_temp_temp);
vector<int> a(n);
for (int i = 0; i < n; i++) {
int a_item = stoi(a_temp[i]);
a[i] = a_item;
}
int result = minimumDistances(a);
cout << result;
cin.get();
return 0;
}
vector<string> split_string(string input_string) {
string::iterator new_end = unique(input_string.begin(), input_string.end(),
[](const char &x, const char &y) {
return x == y and x == ' ';
});
input_string.erase(new_end, input_string.end());
while (input_string[input_string.length() - 1] == ' ') {
input_string.pop_back();
}
vector<string> splits;
char delimiter = ' ';
size_t i = 0;
size_t pos = input_string.find(delimiter);
while (pos != string::npos) {
splits.push_back(input_string.substr(i, pos - i));
i = pos + 1;
pos = input_string.find(delimiter, i);
}
splits.push_back(input_string.substr(i, min(pos, input_string.length()) - i +
1));
return splits;
}
The exception occurs at pt marked by arrow
when n=10 no error
when =1000 exception occurs
Why is this exception only occurring at large values?
sample input :
39572 89524 21749 94613 75569 74800 91713 62107 28574 22617 22271 22624 28116 67573 53717 9358 65220 59894 78686 10945 33641 11708 8851 11860 66780 64697 799 47782 41971 54170 8960 81543 60047 47061 92508 51968 38213 84221 14075 66787 23191 52698 5764 51307 20271 59481 77018 1843 19375 55704 12789 53016 83764 37992 64877 50545 19041 82028 98327 61012 52551 7287 42555 12598 70700 51416 80918 8914 35637 11345 75701 58828 80395 97817 26488 17019 57299 3506 18862 93026 75562 48003 62395 59327 85996 27272 9872 5037 25652 8199 82402 78203 31838 41309 7153 18890 92725 88071 27804 28363 99416 19858 3543 79812 17675 30031 96831 91326 49889 15693 84353 25452 80049 46748 84779 66045 90372 94651 87434 16024 19202 69836 94228 67392 27498 1381 86282 20223 5805 14087 48586 5221 50297 68482 85033 67972 98513 98216 59299 48403 30262 60004 73855 10311 6752 74986 92708 13476 85989 96494 29500 5191 82683 40080 88935 10181 57814 75217 30404 63619 5656 95343 68840 55953 63825 70226 23926 62338 68442 99577 27093 15056 59581 17300 25367 82685 92286 34427 96161 78275 30922 25661 99818 13605 82094 88753 23786 39908 80323 54190 3527 85979 65885 72367 41933 29710 58945 82211 8401 43740 81788 35494 58796 57721 69147 516 40406 77785 34943 36567 72413 65865 78580 72231 95822 60674 77337 35960 582 57660 6503 4109 43639 72388 92829 1924 2099 51774 84135 10500 95514 82275 62346 70663 39996 31493 71179 80402 9279 6122 16969 81692 88340 11902 70275 514 72576 47612 36475 73159 21624 42978 93620 65264 15366 86449 67188 17465 54576 67676 44317 50090 49951 6664 20753 89948 54509 8284 86702 80140 14407 20024 78184 19099 31926 48460 19613 4502 12424 72440 94013 34049 15418 87634 99313 30785 90435 82853 64602 45011 50529 25272 11454 481 48288 48559 6781 2797 56844 93483 82938 87603 13507 61122 6702 45433 25934 42667 66288 38359 15108 60301 72408 46878 64287 88073 94015 54723 87278 74970 99734 37808 242 27540 54641 48530 76100 61422 67679 32944 54905 66969 20547 84765 44444 43601 30198 86730 2620 12838 25089 17728 73140 13849 64607 53779 18274 74974 8502 5553 49944 24589 59713 50186 52129 14354 15068 28229 75776 99100 77525 47033 66069 98072 31798 26865 41673 78349 13596 44294 7539 55037 78374 80679 68887 59333 50811 3513 34308 59313 9066 84252 254 85131 50791 52384 99485 82211 96965 91613 81311 74491 38647 63733 88915 86797 90598 46941 65146 20546 7587 72686 75584 85961 69717 60823 61647 36880 64336 12307 96194 89755 12911 12800 74886 63702 65184 90724 45914 78502 82337 43577 52993 20984 7310 41908 24134 97909 88849 5632 18455 96436 94670 10391 98750 80740 71214 60397 17620 51903 89056 30166 41658 1967 42967 32896 65670 8151 23620 27936 86653 5958 71513 55998 43294 78824 14259 67428 93085 19460 73061 27892 15897 84083 54636 30999 64823 25850 7748 82444 77753 96804 12610 35763 98771 55577 68660 80793 80081 92280 8729 83086 14590 96595 55437 57885 91771 69696 41665 1208 89156 31078 29100 21405 15162 83736 52404 79985 25939 60152 78781 3692 73308 7744 39456 72080 63321 24468 69225 59754 33100 94307 42841 47691 90902 98278 21928 82673 84326 63593 83881 73482 11024 29333 94888 42538 29422 63644 38875 71713 40149 17657 75405 13457 25401 31213 1889 5074 72033 71115 64829 5134 65422 24022 52825 72676 22300 91105 71701 6626 54698 55582 96460 82074 1267 7700 24612 47041 71345 63488 18754 11494 97497 10512 41303 39250 58077 59545 44324 30111 47012 25505 35245 28786 49527 4422 1462 88179 95527 73163 11157 66577 45097 7618 48652 62716 31670 89616 9758 3015 69456 28512 30861 83305 39024 88517 22555 97102 48062 83232 43565 95074 8737 78810 23860 74617 99584 25322 62796 95111 14837 90306 61688 59934 14276 26692 22650 45946 32661 48760 48962 2117 77273 96175 1775 32649 84692 24330 46103 32754 23914 89668 44180 49004 84830 84392 23621 84414 9714 2769 95877 40903 93075 73918 17189 7351 16962 56192 53298 49623 4952 18612 68093 98577 31139 69868 47579 15832 10550 93682 64938 34465 99703 25471 83469 885 9863 23442 1652 35930 26211 97529 76833 35639 87799 94023 59342 4762 50215 28992 54385 71519 47604 38830 70097 78744 8698 17676 10928 19249 27710 92218 70066 27413 17689 53535 44651 27553 76977 46303 63483 19540 43832 56668 55179 31632 50691 30874 52746 17258 59866 7131 5130 23823 45962 75227 18919 71012 9255 29847 6613 53317 38417 76679 97083 56107 46566 41734 83660 23543 88037 63495 59436 48221 20163 30967 96205 87207 61841 48951 20817 38060 56083 25947 61883 18397 17526 80802 5761 26781 27001 12375 96451 81770 89054 93534 37877 35621 35268 37889 75516 23305 1384 34952 71526 21548 82272 67732 25107 44113 16683 45924 98525 89118 71872 60408 23867 5750 57562 29629 48884 915 42004 45335 82686 47410 38869 36915 83031 74137 74805 74900 97442 76189 26204 85320 14089 8476 69404 55548 68942 2440 1473 67467 7910 89697 44228 31778 95447 1790 77759 44331 19058 36115 89666 18096 83525 44887 55011 82909 19024 29816 57809 32818 22358 365 34491 52799 8842 3895 8348 94136 22687 26173 61603 30598 15870 5831 78728 27669 23974 56487 88353 59384 92602 94371 77480 92479 39259 32491 91740 58283 78660 65901 91102 1018 66267 25593 70169 91461 45840 78517 85597 68528 4690 47200 99126 36912 69384 94206 64582 93358 50693 52935 52742 59647 47306 46574 68478 86565 95417 60219 44849 74077 26120 52303 91447 8739 94248 61617 200 40088 40134 85797 8616 61177 32998 24094 98089 18734 34652 62671 12092 1697 31958 81186 61344 79265 44112 46175 82182 39529 22746 43383 13607 65218 95686 5054 73958 6286 66671 74158 46375 23158 76308 71343 84335 25658 11790 82424 44392 46442 61448 72836 48140 93406 70374 25836 89023 14486 88363 71206 54015 11109 14589 83974 76328 26628 89029 66638 32914 72052 57148 95641 11562 33456 66985 95897 59114 95127 94674 19858 57921 56122 92694 6061 65880 79420 48250 54904 93906 36613 26110 64274 64075 57051 48248 40403 31 37277 7041 49298 25682 64189 44939 37244 13998 28276 49494 89464 23403 44168 9323 97677 16642 18369 3738 82522 97790 68340

turning OFF simple text-writing code slows down app

I'm programming a simple game in SFML/C++/Code::blocks. I wrote a simple "dev-console" which basically prints out in the corner fps, position, number of logic/ graphics loops etc.
Everything works fine until I hide it, then fps fall down from 60(blocked max) to around 15. Why disabling writing function causes so much fps drop? (shouldn't disabling it speed things up a little?)
Declarations:
sf::Text consoletxt;
sf::Font font;
if (!font.loadFromFile("Times_New_Roman.ttf"))
std::cout<<"Error loading font Times New Roman"<<std::endl;
consoletxt.setFont(font);
consoletxt.setFillColor(sf::Color(255,255,255,255));
consoletxt.setCharacterSize(14);
consoletxt.setOutlineColor(sf::Color(0,0,0,192));
consoletxt.setOutlineThickness(1);
bool console = true;
Code below: upon switching console = false; fps drops from 60 to 15
tm = t.asMilliseconds();
fps += 1000/tm;
if (console == true)
{
consoletxt.setString("Last loop time: " + doubleToString(tm));
consoletxt.setPosition(0,0);
window.draw(consoletxt);
consoletxt.setString("Fps: " + intToString(1000/tm) + " Average fps: " + intToString(fps/logicLoops));
consoletxt.setPosition(0,15);
window.draw(consoletxt);
consoletxt.setString("objects[0].x: " + doubleToString(objects[0].x));
consoletxt.setPosition(0,30);
window.draw(consoletxt);
consoletxt.setString("objects[0].y: " + doubleToString(objects[0].y));
consoletxt.setPosition(0,45);
window.draw(consoletxt);
consoletxt.setString("Angle radians/degrees: " + doubleToString(cam_angle) + " | " + intToString((int)(cam_angle*180/pi)));
consoletxt.setPosition(0,60);
window.draw(consoletxt);
consoletxt.setString("Logical Loops: " + doubleToString(logicLoops) + " Graphics loops: " + doubleToString(graphicsLoops) + " Difference: " + doubleToString(logicLoops - graphicsLoops - 1));
consoletxt.setPosition(0,75);
window.draw(consoletxt);
consoletxt.setString("Variable test: " + doubleToString(cos(cam_angle*180/3.1415)));
consoletxt.setPosition(0,585);
//window.draw(consoletxt);
}

Recursive Breath First Search works on first execution but not following executions

The solution presented at CodeReview works fine on CentOS 7.1. I have tried to port it to Windows 7, Visual Studio 2012. With minor edits to allow for the parts of C++11 that VS 2012 doesn't support the code compiles, and the first execution of the loop works correctly. The rest of the execution of test cases fail, growing progressively more incorrect with each execution.
The code for this problem can be found on github.
finished computation at 0 /* problem here not included in question */
elapsed time: 0.202012 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 5 Resulting Paths
There were 323 attempted paths
The average path length is 4.8
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
I believe the problem is in one of the files listed below. I've been debugging this for 2 days, I can use some help.
CRKnightMoves_Cpp2.cpp
/*
* KnightMoves.cpp
*
* Author: pacmaninbw
*/
#include "stdafx.h"
#include <iostream>
#include <stdexcept>
#include <chrono>
#include <ctime>
#include <algorithm>
#include <functional>
#include <vector>
#include "KnightMoves.h"
#include "KnightMovesImplementation.h"
#include "KMBoardDimensionConstants.h"
double Average(std::vector<double> TestTimes)
{
double AverageTestTime = 0.0;
double SumOfTestTimes = 0.0;
int CountOfTestTimes = 0;
for (auto TestTimesIter : TestTimes)
{
SumOfTestTimes += TestTimesIter;
CountOfTestTimes++;
}
if (CountOfTestTimes) { // Prevent division by zero.
AverageTestTime = SumOfTestTimes / static_cast<double>(CountOfTestTimes);
}
return AverageTestTime;
}
void OutputOverAllStatistics(std::vector<double> TestTimes)
{
if (TestTimes.size() < 1) {
std::cout << "No test times to run statistics on!" << std::endl;
return;
}
std::cout << std::endl << "Overall Results" << std::endl;
std::cout << "The average execution time is " << Average(TestTimes) << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin() + TestTimes.size()/2, TestTimes.end());
std::cout << "The median execution time is " << TestTimes[TestTimes.size()/2] << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin()+1, TestTimes.end(), std::greater<double>());
std::cout << "The longest execution time is " << TestTimes[0] << " seconds" << std::endl;
std::nth_element(TestTimes.begin(), TestTimes.begin()+1, TestTimes.end(), std::less<double>());
std::cout << "The shortest execution time is " << TestTimes[0] << " seconds" << std::endl;
}
double ExecutionLoop(KMBaseData UserInputData)
{
KnightMovesImplementation *KnightPathFinder = new KnightMovesImplementation(UserInputData);
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
KMOutputData OutputData = KnightPathFinder->CalculatePaths();
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
double ElapsedTimeForOutPut = elapsed_seconds.count();
char ctimebuffer[1024];
std::cout << "finished computation at " << ctime_s(ctimebuffer, 1024, &end_time) << "\n"
<< "elapsed time: " << ElapsedTimeForOutPut << " Seconds\n" << "\n" << "\n";
// Don't include output of results in elapsed time calculation
OutputData.DontShowPathData();
// OutputData.ShowPathData();
OutputData.ShowResults();
delete KnightPathFinder;
return ElapsedTimeForOutPut;
}
int LetUserEnterTestCaseNumber(std::vector<KMBaseData> &TestData)
{
int i = 1;
int Choice = -1;
std::cout << "Select the number of the test case you want to run.\n";
std::cout << "Test Case #" << "\tStart Name" << "\tTarget Name" << "\tBoard Size" << "\tSlicing Method" << "\n";
for (auto TestCase: TestData) {
std::cout << i << "\t" << TestCase.m_StartName << "\t" << TestCase.m_TargetName << "\t" << TestCase.m_DimensionOneSide << "\t";
switch (TestCase.m_LimitationsOnMoves)
{
default :
throw std::runtime_error("LetUserEnterTestCaseNumber : Unknown type of Path Limitation.");
case DenyByPreviousLocation :
std::cout << "Can't return to previous location";
break;
case DenyByPreviousRowOrColumn:
std::cout << "Can't return to previous row or column";
break;
}
std::cout << "\n";
i++;
}
std::cout << i << "\tAll of the above except for 13 and 14\n";
std::cout << ++i <<"\tAll of the above (Go get lunch)\n";
std::cin >> Choice;
if (Choice == 15)
{
std::vector<KMBaseData> TempTests;
for (auto TestCase: TestData)
{
if ((TestCase.m_DimensionOneSide != MaximumBoardDimension) && (TestCase.m_LimitationsOnMoves != DenyByPreviousLocation))
{
TempTests.push_back(TestCase);
}
}
TestData = TempTests;
}
return Choice;
}
void InitTestData(std::vector<KMBaseData> &TestData)
{
KMBaseData TestCases[] = {
{1,3,"A3",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,1,"A1",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,8,"A8",8,1,"H1", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{2,3,"B3",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{2,3,"B3",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{3,1,"C1",8,4,"H4", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{3,1,"A3",8,8,"H8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,3,"A3",2,5,"B5", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn}, // Minimum should be one move
{8,4,"H4",1,3,"A3", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{4,4,"D4",1,8,"A8", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{4,4,"D4",5,6,"E6", DefaultBoardDimensionOnOneSide, DenyByPreviousRowOrColumn},
{1,3,"A3",2,5,"B5", 12, DenyByPreviousRowOrColumn}, // Minimum should be one move
{1,3,"A3",2,5,"B5", DefaultBoardDimensionOnOneSide, DenyByPreviousLocation}, // Minimum should be one move
{1,3,"A3",2,5,"B5", MaximumBoardDimension, DenyByPreviousRowOrColumn} // Minimum should be one move
};
for (int i = 0; i < sizeof(TestCases)/sizeof(KMBaseData); i++) {
TestData.push_back(TestCases[i]);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int status = 0;
std::vector<KMBaseData> TestData;
std::vector<double> TestTimes;
try {
InitTestData(TestData);
int Choice = LetUserEnterTestCaseNumber(TestData);
if (Choice < 0)
{
return status;
}
if (Choice < 15)
{
ExecutionLoop(TestData[Choice-1]);
}
else
{
for (auto TestDataIter: TestData) {
TestTimes.push_back(ExecutionLoop(TestDataIter));
}
}
OutputOverAllStatistics(TestTimes);
return status;
}
catch(std::runtime_error &e) {
std::cerr << "A fatal error occurred in KnightMoves: ";
std::cerr << e.what() << std::endl;
status = 1;
}
catch(std::runtime_error *e) {
std::cerr << "A fatal error occurred in KnightMoves: ";
std::cerr << e->what() << std::endl;
status = 1;
}
catch(...) {
std::cerr << "An unknown fatal error occurred in KnightMoves." << std::endl;
status = 1;
}
return status;
}
KnightMovesImplementation.h
#pragma once
/*
* KnightMovesImplementation.h
*
* Created on: Mar 18, 2016
* Modified on: June 20, 2016
* Author: pacmaninbw
*
* This class provides the search for all the paths a Knight on a chess
* board can take from the point of origin to the destination. It
* implements a modified Knights Tour. The classic knights tour problem
* is to visit every location on the chess board without returning to a
* previous location. That is a single path for the knight. This
* implementation returns all possible paths from point a to point b.
* The actual implementation is documented in the CPP file because it
* can be changed. This head file provides the public interface which
* should not be changed. The public interface may be moved to a
* super class in the future.
*/
#ifndef KNIGHTMOVESIMPLEMENTATION_H_
#define KNIGHTMOVESIMPLEMENTATION_H_
#include "KMPath.h"
#include "KMOutputData.h"
#include "KMMoveFilters.h"
class KnightMovesImplementation {
private:
KMBoardLocation m_PointOfOrigin;
KMBoardLocation m_Destination;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
KMOutputData *m_Results;
KMMoveFilters *m_MoveFilters;
KMPath *m_Path;
protected:
bool CalculatePath(KMMove CurrentMove); // Recursive function
void InitPointOfOrigin(KMBaseData UserData);
void InitDestination(KMBaseData UserData);
public:
KnightMovesImplementation(KMBaseData UserData);
virtual ~KnightMovesImplementation(void);
KMOutputData CalculatePaths();
};
#endif /* KNIGHTMOVESIMPLEMENTATION_H_ */
KnightsImplementation.cpp
/*
* KnightMovesImplementation.cpp
*
* Created on: Mar 18, 2016
* Modified on: June 21, 2016
* Commented on: June 24, 2016
* Author: pacmaninbw
*
* This class implements the search for all possible paths for a Knight
* on a chess board from one particular square on the board to another
* particular square on the board.
*
* The current implementation is a Recursive Breadth First Search. Conceptually
* the algorithm implements a B+ tree with a maximum of 8 possible branches
* at each level. The root of the tree is the point of origin. A particular
* path terminates in a leaf. A leaf is the result of either reaching the
* destination, or reaching a point where there are no more branches to
* traverse.
*
* The m_Path variable is used as a stack within the search.
*
* The public interface CalculatePaths establishes the root and creates
* the first level of branching. The protected interface CalculatePath
* performs the recursive depth first search, however, the
* m_MoveFilters.GetPossibleMoves() function it calls performs a breadth
* first search of the current level.
*
*/
#include "stdafx.h"
#include "KnightMoves.h"
#include "KnightMovesImplementation.h"
#include "KMBoardDimensionConstants.h"
KnightMovesImplementation::~KnightMovesImplementation(void)
{
delete m_MoveFilters;
delete m_Results;
delete m_Path;
}
KnightMovesImplementation::KnightMovesImplementation(KMBaseData UserInputData)
: m_SingleSideBoardDimension(UserInputData.m_DimensionOneSide),
m_PathLimitations(UserInputData.m_LimitationsOnMoves)
{
InitPointOfOrigin(UserInputData);
InitDestination(UserInputData);
m_Path = new KMPath;
m_MoveFilters = new KMMoveFilters(static_cast<unsigned int>(UserInputData.m_DimensionOneSide), UserInputData.m_LimitationsOnMoves);
m_Results = new KMOutputData(m_PointOfOrigin, m_Destination, m_SingleSideBoardDimension, m_PathLimitations);
}
void KnightMovesImplementation::InitPointOfOrigin(KMBaseData UserInputData)
{
m_PointOfOrigin.SetRow(UserInputData.m_StartRow);
m_PointOfOrigin.SetColumn(UserInputData.m_StartColumn);
m_PointOfOrigin.SetName(UserInputData.m_StartName);
m_PointOfOrigin.SetBoardDimension(m_SingleSideBoardDimension);
}
void KnightMovesImplementation::InitDestination(KMBaseData UserInputData)
{
m_Destination.SetRow(UserInputData.m_TargetRow);
m_Destination.SetColumn(UserInputData.m_TargetColumn);
m_Destination.SetName(UserInputData.m_TargetName);
m_Destination.SetBoardDimension(m_SingleSideBoardDimension);
}
KMOutputData KnightMovesImplementation::CalculatePaths()
{
KMRandomAccessMoveCollection PossibleFirstMoves = m_MoveFilters->GetPossibleMoves(m_PointOfOrigin);
if (PossibleFirstMoves.empty())
{
std::cerr << "No Possible Moves in KnightMovesImplementation::CalculatePaths" << std::endl;
}
else
{
for (auto CurrentMoveIter : PossibleFirstMoves)
{
KMMove CurrentMove = CurrentMoveIter;
CurrentMove.SetOriginCalculateDestination(m_PointOfOrigin);
if (CurrentMove.IsValid()) {
CalculatePath(CurrentMove);
}
}
}
return *m_Results;
}
bool KnightMovesImplementation::CalculatePath(KMMove CurrentMove)
{
bool CompletedSearch = false;
KMBoardLocation CurrentLocation = CurrentMove.GetNextLocation();
m_Path->AddMoveToPath(CurrentMove);
m_MoveFilters->PushVisited(CurrentLocation);
if (CurrentLocation == m_Destination)
{
m_Results->AddPath(*m_Path);
CompletedSearch = true;
m_Results->IncrementAttemptedPaths();
}
else
{
if (CurrentMove.IsValid())
{
KMRandomAccessMoveCollection PossibleMoves = m_MoveFilters->GetPossibleMoves(CurrentLocation);
if (!PossibleMoves.empty())
{
for (auto NextMove : PossibleMoves)
{
CalculatePath(NextMove);
}
}
else
{
// No more moves to test, record the attempted path
m_Results->IncrementAttemptedPaths();
}
}
else
{
// There is a logic error if we get here.
std::cerr << "In KnightMovesImplementation::CalculatePath CurrentMove Not Valid" << std::endl;
}
}
m_Path->RemoveLastMove();
m_MoveFilters->PopVisited();
return CompletedSearch;
}
KMMoveFilters.h
#pragma once
/*
* KMMoveFilters.h
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*
* This class provides all the possible Knight moves for a specified location
* on the chess board. In the center of the chess board there are 8 possible
* moves. In the middle of the edge on the chess board there are 4 possible
* moves. In a corner of the chess board there are 2 possible moves. The
* location on the board provides the first filter.
* Slicing is used to allow the program to complete in a reasonable finite
* amount of time. The slicing method can be varied, the default slicing
* method is the knight can't return to any row or column it has previously
* visited. The slicing is the second filter.
*/
#ifndef KMMOVEFILTERS_H_
#define KMMOVEFILTERS_H_
#include <vector>
#include "KnightMoves.h"
#include "KMMove.h"
class KMMoveFilters {
private:
std::vector<KMBoardLocation> m_VisitedLocations;
std::vector<unsigned int> m_VisitedRows;
std::vector<unsigned int> m_VisitedColumns;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
static KMRandomAccessMoveCollection AllPossibleMoves;
// The 8 possible moves the knight can make.
static KMMove Left1Up2;
static KMMove Left2Up1;
static KMMove Left2Down1;
static KMMove Left1Down2;
static KMMove Right1Up2;
static KMMove Right2Up1;
static KMMove Right2Down1;
static KMMove Right1Down2;
protected:
bool IsNotPreviouslyVisited(KMMove Move) const { return IsNotPreviouslyVisited(Move.GetNextLocation()); };
bool IsNotPreviouslyVisited(KMBoardLocation Destination) const;
public:
KMMoveFilters(void);
KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod);
void ResetFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod) {m_SingleSideBoardDimension = BoardDimension; m_PathLimitations = SlicingMethod; }
virtual ~KMMoveFilters(void);
void PushVisited(KMBoardLocation Location);
void PopVisited();
KMRandomAccessMoveCollection GetPossibleMoves(const KMBoardLocation CurrentLocation) const;
};
KMMoveFilters.cpp
/*
* KMMoveFilters.cpp
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*/
#include "stdafx.h"
#include <stdexcept>
#include <algorithm>
#include "KMBoardDimensionConstants.h"
#include "KMMoveFilters.h"
KMMoveFilters::~KMMoveFilters(void)
{
}
KMMoveFilters::KMMoveFilters(void)
: m_SingleSideBoardDimension(DefaultBoardDimensionOnOneSide),
m_PathLimitations(DenyByPreviousRowOrColumn)
{
AllPossibleMoves.push_back(Left1Up2);
AllPossibleMoves.push_back(Left2Up1);
AllPossibleMoves.push_back(Left2Down1);
AllPossibleMoves.push_back(Left1Down2);
AllPossibleMoves.push_back(Right1Up2);
AllPossibleMoves.push_back(Right2Up1);
AllPossibleMoves.push_back(Right2Down1);
AllPossibleMoves.push_back(Right1Down2);
}
KMMoveFilters::KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod)
: m_SingleSideBoardDimension(BoardDimension), m_PathLimitations(SlicingMethod)
{
AllPossibleMoves.push_back(Left1Up2);
AllPossibleMoves.push_back(Left2Up1);
AllPossibleMoves.push_back(Left2Down1);
AllPossibleMoves.push_back(Left1Down2);
AllPossibleMoves.push_back(Right1Up2);
AllPossibleMoves.push_back(Right2Up1);
AllPossibleMoves.push_back(Right2Down1);
AllPossibleMoves.push_back(Right1Down2);
}
const int Left1 = -1;
const int Left2 = -2;
const int Down1 = -1;
const int Down2 = -2;
const int Right1 = 1;
const int Right2 = 2;
const int Up1 = 1;
const int Up2 = 2;
KMMove KMMoveFilters::Left1Up2(Left1, Up2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left2Up1(Left2, Up1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left2Down1(Left2, Down1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Left1Down2(Left1, Down2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right1Up2(Right1, Up2, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right2Up1(Right2, Up1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right2Down1(Right2, Down1, DefaultBoardDimensionOnOneSide);
KMMove KMMoveFilters::Right1Down2(Right1, Down2, DefaultBoardDimensionOnOneSide);
KMRandomAccessMoveCollection KMMoveFilters::AllPossibleMoves;
KMRandomAccessMoveCollection KMMoveFilters::GetPossibleMoves(const KMBoardLocation CurrentLocation) const
{
KMRandomAccessMoveCollection PossibleMoves;
for (auto PossibeMove : AllPossibleMoves) {
KMMove *TempMove = new KMMove(PossibeMove);
TempMove->SetBoardDimension(m_SingleSideBoardDimension);
TempMove->SetOriginCalculateDestination(CurrentLocation);
if ((TempMove->IsValid()) && (IsNotPreviouslyVisited(*TempMove))) {
PossibleMoves.push_back(*TempMove);
}
}
return PossibleMoves;
}
bool KMMoveFilters::IsNotPreviouslyVisited(KMBoardLocation PossibleDestination) const
{
bool NotPrevioslyVisited = true;
if (!m_VisitedLocations.empty()) { // This is always a test, we can't move backwards
if (std::find(m_VisitedLocations.begin(), m_VisitedLocations.end(), PossibleDestination)
!= m_VisitedLocations.end()) {
NotPrevioslyVisited = false;
}
}
switch (m_PathLimitations) {
default :
throw std::runtime_error("KMPath::CheckMoveAgainstPreviousLocations : Unknown type of Path Limitation.");
case DenyByPreviousLocation :
// Always tested above.
break;
case DenyByPreviousRowOrColumn:
if ((!m_VisitedRows.empty()) && (!m_VisitedColumns.empty())) {
unsigned int PossibleRow = PossibleDestination.GetRow();
if (std::find(m_VisitedRows.begin(), m_VisitedRows.end(), PossibleRow) != m_VisitedRows.end()) {
NotPrevioslyVisited = false;
break;
}
unsigned int PossibleColum = PossibleDestination.GetColumn();
if (std::find(m_VisitedColumns.begin(), m_VisitedColumns.end(), PossibleColum) != m_VisitedColumns.end()) {
NotPrevioslyVisited = false;
}
}
break;
}
return NotPrevioslyVisited;
}
void KMMoveFilters::PushVisited(KMBoardLocation Location)
{
m_VisitedRows.push_back(Location.GetRow());
m_VisitedColumns.push_back(Location.GetColumn());
m_VisitedLocations.push_back(Location);
}
void KMMoveFilters::PopVisited()
{
m_VisitedRows.pop_back();
m_VisitedColumns.pop_back();
m_VisitedLocations.pop_back();
}
The problem was the static declaration of AllPossibleMoves, the memory leak in GetPossibleMoves may have been an additional contributor to the problem. In the CentOS C++11 version AllPossibleMoves was declared as static const, and was not initialized in the constructor, it was initialized outside as each of it's member moves are. This did not compile in Visual Studio 2012 C++. AllPossibleMoves was declared as static const for execution time reasons in the original version.
I am disappointed in the results since this is much slower than the CentOS version using C++11 compiled with g++. The computer I'm running this on is 2 years new than the CentOS computer and has 8GB of memory with an i7 processor.
First I present the working code, then I present the output of the program.
The final code that solves the problem is:
KMMoveFilters.h
#pragma once
/*
* KMMoveFilters.h
*
* Created on: Jun 20, 2016
* Author: pacmaninbw
*
* This class provides all the possible Knight moves for a specified location
* on the chess board. In the center of the chess board there are 8 possible
* moves. In the middle of the edge on the chess board there are 4 possible
* moves. In a corner of the chess board there are 2 possible moves. The
* location on the board provides the first filter.
* Slicing is used to allow the program to complete in a reasonable finite
* amount of time. The slicing method can be varied, the default slicing
* method is the knight can't return to any row or column it has previously
* visited. The slicing is the second filter.
*/
#ifndef KMMOVEFILTERS_H_
#define KMMOVEFILTERS_H_
#include <vector>
#include "KnightMoves.h"
#include "KMMove.h"
class KMMoveFilters {
private:
std::vector<KMBoardLocation> m_VisitedLocations;
std::vector<unsigned int> m_VisitedRows;
std::vector<unsigned int> m_VisitedColumns;
unsigned int m_SingleSideBoardDimension;
KnightMovesMethodLimitations m_PathLimitations;
KMRandomAccessMoveCollection AllPossibleMoves;
// The 8 possible moves the knight can make.
static KMMove Left1Up2;
static KMMove Left2Up1;
static KMMove Left2Down1;
static KMMove Left1Down2;
static KMMove Right1Up2;
static KMMove Right2Up1;
static KMMove Right2Down1;
static KMMove Right1Down2;
protected:
bool IsNotPreviouslyVisited(KMMove Move) const { return IsNotPreviouslyVisited(Move.GetNextLocation()); }
bool IsNotPreviouslyVisited(KMBoardLocation Destination) const;
public:
KMMoveFilters(void);
KMMoveFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod);
void ResetFilters(unsigned int BoardDimension, KnightMovesMethodLimitations SlicingMethod) {m_SingleSideBoardDimension = BoardDimension; m_PathLimitations = SlicingMethod; }
virtual ~KMMoveFilters(void);
void PushVisited(KMBoardLocation Location);
void PopVisited();
KMRandomAccessMoveCollection GetPossibleMoves(const KMBoardLocation CurrentLocation) const;
};
#endif /* KMMOVEFILTERS_H_ */
Only the changes in KMMoveFilters.cpp
KMRandomAccessMoveCollection KMMoveFilters::GetPossibleMoves(const KMBoardLocation CurrentLocation) const
{
KMRandomAccessMoveCollection SafeAllPossibleMoves = AllPossibleMoves;
KMRandomAccessMoveCollection PossibleMoves;
for (auto PossibleMove : SafeAllPossibleMoves) {
PossibleMove.SetBoardDimension(m_SingleSideBoardDimension);
PossibleMove.SetOriginCalculateDestination(CurrentLocation);
if ((PossibleMove.IsValid()) && (IsNotPreviouslyVisited(PossibleMove))) {
PossibleMoves.push_back(PossibleMove);
}
}
return PossibleMoves;
}
The resulting output
Select the number of the test case you want to run.
Test Case # Start Name Target Name Board Size Slicing Method
1 A3 H4 8 Can't return to previous row or column
2 A1 H8 8 Can't return to previous row or column
3 A8 H1 8 Can't return to previous row or column
4 B3 H4 8 Can't return to previous row or column
5 B3 H8 8 Can't return to previous row or column
6 C1 H4 8 Can't return to previous row or column
7 A3 H8 8 Can't return to previous row or column
8 A3 B5 8 Can't return to previous row or column
9 H4 A3 8 Can't return to previous row or column
10 D4 A8 8 Can't return to previous row or column
11 D4 E6 8 Can't return to previous row or column
12 A3 B5 12 Can't return to previous row or column
13 A3 B5 8 Can't return to previous location
14 A3 B5 26 Can't return to previous row or column
15 All of the above except for 13 and 14
16 All of the above (Go get lunch)
finished computation at 0
elapsed time: 0.209012 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 5 Resulting Paths
There were 323 attempted paths
The average path length is 4.8
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.0930054 Seconds
The point of origin for all path searches was A1
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 22 Resulting Paths
There were 160 attempted paths
The average path length is 6.36364
The median path length is 6
The longest path is 8 moves
The shortest path is 6 moves
finished computation at 0
elapsed time: 0.0950054 Seconds
The point of origin for all path searches was A8
The destination point for all path searches was H1
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 22 Resulting Paths
There were 160 attempted paths
The average path length is 6.36364
The median path length is 6
The longest path is 8 moves
The shortest path is 6 moves
finished computation at 0
elapsed time: 0.248014 Seconds
The point of origin for all path searches was B3
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 8 Resulting Paths
There were 446 attempted paths
The average path length is 5
The median path length is 5
The longest path is 7 moves
The shortest path is 3 moves
finished computation at 0
elapsed time: 0.251014 Seconds
The point of origin for all path searches was B3
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 39 Resulting Paths
There were 447 attempted paths
The average path length is 6.23077
The median path length is 7
The longest path is 7 moves
The shortest path is 5 moves
finished computation at 0
elapsed time: 0.17801 Seconds
The point of origin for all path searches was C1
The destination point for all path searches was H4
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 7 Resulting Paths
There were 324 attempted paths
The average path length is 4.85714
The median path length is 4
The longest path is 6 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.18201 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was H8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 36 Resulting Paths
There were 324 attempted paths
The average path length is 6
The median path length is 6
The longest path is 8 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.131008 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was B5
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 6 Resulting Paths
There were 243 attempted paths
The average path length is 3
The median path length is 3
The longest path is 5 moves
The shortest path is 1 moves
finished computation at 0
elapsed time: 0.17301 Seconds
The point of origin for all path searches was H4
The destination point for all path searches was A3
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 12 Resulting Paths
There were 318 attempted paths
The average path length is 5.66667
The median path length is 6
The longest path is 8 moves
The shortest path is 4 moves
finished computation at 0
elapsed time: 0.332019 Seconds
The point of origin for all path searches was D4
The destination point for all path searches was A8
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 24 Resulting Paths
There were 602 attempted paths
The average path length is 5.25
The median path length is 5
The longest path is 7 moves
The shortest path is 3 moves
finished computation at 0
elapsed time: 0.266015 Seconds
The point of origin for all path searches was D4
The destination point for all path searches was E6
The number of squares on each edge of the board is 8
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 21 Resulting Paths
There were 487 attempted paths
The average path length is 4.14286
The median path length is 5
The longest path is 7 moves
The shortest path is 1 moves
finished computation at 0
elapsed time: 1.86411 Seconds
The point of origin for all path searches was A3
The destination point for all path searches was B5
The number of squares on each edge of the board is 12
The slicing methodology used to further limit searches was no repeat visits to any rows or columns.
There are 6 Resulting Paths
There were 3440 attempted paths
The average path length is 3
The median path length is 3
The longest path is 5 moves
The shortest path is 1 moves
Overall Results
The average execution time is 0.335186 seconds
The median execution time is 0.209012 seconds
The longest execution time is 1.86411 seconds
The shortest execution time is 0.0930054 seconds
Overall Results with optimized version.
Overall Results
The average execution time is 0.00266682 seconds
The median execution time is 0.0020001 seconds
The longest execution time is 0.0140008 seconds
The shortest execution time is 0.001 seconds
CentOS version Overall Results
The average execution time is 0.00195405 seconds
The median execution time is 0.00103346 seconds
The longest execution time is 0.00130368 seconds
The shortest execution time is 0.000716237 seconds

ATLAS' clapack_sgesv with row-major storage order

I'm having a problem with ATLAS' method clapack_sgesv (corresponding FORTRAN method: sgesv.f) when I try to use it with matrices stored in row-major storage order.
I use Eigen3 for most linear algebra tasks in my application but have recently started to replace some internal Eigen routines with calls to ATLAS' cblas and clapack methods. My application must support switching the matrix storage order to row-major by defining Eigen's EIGEN_DEFAULT_TO_ROW_MAJOR flag. This of course works out of the box with Eigen's methods, but requires different code paths for the clapack_ calls. I've run into a problem when replacing Eigen's .partialPivLu().solve() call with ATLAS' clapack_sgesv method. Here is a minimal code example that illustrates the problem:
#include <iostream>
#define EIGEN_DEFAULT_TO_ROW_MAJOR
#include <eigen3/Eigen/Eigen>
extern "C" {
#include <clapack.h>
}
using namespace std;
int main()
{
Eigen::MatrixXf A( 4, 4 );
A << 0.680375 , 0.823295 , -0.444451 , -0.270431 ,
-0.211234 , -0.604897 , 0.10794 , 0.0268018 ,
0.566198 , -0.329554 , -0.0452059 , 0.904459 ,
0.59688 , 0.536459 , 0.257742 , 0.83239 ;
Eigen::MatrixXf B( 4, 4 );
B << 0.271423 , -0.967399 , -0.686642 , 0.997849 ,
0.434594 , -0.514226 , -0.198111 , -0.563486 ,
-0.716795 , -0.725537 , -0.740419 , 0.0258648 ,
0.213938 , 0.608353 , -0.782382 , 0.678224 ;
cout << "----- Eigen" << endl;
cout << "A = " << endl << A << endl;
cout << "B = " << endl << B << endl;
Eigen::MatrixXf X = A.partialPivLu().solve( B );
cout << "X = " << endl << X << endl;
cout << "AX = " << endl << A * X << endl;
cout << "----- ATLAS" << endl;
Eigen::VectorXi ipiv( 4 );
clapack_sgesv(
#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
CblasRowMajor,
#else
CblasColMajor,
#endif
A.rows(),
B.cols(),
A.data(),
#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
A.cols(),
#else
A.rows(),
#endif
ipiv.data(),
B.data(),
#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
B.cols()
#else
B.rows()
#endif
);
cout << "piv = " << ipiv.transpose() << endl;
cout << "LU = " << endl << A << endl;
cout << "X =" << endl << B << endl;
return 0;
}
I compile this with g++ -std=c++11 -Wall -Wextra -g -llapack -lcblas -latlas. The above clapack_sgesv call gives the same results as Eigen's solver as long as EIGEN_DEFAULT_TO_ROW_MAJOR is not defined.
----- Eigen
A =
0.680375 0.823295 -0.444451 -0.270431
-0.211234 -0.604897 0.10794 0.0268018
0.566198 -0.329554 -0.0452059 0.904459
0.59688 0.536459 0.257742 0.83239
B =
0.271423 -0.967399 -0.686642 0.997849
0.434594 -0.514226 -0.198111 -0.563486
-0.716795 -0.725537 -0.740419 0.0258648
0.213938 0.608353 -0.782382 0.678224
X =
4.29176 -3.45693 -3.46864 0.547927
-1.3688 2.04333 1.13806 0.735351
5.6716 -0.593909 -2.65158 -0.0154493
-3.69446 2.07672 1.6349 -0.0472447
AX =
0.271423 -0.967399 -0.686642 0.997849
0.434594 -0.514226 -0.198111 -0.563486
-0.716796 -0.725537 -0.740419 0.0258648
0.213938 0.608353 -0.782382 0.678224
----- ATLAS
piv = 0 2 3 3
LU =
0.680375 0.823295 -0.444451 -0.270431
0.832185 -1.01469 0.32466 1.12951
0.877281 0.183112 0.588201 0.862807
-0.310467 0.344235 -0.241085 -0.237964
X =
4.29176 -3.45694 -3.46864 0.547927
-1.3688 2.04333 1.13806 0.735351
5.6716 -0.593909 -2.65158 -0.0154493
-3.69446 2.07672 1.6349 -0.0472447
If I define it, the ATLAS' results are wrong.
----- Eigen
[... same as above ...]
----- ATLAS
piv = 1 1 3 3
LU =
0.823295 0.826405 -0.328474 -0.539844
-0.604897 0.288656 -0.595488 -0.757338
-0.329554 0.838543 1.29555 0.31797
0.536459 0.153548 1.10004 0.313854
X =
-2.21567 2.33841 -0.554441 1.45218
-2.60368 1.14776 -3.83383 1.63747
-5.05167 2.4991 -3.36881 3.08596
6.03571 -1.84576 8.32067 -4.90008
My first suspicion was of course that I had messed something up with the clapack_sgesv() call. But other than setting the storage order and switching the leading dimensions from the number of rows to the number of cols there seems nothing to be necessary.
Another really confusing thing I've noticed is the following: When I try to solve only for a single right-hand-side, the clapack_sgesv() call fails with Parameter 8 to routine clapack_sgesv was incorrect, ldb must be >= MAX(N,1): ldb=1 N=4. This does not make any sense mathematically.
I suspect that my error must be kind of obvious, but I don't see it.
What is wrong with my clapack_sgesv() call that causes it to fail in row-major storage order?
I've found my mistake. As explained in the ATLAS FAQ the right hand side is not treated like a matrix, but a collection of column-vectors that are adjacent in memory. This does not make a difference if the storage order is column-major, but it does for row-major storage order, because the elements of a column vector are no longer adjacent in memory. It works if one always stores RHS and solution "matrix" in column-major format.