Skip to content

Instantly share code, notes, and snippets.

@lhuemill
Last active February 9, 2020 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lhuemill/f1273291e5f5e85e4b42e5c7614e60ef to your computer and use it in GitHub Desktop.
Save lhuemill/f1273291e5f5e85e4b42e5c7614e60ef to your computer and use it in GitHub Desktop.
Magic_Cube2x2
__pycache__
*.pyc
*.swp
build/
results/
target/
// ./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();
}
// ./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;
};
#! /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())
#
# 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
#! /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]))
// ./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, &current_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, &current_time);
assert(rv == 0);
cout << "# Wall_Time: " << setprecision(2)
<< TS_DIFF2DOUBLE(&state.prog_start_time, &current_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, &current_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, &current_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, &current_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, &current_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();
}
}
#! /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