Last active
February 9, 2020 04:11
-
-
Save lhuemill/f1273291e5f5e85e4b42e5c7614e60ef to your computer and use it in GitHub Desktop.
Magic_Cube2x2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__pycache__ | |
*.pyc | |
*.swp | |
build/ | |
results/ | |
target/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ./magic_cube2x2.cxx | |
// | |
// Library of Magic Cube 2x2 (2 by 2) routines. | |
// | |
// Copyright 2019 Louis Huemiller | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
// | |
#include <cstring> | |
#include <iostream> | |
#include <string> | |
#include <sstream> | |
#include "magic_cube2x2.h" | |
using namespace std; | |
const vector<char> MagicCube2x2::faces = { | |
'L', // Left | |
'R', // Right | |
'U', // Up | |
'D', // Down | |
'F', // Front | |
'B', // Back | |
}; | |
const vector<char> MagicCube2x2::colors = { | |
'G', // Green | |
'B', // Blue | |
'Y', // Yellow | |
'W', // White | |
'O', // Orange | |
'R', // Red | |
}; | |
const std::string MagicCube2x2::solved = "BBBB-GGGG-YYYY-WWWW-RRRR-OOOO"; | |
MagicCube2x2::MagicCube2x2(const string pos) | |
{ | |
if (pos.size() != sizeof(PosStr)) { | |
throw invalid_argument(string("MagicCube2x2::") + __FUNCTION__ | |
+ " Unexpected pos lenght of: " | |
+ to_string(pos.size()) | |
+ "\n Expected: " + to_string(sizeof(PosStr))); | |
} | |
memcpy(&this->state, pos.c_str(), sizeof(this->state)); | |
return; | |
} | |
void MagicCube2x2::rotate(char face) | |
{ | |
PosStr orig; | |
memcpy(&orig, &this->state, sizeof(orig)); | |
switch (face) { | |
case 'L': | |
this->state.lub = orig.ldb; | |
this->state.luf = orig.lub; | |
this->state.ldb = orig.ldf; | |
this->state.ldf = orig.luf; | |
this->state.ubl = orig.bdl; | |
this->state.ufl = orig.bul; | |
this->state.dbl = orig.fdl; | |
this->state.dfl = orig.ful; | |
this->state.ful = orig.ubl; | |
this->state.fdl = orig.ufl; | |
this->state.bul = orig.dbl; | |
this->state.bdl = orig.dfl; | |
break; | |
case 'R': | |
this->state.rub = orig.ruf; | |
this->state.ruf = orig.rdf; | |
this->state.rdb = orig.rub; | |
this->state.rdf = orig.rdb; | |
this->state.ubr = orig.fur; | |
this->state.ufr = orig.fdr; | |
this->state.dbr = orig.bur; | |
this->state.dfr = orig.bdr; | |
this->state.fur = orig.dfr; | |
this->state.fdr = orig.dbr; | |
this->state.bur = orig.ufr; | |
this->state.bdr = orig.ubr; | |
break; | |
case 'U': | |
this->state.ubl = orig.ufl; | |
this->state.ubr = orig.ubl; | |
this->state.ufl = orig.ufr; | |
this->state.ufr = orig.ubr; | |
this->state.lub = orig.ful; | |
this->state.luf = orig.fur; | |
this->state.rub = orig.bul; | |
this->state.ruf = orig.bur; | |
this->state.ful = orig.ruf; | |
this->state.fur = orig.rub; | |
this->state.bul = orig.luf; | |
this->state.bur = orig.lub; | |
break; | |
case 'D': | |
this->state.dbl = orig.dbr; | |
this->state.dbr = orig.dfr; | |
this->state.dfl = orig.dbl; | |
this->state.dfr = orig.dfl; | |
this->state.ldb = orig.bdr; | |
this->state.ldf = orig.bdl; | |
this->state.rdb = orig.fdr; | |
this->state.rdf = orig.fdl; | |
this->state.fdl = orig.ldb; | |
this->state.fdr = orig.ldf; | |
this->state.bdl = orig.rdb; | |
this->state.bdr = orig.rdf; | |
break; | |
case 'F': | |
this->state.ful = orig.fdl; | |
this->state.fur = orig.ful; | |
this->state.fdl = orig.fdr; | |
this->state.fdr = orig.fur; | |
this->state.luf = orig.dfl; | |
this->state.ldf = orig.dfr; | |
this->state.ruf = orig.ufl; | |
this->state.rdf = orig.ufr; | |
this->state.ufl = orig.ldf; | |
this->state.ufr = orig.luf; | |
this->state.dfl = orig.rdf; | |
this->state.dfr = orig.ruf; | |
break; | |
case 'B': | |
this->state.bul = orig.bur; | |
this->state.bur = orig.bdr; | |
this->state.bdl = orig.bul; | |
this->state.bdr = orig.bdl; | |
this->state.lub = orig.ubr; | |
this->state.ldb = orig.ubl; | |
this->state.rub = orig.dbr; | |
this->state.rdb = orig.dbl; | |
this->state.ubl = orig.rub; | |
this->state.ubr = orig.rdb; | |
this->state.dbl = orig.lub; | |
this->state.dbr = orig.ldb; | |
break; | |
default: | |
throw invalid_argument(string("MagicCube2x2::") + __FUNCTION__ | |
+ " Unexpected face value of: " + face); | |
} | |
return; | |
} | |
string MagicCube2x2::str(void) | |
{ | |
return string((char *) &this->state, sizeof(this->state)); | |
} | |
string MagicCube2x2::displayStr(void) | |
{ | |
ostringstream result; | |
result << " " << this->state.ubl << this->state.ubr << endl; | |
result << " " << this->state.ufl << this->state.ufr << endl; | |
result << this->state.lub << this->state.luf | |
<< this->state.ful << this->state.fur | |
<< this->state.ruf << this->state.rub | |
<< this->state.bur << this->state.bul << endl; | |
result << this->state.ldb << this->state.ldf | |
<< this->state.fdl << this->state.fdr | |
<< this->state.rdf << this->state.rdb | |
<< this->state.bdr << this->state.bdl << endl; | |
result << " " << this->state.dfl << this->state.dfr << endl; | |
result << " " << this->state.dbl << this->state.dbr; | |
return result.str(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ./magic_cube2x2.h | |
// | |
// Declaration of Magic Cube 2x2 (2 by 2) Library Interfaces. | |
// | |
// Copyright 2019 Louis Huemiller | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
// | |
#include <string> | |
#include <vector> | |
class MagicCube2x2 { | |
public: | |
static const std::vector<char> faces; | |
static const std::vector<char> colors; | |
struct PosStr { | |
char lub; // Left Upper Back | |
char luf; // Left Upper Front | |
char ldb; // Left Upper Back | |
char ldf; // Left Upper Front | |
char dash1; | |
char rub; // Right Upper Back | |
char ruf; // Right Upper Front | |
char rdb; // Right Down Back | |
char rdf; // Right Down Front | |
char dash2; | |
char ubl; // Upper Back Left | |
char ubr; // Upper Back Right | |
char ufl; // Upper Front Left | |
char ufr; // Upper Front Right | |
char dash3; | |
char dbl; // Down Back Left | |
char dbr; // Down Back Right | |
char dfl; // Down Front Left | |
char dfr; // Down Front Right | |
char dash4; | |
char ful; // Front Upper Left | |
char fur; // Front Upper Right | |
char fdl; // Front Down Left | |
char fdr; // Front Down Right | |
char dash5; | |
char bul; // Back Upper Left | |
char bur; // Back Upper Right | |
char bdl; // Back Down Left | |
char bdr; // Back Down Right | |
}; | |
// Solved condition of cube using standard coloring, | |
// with colors of faces as follows: | |
// Left: Blue | |
// Right: Green | |
// Up: Yellow | |
// Down: White | |
// Front: Red | |
// Back: Orange | |
static const std::string solved; | |
MagicCube2x2(const std::string pos); | |
void rotate(char face); | |
std::string str(void); | |
std::string expr(void); | |
std::string displayStr(void); | |
private: | |
PosStr state; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python3 | |
"""Library of Magic Cube 2x2 (2 by 2) routines. | |
Copyright 2019 Louis Huemiller | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
""" | |
from __future__ import print_function | |
import copy | |
faces = {'L': 'Left', | |
'R': 'Right', | |
'U': 'Up', | |
'D': 'Down', | |
'F': 'Front', | |
'B': 'Back'} | |
colors = {'G': 'Green', | |
'B': 'Blue', | |
'Y': 'Yellow', | |
'W': 'White', | |
'O': 'Orange', | |
'R': 'Red'} | |
class PosStrOffset: | |
LUB = 0 | |
LUF = 1 | |
LDB = 2 | |
LDF = 3 | |
DASH1 = 4 | |
RUB = 5 | |
RUF = 6 | |
RDB = 7 | |
RDF = 8 | |
DASH2 = 9 | |
UBL = 10 | |
UBR = 11 | |
UFL = 12 | |
UFR = 13 | |
DASH3 = 14 | |
DBL = 15 | |
DBR = 16 | |
DFL = 17 | |
DFR = 18 | |
DASH4 = 19 | |
FUL = 20 | |
FUR = 21 | |
FDL = 22 | |
FDR = 23 | |
DASH5 = 24 | |
BUL = 25 | |
BUR = 26 | |
BDL = 27 | |
BDR = 28 | |
# Solved condition of cube using standard coloring, | |
# with colors of faces as follows: | |
# Left: Blue | |
# Right: Green | |
# Up: Yellow | |
# Down: White | |
# Front: Red | |
# Back: Orange | |
solved = 'BBBB-GGGG-YYYY-WWWW-RRRR-OOOO' | |
class MagicCube2x2: | |
def __init__(self, pos = solved): | |
if len(pos) != len(solved): | |
raise ValueError('Unexpected pos length of: %u, expected: %u' | |
% (len(pos), len(solved))) | |
self.state = {} | |
self.state['lub'] = pos[PosStrOffset.LUB] | |
self.state['luf'] = pos[PosStrOffset.LUF] | |
self.state['ldb'] = pos[PosStrOffset.LDB] | |
self.state['ldf'] = pos[PosStrOffset.LDF] | |
self.state['rub'] = pos[PosStrOffset.RUB] | |
self.state['ruf'] = pos[PosStrOffset.RUF] | |
self.state['rdb'] = pos[PosStrOffset.RDB] | |
self.state['rdf'] = pos[PosStrOffset.RDF] | |
self.state['ubl'] = pos[PosStrOffset.UBL] | |
self.state['ubr'] = pos[PosStrOffset.UBR] | |
self.state['ufl'] = pos[PosStrOffset.UFL] | |
self.state['ufr'] = pos[PosStrOffset.UFR] | |
self.state['dbl'] = pos[PosStrOffset.DBL] | |
self.state['dbr'] = pos[PosStrOffset.DBR] | |
self.state['dfl'] = pos[PosStrOffset.DFL] | |
self.state['dfr'] = pos[PosStrOffset.DFR] | |
self.state['ful'] = pos[PosStrOffset.FUL] | |
self.state['fur'] = pos[PosStrOffset.FUR] | |
self.state['fdl'] = pos[PosStrOffset.FDL] | |
self.state['fdr'] = pos[PosStrOffset.FDR] | |
self.state['bul'] = pos[PosStrOffset.BUL] | |
self.state['bur'] = pos[PosStrOffset.BUR] | |
self.state['bdl'] = pos[PosStrOffset.BDL] | |
self.state['bdr'] = pos[PosStrOffset.BDR] | |
def rotate(self, face): | |
orig = copy.copy(self.state) | |
if face == 'L': | |
self.state['lub'] = orig['ldb'] | |
self.state['luf'] = orig['lub'] | |
self.state['ldb'] = orig['ldf'] | |
self.state['ldf'] = orig['luf'] | |
self.state['ubl'] = orig['bdl'] | |
self.state['ufl'] = orig['bul'] | |
self.state['dbl'] = orig['fdl'] | |
self.state['dfl'] = orig['ful'] | |
self.state['ful'] = orig['ubl'] | |
self.state['fdl'] = orig['ufl'] | |
self.state['bul'] = orig['dbl'] | |
self.state['bdl'] = orig['dfl'] | |
elif face == 'R': | |
self.state['rub'] = orig['ruf'] | |
self.state['ruf'] = orig['rdf'] | |
self.state['rdb'] = orig['rub'] | |
self.state['rdf'] = orig['rdb'] | |
self.state['ubr'] = orig['fur'] | |
self.state['ufr'] = orig['fdr'] | |
self.state['dbr'] = orig['bur'] | |
self.state['dfr'] = orig['bdr'] | |
self.state['fur'] = orig['dfr'] | |
self.state['fdr'] = orig['dbr'] | |
self.state['bur'] = orig['ufr'] | |
self.state['bdr'] = orig['ubr'] | |
elif face == 'U': | |
self.state['ubl'] = orig['ufl'] | |
self.state['ubr'] = orig['ubl'] | |
self.state['ufl'] = orig['ufr'] | |
self.state['ufr'] = orig['ubr'] | |
self.state['lub'] = orig['ful'] | |
self.state['luf'] = orig['fur'] | |
self.state['rub'] = orig['bul'] | |
self.state['ruf'] = orig['bur'] | |
self.state['ful'] = orig['ruf'] | |
self.state['fur'] = orig['rub'] | |
self.state['bul'] = orig['luf'] | |
self.state['bur'] = orig['lub'] | |
elif face == 'D': | |
self.state['dbl'] = orig['dbr'] | |
self.state['dbr'] = orig['dfr'] | |
self.state['dfl'] = orig['dbl'] | |
self.state['dfr'] = orig['dfl'] | |
self.state['ldb'] = orig['bdr'] | |
self.state['ldf'] = orig['bdl'] | |
self.state['rdb'] = orig['fdr'] | |
self.state['rdf'] = orig['fdl'] | |
self.state['fdl'] = orig['ldb'] | |
self.state['fdr'] = orig['ldf'] | |
self.state['bdl'] = orig['rdb'] | |
self.state['bdr'] = orig['rdf'] | |
elif face == 'F': | |
self.state['ful'] = orig['fdl'] | |
self.state['fur'] = orig['ful'] | |
self.state['fdl'] = orig['fdr'] | |
self.state['fdr'] = orig['fur'] | |
self.state['luf'] = orig['dfl'] | |
self.state['ldf'] = orig['dfr'] | |
self.state['ruf'] = orig['ufl'] | |
self.state['rdf'] = orig['ufr'] | |
self.state['ufl'] = orig['ldf'] | |
self.state['ufr'] = orig['luf'] | |
self.state['dfl'] = orig['rdf'] | |
self.state['dfr'] = orig['ruf'] | |
elif face == 'B': | |
self.state['bul'] = orig['bur'] | |
self.state['bur'] = orig['bdr'] | |
self.state['bdl'] = orig['bul'] | |
self.state['bdr'] = orig['bdl'] | |
self.state['lub'] = orig['ubr'] | |
self.state['ldb'] = orig['ubl'] | |
self.state['rub'] = orig['dbr'] | |
self.state['rdb'] = orig['dbl'] | |
self.state['ubl'] = orig['rub'] | |
self.state['ubr'] = orig['rdb'] | |
self.state['dbl'] = orig['lub'] | |
self.state['dbr'] = orig['ldb'] | |
else: | |
raise ValueError('Unexpected face value of: %s' % face) | |
def __str__(self): | |
result = '%c%c%c%c' % ( | |
self.state['lub'], | |
self.state['luf'], | |
self.state['ldb'], | |
self.state['ldf']) | |
result += '-%c%c%c%c' % ( | |
self.state['rub'], | |
self.state['ruf'], | |
self.state['rdb'], | |
self.state['rdf']) | |
result += '-%c%c%c%c' % ( | |
self.state['ubl'], | |
self.state['ubr'], | |
self.state['ufl'], | |
self.state['ufr']) | |
result += '-%c%c%c%c' % ( | |
self.state['dbl'], | |
self.state['dbr'], | |
self.state['dfl'], | |
self.state['dfr']) | |
result += '-%c%c%c%c' % ( | |
self.state['ful'], | |
self.state['fur'], | |
self.state['fdl'], | |
self.state['fdr']) | |
result += '-%c%c%c%c' % ( | |
self.state['bul'], | |
self.state['bur'], | |
self.state['bdl'], | |
self.state['bdr']) | |
return result | |
def __expr__(self): | |
result = '\'' | |
result += self.__str__() | |
result += '\'' | |
return result | |
def displayStr(self): | |
result = ' %c%c\n' % (self.state['ubl'], self.state['ubr']) | |
result += ' %c%c\n' % (self.state['ufl'], self.state['ufr']) | |
result += '%c%c%c%c%c%c%c%c\n' % (self.state['lub'], self.state['luf'], | |
self.state['ful'], self.state['fur'], self.state['ruf'], | |
self.state['rub'], self.state['bur'], self.state['bul']) | |
result += '%c%c%c%c%c%c%c%c\n' % (self.state['ldb'], self.state['ldf'], | |
self.state['fdl'], self.state['fdr'], self.state['rdf'], | |
self.state['rdb'], self.state['bdr'], self.state['bdl']) | |
result += ' %c%c\n' % (self.state['dfl'], self.state['dfr']) | |
result += ' %c%c\n' % (self.state['dbl'], self.state['dbr']) | |
return result | |
if __name__ == '__main__': | |
init = MagicCube2x2('Gabc-Bdef-Yghi-Wjkl-Omno-Rpqr') | |
print(init.displayStr()) | |
rotated = copy.copy(init) | |
print('B') | |
rotated.rotate('B') | |
print(rotated.displayStr()) | |
# print(foo001.displayStr()) | |
# foo001.rotate('L') | |
# foo001.rotate('R') | |
# foo001.rotate('U') | |
# foo001.rotate('D') | |
# foo001.rotate('F') | |
# foo001.rotate('B') | |
# print(foo001.displayStr()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# magic_cube2x2/Makefile | |
# | |
all: binaries scripts | |
.PHONY: clean | |
clean: ## remove build artifacts | |
rm -rf ./build/ ./target/ *.pyc __pycache__/ | |
.PHONY: scripts | |
scripts: ./target/python/magic_cube2x2.py ./target/python/permutations2x2 | |
./target/python/magic_cube2x2.py: ./magic_cube2x2.py | |
mkdir -p ./target/python/ | |
cp ./magic_cube2x2.py ./target/python/magic_cube2x2.py | |
./target/python/permutations2x2: ./permutations2x2 | |
mkdir -p ./target/python/ | |
cp ./permutations2x2 ./target/python/permutations2x2 | |
.PHONY: binaries | |
binaries: ./target/permutations2x2 | |
./target/permutations2x2: ./permutations2x2.cxx ./build/magic_cube2x2.a | |
mkdir -p ./target/ | |
g++ -std=c++11 -O3 -o ./target/permutations2x2 permutations2x2.cxx ./build/magic_cube2x2.a | |
./build/magic_cube2x2.o: ./magic_cube2x2.cxx ./magic_cube2x2.h | |
mkdir -p ./build/ | |
g++ -std=c++11 -O3 -c -o ./build/magic_cube2x2.o ./magic_cube2x2.cxx | |
./build/magic_cube2x2.a: ./build/magic_cube2x2.o | |
ar rc ./build/magic_cube2x2.a ./build/magic_cube2x2.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
"""Generate list of all Magic Cube 2x2 Permutations | |
Copyright 2019 Louis Huemiller | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
""" | |
from __future__ import print_function | |
import argparse | |
import copy | |
import collections | |
import enum | |
import itertools | |
import os | |
import pkgutil | |
import subprocess | |
import sys | |
import time | |
import magic_cube2x2 | |
def FloatOrDash(val): | |
if type(val) == float: | |
return '%5.2g' % val | |
return '-' | |
class State(): | |
class States(enum.IntEnum): | |
INIT = 1 | |
GENERATE = 2 | |
REPORT = 3 | |
__nemonics = { | |
'INIT': 'INIT', | |
'GENERATE': 'GEN', | |
'REPORT': 'REPT', | |
} | |
def __init__(self): | |
self.set_state(list(State.States)[0]) | |
def state(self): | |
return self.__state | |
def set_state(self, state): | |
assert isinstance(state, State.States) | |
self.__state = state | |
self.__state_start_time = time.time() | |
def nemonic(self): | |
return self.__nemonics[self.__state.name] | |
def state_start_time(self): | |
return self.__state_start_time | |
class MemStats(): | |
def __init__(self): | |
# Attempt to obtain page size, through the use of getconf(1). | |
try: | |
self.__page_size = int(subprocess.check_output("getconf PAGESIZE", | |
shell=True)) | |
print('# Page_size:', self.__page_size) | |
except (ValueError, subprocess.CalledProcessError, OSError): | |
self.__page_size = None # PageSize Unknown | |
print('# Page_size:', 'Unknown') | |
# When PageSize is known, attempt to open /proc/self/statm. | |
self.__f_statm = None | |
if self.__page_size: | |
print('# PageSize Known') | |
try: | |
self.__f_statm = open('/proc/self/statm', 'r') | |
except: | |
self.__f_statm = None | |
print('# Failed to open /proc/self/statm') | |
def stats(self): | |
''' | |
Returns dictionary with current memory stats. Dictionary | |
contains the following keys: | |
VmSize - Virtual Memory | |
Resident - Resident Set Size | |
ResidentShared - Resident Shared | |
Text - Text (code) | |
DataStack - Data plus Stack | |
Corresponding value of each key is decimal number of bytes or | |
str('-'), if value could not be determined. Note: On success, | |
all values are converted as needed to bytes. | |
''' | |
if self.__f_statm: | |
# TODO: Why does statm file have to be re-opened, instead of | |
# just seeking to the beginning of the file? | |
# self.__f_statm.seek(0, 0) | |
self.__f_statm = open('/proc/self/statm', 'r') | |
vals = self.__f_statm.readline().split(' ') | |
return {'VmSize':(int(vals[0]) * self.__page_size), | |
'Resident':(int(vals[1]) * self.__page_size), | |
'ResidentShared':(int(vals[2]) * self.__page_size), | |
'Text':(int(vals[3]) * self.__page_size), | |
'DataStack':(int(vals[4]) * self.__page_size)} | |
else: | |
return {'VmSize':'-', 'Resident':'-', 'ResidentShared':'-', | |
'Text':'-', 'DataStack':'-'} | |
class DictStat(dict): | |
def __reset_per_interval_stats(self): | |
self.__contains_num = 0 | |
self.__contains_total_time = 0.0 | |
self.__contains_max_time = 0.0 | |
self.__get_num = 0 | |
self.__get_total_time = 0.0 | |
self.__get_max_time = 0.0 | |
self.__set_num = 0 | |
self.__set_total_time = 0.0 | |
self.__set_max_time = 0.0 | |
def __init__(self, val): | |
# Initialize overall stats. These stats | |
# represent operations from time immermorial. | |
self.__overall_contains_num = 0 | |
self.__overall_contains_total_time = 0.0 | |
self.__overall_contains_max_time = 0.0 | |
self.__overall_get_num = 0 | |
self.__overall_get_total_time = 0.0 | |
self.__overall_get_max_time = 0.0 | |
self.__overall_set_num = 0 | |
self.__overall_set_total_time = 0.0 | |
self.__overall_set_max_time = 0.0 | |
# Initialize per-interval stats. These stats | |
# represent operations since stats were previously | |
# obtained. | |
self.__reset_per_interval_stats() | |
dict.__init__(self) | |
for key, val in val.items(): | |
self[key] = val | |
return None | |
def __contains__(self, key): | |
t1 = time.time() | |
rv = dict.__contains__(self, key) | |
t2 = time.time() | |
td = t2 - t1 | |
# self.__contains_num = self.__contains_num + 1 | |
self.__contains_num += 1 | |
self.__contains_total_time += td | |
self.__contains_max_time = max(self.__contains_max_time, td) | |
self.__overall_contains_num += 1 | |
self.__overall_contains_total_time += td | |
self.__overall_contains_max_time = max( | |
self.__overall_contains_max_time, td) | |
return rv | |
def __getitem__(self, key): | |
t1 = time.time() | |
rv = dict.__getitem__(self, key) | |
t2 = time.time() | |
td = t2 - t1 | |
self.__get_num += 1 | |
self.__get_total_time += td | |
self.__get_max_time = max(self.__get_max_time, td) | |
self.__overall_get_num += 1 | |
self.__overall_get_total_time += td | |
self.__overall_get_max_time = max(self.__overall_get_max_time, td) | |
return rv | |
def __setitem__(self, key, val): | |
t1 = time.time() | |
rv = dict.__setitem__(self,key, val) | |
t2 = time.time() | |
td = t2 - t1 | |
self.__set_num += 1 | |
self.__set_total_time += td | |
self.__set_max_time = max(self.__set_max_time, td) | |
self.__overall_set_num += 1 | |
self.__overall_set_total_time += td | |
self.__overall_set_max_time = max(self.__overall_set_max_time, td) | |
return rv | |
def stats(self): | |
rv = {} | |
rv['contains_num'] = self.__contains_num | |
rv['contains_avg_time'] = ((self.__contains_total_time | |
/ self.__contains_num) | |
if self.__contains_num != 0 else None) | |
rv['contains_max_time'] = self.__contains_max_time | |
rv['get_num'] = self.__get_num | |
rv['get_avg_time'] = ((self.__get_total_time | |
/ self.__get_num) | |
if self.__get_num != 0 else None) | |
rv['get_max_time'] = self.__get_max_time | |
rv['set_num'] = self.__set_num | |
rv['set_avg_time'] = ((self.__set_total_time | |
/ self.__set_num) | |
if self.__set_num != 0 else None) | |
rv['set_max_time'] = self.__set_max_time | |
# Reset per-interval stats. | |
self.__reset_per_interval_stats() | |
return rv | |
def stats_overall(self): | |
rv = {} | |
rv['contains_num'] = self.__overall_contains_num | |
rv['contains_avg_time'] = ((self.__overall_contains_total_time | |
/ self.__overall_contains_num) | |
if self.__overall_contains_num != 0 else None) | |
rv['contains_max_time'] = self.__overall_contains_max_time | |
rv['get_num'] = self.__overall_get_num | |
rv['get_avg_time'] = ((self.__overall_get_total_time | |
/ self.__overall_get_num) | |
if self.__overall_get_num != 0 else None) | |
rv['get_max_time'] = self.__overall_get_max_time | |
rv['set_num'] = self.__overall_set_num | |
rv['set_avg_time'] = ((self.__overall_set_total_time | |
/ self.__overall_set_num) | |
if self.__overall_set_num != 0 else None) | |
rv['set_max_time'] = self.__overall_set_max_time | |
return rv | |
state = State() | |
mem_stats = MemStats() | |
print('# Python Version:\n# ', sys.version.replace('\n', '\n# ')) | |
Node = collections.namedtuple('Node', 'permutation, sequence') | |
parser = argparse.ArgumentParser(description='Magic Cube 2x2 Permutations') | |
parser.add_argument('--max_depth', default=None) | |
parser.add_argument('--results_suppress', action='store_true', default=False) | |
args = parser.parse_args() | |
print('# max_depth:', args.max_depth) | |
print('# results_suppress:', args.results_suppress) | |
root = Node(magic_cube2x2.solved, '') | |
permutations = DictStat({root.permutation: root.sequence}) | |
depth = None | |
leaves = [] | |
leaves_next = [root] | |
permutations_reported = 0 | |
gen_stats_heading_displayed = False | |
rept_stats_heading_displayed = False | |
start_time = prev_stat_time = time.time() | |
print('# start_time:', start_time) | |
def print_stats(always_display=False): | |
global gen_stats_heading_displayed | |
global rept_stats_heading_displayed | |
global prev_stat_time | |
current_time = time.time() | |
# Display stats if any of the following are true: | |
# + always_display argument is true | |
# + In current state less then 10 seconds and its been longer | |
# then 0.1 seconds since stats were previously displayed | |
# + In current state less then 100 seconds and its been longer | |
# then 1.0 seconds since stats were previously displayed | |
# + In current state less then 1000 seconds and its been longer | |
# then 10.0 seconds since stats were previously displayed | |
# + Stats have not been display for >= 1 minute | |
if (always_display | |
or (prev_stat_time == None) | |
or ((current_time - state.state_start_time() <= 10.0) | |
and (current_time - prev_stat_time >= 0.1)) | |
or ((current_time - state.state_start_time() < 100.0) | |
and (current_time - prev_stat_time >= 1.0)) | |
or ((current_time - state.state_start_time() < 1000.0) | |
and (current_time - prev_stat_time >= 10.0)) | |
or (current_time - prev_stat_time >= 60.0) ): | |
if state.state() == State.States.GENERATE: | |
if not gen_stats_heading_displayed: | |
print('# ', ' ' * 14, 'Time', ' ' * 12, | |
' |', ' ' * 81, | |
' | Contains ', | |
' | Set') | |
print('# Wall, Usr, Sys' | |
+ ' | State, Permutations, Depth,' | |
+ ' Leaves, Leaves_next, VmSize,' | |
+ ' Resident' | |
+ ' | num, avg, max' | |
+ ' | num, avg, max') | |
gen_stats_heading_displayed = True | |
stats = mem_stats.stats() | |
(utime, stime) = os.times()[0:2] | |
print('# %12.2f, %9.2f, %9.2f' | |
% (current_time - start_time, utime, stime), end='') | |
print(' | %5s, %12d, %5d, %12d, %12d, %12s, %12s' | |
% (state.nemonic(), | |
len(permutations), | |
depth, | |
len(leaves), | |
len(leaves_next), | |
stats['VmSize'], stats['Resident']), end='') | |
stats = permutations.stats() | |
print(' | %8u, %8s, %8s' % (stats['contains_num'], | |
FloatOrDash(stats['contains_avg_time']), | |
FloatOrDash(stats['contains_max_time'])), end='') | |
print(' | %8u, %8s, %8s' % (stats['set_num'], | |
FloatOrDash(stats['set_avg_time']), | |
FloatOrDash(stats['set_max_time']))) | |
elif state.state() == State.States.REPORT: | |
if not rept_stats_heading_displayed: | |
print('# ', ' ' * 14, 'Time', ' ' * 12, ' |') | |
print('# Wall, Usr, Sys' | |
+ ' | State, Remaining') | |
rept_stats_heading_displayed = True | |
(utime, stime) = os.times()[0:2] | |
print('# %12.2f, %9.2f, %9.2f | %5s, %12d' | |
% (current_time - start_time, utime, stime, | |
state.nemonic(), | |
len(permutations) - permutations_reported)) | |
prev_stat_time = current_time | |
sys.stdout.flush() | |
state.set_state(State.States.GENERATE) | |
for depth in itertools.count(1): | |
if (args.max_depth != None) and (depth > int(args.max_depth)): | |
break | |
if not leaves_next: | |
break | |
leaves = leaves_next | |
leaves_next = [] | |
print_stats(True) | |
while leaves: | |
leaf = leaves.pop() | |
for face in magic_cube2x2.faces: | |
child = magic_cube2x2.MagicCube2x2(leaf.permutation) | |
for direction in ["", "2", "\'"]: | |
child.rotate(face) | |
if child.__str__() not in permutations: | |
sequence = leaf.sequence + face + direction | |
permutations[child.__str__()] = sequence | |
leaves_next.append(Node(child.__str__(), | |
sequence)) | |
print_stats() | |
print_stats() | |
print_stats() | |
print_stats(True) | |
print('# num_permutations:', len(permutations)) | |
state.set_state(State.States.REPORT) | |
print_stats(True) | |
for key, value in permutations.items(): | |
if not args.results_suppress: | |
print(key, value) | |
permutations_reported += 1 | |
print_stats() | |
print_stats(True) | |
current_time = time.time() | |
print('# Wall_Time: %.2f' % (current_time - start_time)) | |
(utime, stime) = os.times()[0:2] | |
print('# User_Time: %.2f' % (utime)) | |
print('# Sys_Time: %.2f' % (stime)) | |
stats = permutations.stats_overall() | |
print('# Stats:') | |
for key in sorted (stats): | |
print('# %s: %s' % (key, stats[key])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ./permutations2x2.cxx | |
// | |
// Generate list of all Magic Cube 2x2 Permutations | |
// | |
// Copyright 2019 Louis Huemiller | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
#include <assert.h> | |
#include <climits> | |
#include <cstdlib> | |
#include <deque> | |
#include <fstream> | |
#include <iomanip> | |
#include <iostream> | |
#include <map> | |
#include <unistd.h> | |
#include <unordered_map> | |
#include <sys/time.h> | |
#include <sys/times.h> | |
#include <getopt.h> | |
#include "magic_cube2x2.h" | |
using namespace std; | |
#define TS_DIFF2DOUBLE(a, b) \ | |
(((double) ((b)->tv_sec - (a)->tv_sec)) \ | |
+ (((double)((b)->tv_nsec - (a)->tv_nsec)) / 1.0e9) ) | |
void print_stats(bool always_display=false); | |
class DictStat { | |
public: | |
void reset_per_interval_stats() { | |
contains_num = 0; | |
contains_total_time = 0.0; | |
contains_max_time = 0.0; | |
get_num = 0; | |
get_total_time = 0.0; | |
get_max_time = 0.0; | |
set_num = 0; | |
set_total_time = 0.0; | |
set_max_time = 0.0; | |
} | |
// TODO: Create and use as return value a structure instead of a map. | |
// Current implementation has issue in that _num values are | |
// returned as map values of type double, but they should be | |
// of type unsinged long. | |
map<string, double> stats() { | |
map<string, double> rv; | |
rv["contains_num"] = contains_num; | |
rv["contains_avg_time"] = (contains_num) | |
? contains_total_time / contains_num : 3.0; | |
rv["contains_max_time"] = contains_max_time; | |
rv["get_num"] = get_num; | |
rv["get_avg_time"] = (get_num) | |
? get_total_time / get_num : 0.0; | |
rv["get_max_time"] = get_max_time; | |
rv["set_num"] = set_num; | |
rv["set_avg_time"] = (set_num) | |
? set_total_time / set_num : 0.0; | |
rv["set_max_time"] = set_max_time; | |
// Reset per-interval stats. | |
reset_per_interval_stats(); | |
return rv; | |
} | |
// TODO: Create and use as return value a structure instead of a map. | |
// Current implementation has issue in that _num values are | |
// returned as map values of type double, but they should be | |
map<string, double> stats_overall() { | |
map<string, double> rv; | |
rv["contains_num"] = overall_contains_num; | |
rv["contains_avg_time"] = (overall_contains_num) | |
? overall_contains_total_time / overall_contains_num : 0.0; | |
rv["contains_max_time"] = overall_contains_max_time; | |
rv["get_num"] = overall_get_num; | |
rv["get_avg_time"] = (overall_get_num) | |
? overall_get_total_time / overall_get_num : 0.0; | |
rv["get_max_time"] = overall_get_max_time; | |
rv["set_num"] = overall_set_num; | |
rv["set_avg_time"] = (overall_set_num) | |
? overall_set_total_time / overall_set_num : 0.0; | |
rv["set_max_time"] = overall_set_max_time; | |
return rv; | |
} | |
std::unordered_map<string, string>::iterator begin() noexcept { | |
return data.begin(); | |
} | |
std::unordered_map<string, string>::iterator end() noexcept { | |
return data.end(); | |
} | |
// TODO: Intercept iterator dereference. Accumulate its stats | |
// into get_num, get_total_time, and get_max_time. | |
void insert(pair<string, string> val) { | |
int rv_int; | |
struct timespec start_time, end_time; | |
double td; | |
set_num++; | |
overall_set_num++; | |
rv_int = clock_gettime(CLOCK_REALTIME, &start_time); | |
assert(rv_int == 0); | |
(void) data.insert(val); | |
rv_int = clock_gettime(CLOCK_REALTIME, &end_time); | |
assert(rv_int == 0); | |
td = TS_DIFF2DOUBLE(&start_time, &end_time); | |
set_total_time += td; | |
overall_set_total_time += td; | |
if (td > set_max_time) { set_max_time = td; } | |
if (td > overall_set_max_time) { overall_set_max_time = td; } | |
} | |
std::unordered_map<string, string>::iterator find(const string& k) { | |
int rv_int; | |
struct timespec start_time, end_time; | |
double td; | |
std::unordered_map<string, string>::iterator rv; | |
contains_num++; | |
overall_contains_num++; | |
rv_int = clock_gettime(CLOCK_REALTIME, &start_time); | |
assert(rv_int == 0); | |
rv = data.find(k); | |
rv_int = clock_gettime(CLOCK_REALTIME, &end_time); | |
assert(rv_int == 0); | |
td = TS_DIFF2DOUBLE(&start_time, &end_time); | |
contains_total_time += td; | |
overall_contains_total_time += td; | |
if (td > get_max_time) { contains_max_time = td; } | |
if (td > overall_get_max_time) { overall_contains_max_time = td; } | |
return rv; | |
} | |
pair<std::unordered_map<string, string>::iterator, bool> | |
emplace(string k, string v) { | |
int rv_int; | |
struct timespec start_time, end_time; | |
double td; | |
pair<std::unordered_map<string, string>::iterator, bool> rv; | |
set_num++; | |
overall_set_num++; | |
rv_int = clock_gettime(CLOCK_REALTIME, &start_time); | |
assert(rv_int == 0); | |
rv = data.emplace(k, v); | |
rv_int = clock_gettime(CLOCK_REALTIME, &end_time); | |
assert(rv_int == 0); | |
td = TS_DIFF2DOUBLE(&start_time, &end_time); | |
set_total_time += td; | |
overall_set_total_time += td; | |
if (td > set_max_time) { set_max_time = td; } | |
if (td > overall_set_max_time) { overall_set_max_time = td; } | |
return rv; | |
} | |
// TODO: use size_type instead of size_t | |
size_t size() const noexcept { | |
return data.size(); | |
} | |
private: | |
unsigned long contains_num = 0; | |
double contains_total_time = 0.0; | |
double contains_max_time = 0.0; | |
unsigned long get_num = 0; | |
double get_total_time = 0.0; | |
double get_max_time = 0.0; | |
unsigned long set_num = 0; | |
double set_total_time = 0.0; | |
double set_max_time = 0.0; | |
unsigned long overall_contains_num = 0; | |
double overall_contains_total_time = 0.0; | |
double overall_contains_max_time = 0.0; | |
unsigned long overall_get_num = 0; | |
double overall_get_total_time = 0.0; | |
double overall_get_max_time = 0.0; | |
unsigned long overall_set_num = 0; | |
double overall_set_total_time = 0.0; | |
double overall_set_max_time = 0.0; | |
// TODO: Provide a command-line method of selecting which | |
// type (i.e. unordered_map, map) that is used to store | |
// the permutations. | |
unordered_map<string, string> data; | |
// map<string, string> data; | |
}; | |
class State { | |
public: | |
enum States { INIT=1, GENERATE=2, REPORT=3 }; | |
map<States, string> nemonic_map = { | |
{INIT, "INIT"}, | |
{GENERATE, "GEN"}, | |
{REPORT, "REPT"}, | |
}; | |
States state; | |
struct timespec prog_start_time; | |
struct timespec current_state_start_time; | |
struct timespec prev_stat_time; | |
unsigned int depth; | |
bool gen_stats_heading_displayed; | |
bool rept_stats_heading_displayed; | |
deque<pair<string, string> > leaves; | |
deque<pair<string, string> > leaves_next; | |
unsigned int permutations_reported; | |
// TODO: Provide a command-line method of selecting which | |
// type (i.e. unordered_map, map) that is used to store | |
// the permutations. | |
// unordered_map<string, string> permutations; | |
// map<string, string> permutations; | |
DictStat permutations; | |
State() { | |
int rv = clock_gettime(CLOCK_REALTIME, &this->prog_start_time); | |
assert(rv == 0); | |
set(State::States::INIT); | |
depth = UINT_MAX; | |
gen_stats_heading_displayed = false; | |
rept_stats_heading_displayed = false; | |
permutations_reported = 0; | |
} | |
void set(States state) { | |
this->state = state; | |
int rv = clock_gettime(CLOCK_REALTIME, &this->current_state_start_time); | |
assert(rv == 0); | |
// Clear previous stat time, each time the state is changed. | |
prev_stat_time = {}; | |
} | |
string nemonic(States state) { | |
return nemonic_map[state]; | |
} | |
}; | |
State state; | |
class MemStats { | |
public: | |
MemStats() { | |
pagesize = sysconf(_SC_PAGESIZE); | |
assert(pagesize >= 1); | |
f_statm.open("/proc/self/statm"); | |
} | |
map<string, size_t> stats() { | |
map<string, size_t> rv; | |
size_t vm_size; | |
size_t resident; | |
size_t resident_shared; | |
size_t text; | |
size_t data_stack; | |
f_statm.seekg(0, ios_base::beg); | |
f_statm >> vm_size >> resident >> resident_shared >> text >> data_stack; | |
rv["vm_size"] = vm_size * pagesize; | |
rv["resident"] = resident * pagesize; | |
rv["resident_shared"] = resident_shared * pagesize; | |
rv["text"] = text * pagesize; | |
rv["data_stack"] = data_stack * pagesize; | |
return rv; | |
} | |
size_t pagesize; | |
ifstream f_statm; | |
}; | |
MemStats mem_stats; | |
size_t ticks_per_sec; | |
#ifndef _GNU_SOURCE | |
#define _GNU_SOURCE /* for program_invocation_short_name */ | |
#endif | |
static void usage(void); | |
static void help(void); | |
static void usage(void) | |
{ | |
cout << "usage: " << program_invocation_short_name << ' ' | |
<< "[-h?] [(-n|--max_depth) max_depth] [--results_suppress]" << endl; | |
} | |
static void help(void) | |
{ | |
usage(); | |
puts("Magic Cube 2x2 Permutations"); | |
puts(" -n,--max_depth Maximum depth"); | |
puts(" --results_suppress"); | |
puts(" -?h,--help Help"); | |
} | |
#include <unistd.h> | |
int main(int argc, char *argv[]) | |
{ | |
try { | |
struct timespec current_time; | |
int rv; | |
// Command line parsing | |
static const struct option options[] = { | |
{"max_depth", required_argument, NULL, 'n'}, | |
{"results_suppress", no_argument}, | |
{} // End-of-Array Marker | |
}; | |
char opt; | |
int option_index; | |
bool error; | |
unsigned long arg_max_depth = LONG_MAX; | |
bool arg_results_suppress = false; | |
while ((opt = getopt_long(argc, argv, "n:h?", options, &option_index)) | |
!= EOF) { | |
string option_name = options[option_index].name; | |
switch (opt) { | |
case 0: | |
if (option_name == "results_suppress") { | |
arg_results_suppress = true; | |
} else { | |
cerr << "Unexpected option_name of: " << option_name << endl; | |
exit(23); | |
} | |
break; | |
case 'n': { | |
long val; | |
char *endptr; | |
val = strtol(optarg, &endptr, 10); | |
if ((endptr == optarg) || (*endptr != '\0') || (val <= 0)) { | |
cerr << "Invalid -n/--max_depth value of: " << optarg << endl; | |
exit(20); | |
} | |
arg_max_depth = val; | |
break; | |
} | |
case 'h': | |
case '?': | |
default: | |
error = ((optopt != 0) && (optopt != '?') && (optopt != 'h')); | |
if (error) | |
usage(); | |
else | |
help(); | |
exit(21); | |
} | |
} | |
if (optind != argc) { | |
cerr << "Unexpected positional command-line arguments" << endl; | |
exit(22); | |
} | |
cout << "# max_depth: "; | |
if (arg_max_depth != LONG_MAX) { | |
cout << arg_max_depth << endl; | |
} else { | |
cout << "Unlimited" << endl; | |
} | |
cout << "# results_suppress: " | |
<< ((arg_results_suppress) ? "True" : "False") << endl; | |
rv = clock_gettime(CLOCK_REALTIME, ¤t_time); | |
assert(rv == 0); | |
cout << "# start_time: " << fixed << ((double) current_time.tv_sec | |
+ ((double) current_time.tv_nsec / 1.0e9)) << endl; | |
cout << "# Page_size: " << mem_stats.pagesize << endl; | |
cout << "# CLOCKS_PER_SEC: " << CLOCKS_PER_SEC << endl; | |
ticks_per_sec = sysconf(_SC_CLK_TCK); | |
assert(ticks_per_sec >= 1); | |
cout << "# ticks_per_sec: " << ticks_per_sec << endl; | |
string sequence(""); | |
pair<string, string> entry(MagicCube2x2::solved, sequence); | |
state.permutations.insert(entry); | |
state.leaves_next.push_back(entry); | |
state.set(State::States::GENERATE); | |
for (state.depth = 1; | |
(arg_max_depth == LONG_MAX) || (state.depth <= arg_max_depth); | |
state.depth++) { | |
if (!state.leaves_next.size()) break; | |
state.leaves.clear(); | |
swap(state.leaves, state.leaves_next); | |
print_stats(true); | |
while (state.leaves.size()) { | |
auto leaf = state.leaves.back(); | |
state.leaves.pop_back(); | |
MagicCube2x2 cube(leaf.first); | |
// For face in MagicCube2x2::faces: | |
for (auto&& face: MagicCube2x2::faces) { | |
MagicCube2x2 child(leaf.first); | |
// for direction in ["", "2", "\'"]: | |
string directions[] = {"", "2", "\'"}; | |
for (string direction: directions) { | |
// child.rotate(face) | |
child.rotate(face); | |
// if child.__str__() not in permutations: | |
if (state.permutations.find(child.str()) | |
== state.permutations.end()) { | |
string sequence = leaf.second + face + direction; | |
state.permutations.emplace(child.str(), sequence); | |
state.leaves_next.push_back(pair<string, string>(child.str(), | |
sequence)); | |
} | |
print_stats(); | |
} | |
print_stats(); | |
} | |
print_stats(); | |
} | |
} | |
print_stats(true); | |
cout << "# num_permutations: " << state.permutations.size() << endl; | |
state.set(State::States::REPORT); | |
print_stats(true); | |
// for key, value in permutations.items(): | |
for (auto entry: state.permutations) { | |
if (!arg_results_suppress) { | |
cout << entry.first << " " << entry.second << endl; | |
} | |
state.permutations_reported++; | |
print_stats(); | |
} | |
print_stats(true); | |
rv = clock_gettime(CLOCK_REALTIME, ¤t_time); | |
assert(rv == 0); | |
cout << "# Wall_Time: " << setprecision(2) | |
<< TS_DIFF2DOUBLE(&state.prog_start_time, ¤t_time) << endl; | |
struct tms resource_times; | |
clock_t times_rv; | |
times_rv = times(&resource_times); | |
assert(times_rv != -1); | |
cout << "# User_Time: " << setprecision(2) | |
<< double(resource_times.tms_utime) / ticks_per_sec << endl; | |
cout << "# Sys_Time: " << setprecision(2) | |
<< double(resource_times.tms_stime) / ticks_per_sec << endl; | |
map<string, double> stats_dict; | |
stats_dict = state.permutations.stats_overall(); | |
cout << "# Stats:" << endl; | |
for (auto entry: stats_dict) { | |
// TODO: Dispaly _num values at integer instead of float. | |
cout << "# " << entry.first << ": " | |
<< scientific | |
<< setprecision(-1) | |
<< entry.second | |
<< endl; | |
} | |
} catch (const std::exception& ex) { | |
cerr << "Unexpected Standard Exception" << endl; | |
cerr << ex.what() << endl; | |
exit(1); | |
} catch (...) { | |
cerr << "Unexpected Exception Type" << endl; | |
exit(2); | |
} | |
return 0; | |
} | |
void print_stats(bool always_display) { | |
int rv; | |
double td_state_start; // Time Difference since start of current state. | |
double td_prev_stat; // Time Difference since previous stat | |
struct tms resource_times; | |
clock_t times_rv; | |
static bool gen_stats_heading_displayed = false; | |
static bool rept_stats_heading_displayed = false; | |
map<string, size_t> stats_mem; | |
map<string, double> stats_dict; | |
struct timespec current_time; | |
rv = clock_gettime(CLOCK_REALTIME, ¤t_time); | |
assert(rv == 0); | |
td_state_start = ((state.current_state_start_time.tv_sec != 0) | |
|| (state.current_state_start_time.tv_nsec != 0)) | |
? TS_DIFF2DOUBLE(&state.current_state_start_time, ¤t_time) : 0; | |
td_prev_stat = ((state.prev_stat_time.tv_sec != 0) | |
|| (state.prev_stat_time.tv_nsec != 0)) | |
? TS_DIFF2DOUBLE(&state.prev_stat_time, ¤t_time) : 0; | |
// Display stats if any of the following are true: | |
// + always_display argument is true | |
// + In current state less then 10 seconds and its been longer | |
// then 0.1 seconds since stats were previously displayed | |
// + In current state less then 100 seconds and its been longer | |
// then 1.0 seconds since stats were previously displayed | |
// + In current state less then 1000 seconds and its been longer | |
// then 10.0 seconds since stats were previously displayed | |
// + Stats have not been display for >= 1 minute | |
if (always_display | |
|| ((state.prev_stat_time.tv_sec == 0) | |
&& (state.prev_stat_time.tv_nsec == 0)) | |
|| ((td_state_start <= 10.0) && (td_prev_stat >= 0.1)) | |
|| ((td_state_start <= 100.0) && (td_prev_stat >= 1.0)) | |
|| ((td_state_start <= 1000.0) && (td_prev_stat >= 10.0)) | |
|| (td_prev_stat >= 60.0)) { | |
double td_start; // Time Difference since start of program | |
td_start = TS_DIFF2DOUBLE(&state.prog_start_time, ¤t_time); | |
switch (state.state) { | |
case State::GENERATE: | |
times_rv = times(&resource_times); | |
assert(times_rv != -1); | |
if (!state.gen_stats_heading_displayed) { | |
cout << "# " | |
<< string(15, ' ') << "Time" << string(14, ' ') | |
<< " |" << string(83, ' ') | |
<< " | Contains " | |
<< " | Set" << endl; | |
cout << "# Wall, Usr, Sys" | |
<< " | State, Permutations, Depth," | |
<< " Leaves, Leaves_next, VmSize," | |
<< " Resident" | |
<< " | num, avg, max" | |
<< " | num, avg, max" << endl; | |
state.gen_stats_heading_displayed = true; | |
} | |
stats_mem = mem_stats.stats(); | |
cout << fixed | |
<< "# " << setw(12) << setprecision(2) << td_start << ", " | |
<< setw(9) << setprecision(2) | |
<< double(resource_times.tms_utime) / ticks_per_sec << ", " | |
<< setw(9) << setprecision(2) | |
<< double(resource_times.tms_stime) / ticks_per_sec; | |
cout << " | " | |
<< setw(5) << state.nemonic(state.state).c_str() << ", " | |
<< setw(12) << state.permutations.size() << ", " | |
<< setw(5) << state.depth << ", " | |
<< setw(12) << state.leaves.size() << ", " | |
<< setw(12) << state.leaves_next.size() << ", " | |
<< setw(12) << stats_mem["vm_size"] << ", " | |
<< setw(12) << stats_mem["resident"]; | |
stats_dict = state.permutations.stats(); | |
cout << " | " | |
<< fixed | |
<< setw(8) << (unsigned long) stats_dict["contains_num"] << ", " | |
// TODO: When _num is 0 print - instead of avg and max time. | |
<< scientific | |
<< setw(8) << setprecision(2) << stats_dict["contains_avg_time"] << ", " | |
<< setw(8) << setprecision(2) << stats_dict["contains_max_time"]; | |
cout << " | " | |
<< fixed | |
<< setw(8) << (unsigned long) stats_dict["set_num"] << ", " | |
// TODO: When _num is 0 print - instead of avg and max time. | |
<< scientific | |
<< setw(8) << setprecision(2) << stats_dict["set_avg_time"] << ", " | |
<< setw(8) << setprecision(2) << stats_dict["set_max_time"] | |
<< endl; | |
break; | |
case State::REPORT: | |
times_rv = times(&resource_times); | |
assert(times_rv != -1); | |
if (!state.rept_stats_heading_displayed) { | |
cout << "# " | |
<< string(15, ' ') << "Time" << string(14, ' ') | |
<< " |" << endl; | |
cout << "# Wall, Usr, Sys" | |
<< " | State, Remaining" << endl; | |
state.rept_stats_heading_displayed = true; | |
} | |
cout << fixed | |
<< "# " << setw(12) << setprecision(2) << td_start << ", " | |
<< setw(9) << setprecision(2) | |
<< double(resource_times.tms_utime) / ticks_per_sec << ", " | |
<< setw(9) << setprecision(2) | |
<< double(resource_times.tms_stime) / ticks_per_sec; | |
cout << " | " | |
<< setw(5) << state.nemonic(state.state).c_str() << ", " | |
<< setw(12) << (state.permutations.size() - state.permutations_reported) | |
<< endl; | |
break; | |
} | |
state.prev_stat_time = current_time; | |
cout.flush(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
"""Produce chart of specified permutations2x2 results | |
Copyright 2019 Louis Huemiller | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
""" | |
from __future__ import print_function | |
from __future__ import division | |
import argparse | |
import leather | |
import sys | |
parser = argparse.ArgumentParser(prog='permutations2x2_chart_results', | |
description='Permutations2x2 Chart Results') | |
parser.add_argument('-f', '--file', type=argparse.FileType('w'), | |
dest='file_out', default=sys.stdout, | |
help='Output filename (default:stdout)') | |
parser.add_argument('results', metavar='result', nargs='+', | |
help='[label:]results_filename') | |
args = parser.parse_args() | |
chart = leather.Chart() | |
for result in args.results: | |
parts = result.split(':') | |
assert(len(parts) >= 1) | |
assert(len(parts) <= 2) | |
if (len(parts) == 2): | |
label = parts.pop(0) | |
else: | |
label = None | |
filepath = parts[0] | |
f = open(filepath, 'r') | |
data = [] | |
for line in f: | |
# Skip non-comment lines. Stats to be charted are only | |
# provided by comment lines, lines that start with '# '. | |
if not line.startswith('# '): | |
continue | |
# Only process stat lines for the Generation and Reporting states. | |
if not (('GEN,' in line) or ('REPT,' in line)): | |
continue | |
parts = line[2:].split(',') | |
if len(parts) < 3: | |
print('Line contains insufficient number of values.', | |
file=sys.stderr) | |
print('Expected at least Time, State, and Num_Permutations', | |
file=sys.stderr) | |
print('line:', line) | |
assert(0) | |
time = parts[0] | |
num_permutations = parts[2] | |
data.append((float(time), int(num_permutations))) | |
chart.add_line(data, name=label) | |
chart.to_svg(path=args.file_out) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment