diff --git a/Group_Scoobidoo/pentominos.py b/Group_Scoobidoo/pentominos.py new file mode 100644 index 0000000..b141945 --- /dev/null +++ b/Group_Scoobidoo/pentominos.py @@ -0,0 +1,346 @@ +import copy + +#nontested +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + + #the comments are the version i would prefer, without input coo + def normalize_coo(self, coo): + if ~self.consistent(): + print "polyomino non consistent" + if coo >=self.dim | coo<0: + print "Invalid argument for coo" + selbst = copy.deepcopy(self) + mini = sys.maxint + for c in selbst.coos: + if c[coo] < mini: + mini = c[coo] + self.translate_coo(coo,mini*(-1)) + + def normalize(self): + for i in range(self.dim): + normalize_coo(i) + + def flip(self, coo): + if ~self.consistent(): + print "polyomino non consistent" + if coo >=self.dim | coo<0: + print "Invalid argument for coo" + else: + for c in self.coos: + c[coo]*=-1 + + + def translate_one(self, coo): + translate_coo(self,coo,1) + + #this method translates all coordinates in direction no. coo (starting with 0) by amount + #(negative amount yields the opposite direction) + def translate_coo(self, coo, amount): + if ~self.consistent(): + print "polyomino non consistent" + if coo >=self.dim | coo<0: + print "Invalid argument for coo" + else: + for c in self.coos: + c[coo]+=amount + + #this method translates all coordinates of the pentomino by the vector by_vector + def translate_by(self, by_vector): + if ~self.consistent(): + print "polyomino non consistent" + if len(by_vector)!=self.dim: + print "Invalid argument for by_vector" + else: + for c in self.coos: + for i in range(len(c)): + c[i]+=by_vector[i] + #c= map(int.__add__,c,by_vector) + + #Turn 90 degrees around midpoint: coos[2] for pentominos, coos[3] for hexominos, etc. + def turn90(self): + if ~self.consistent(): + print "polyomino non consistent" + if self.dim!=2: + print "rotation only possible in 2D" + else: + vec=copy.deepcopy(self.coos[len(self.coos)//2]) + for i in range(self.dim): + vec[i]=-vec[i] + translate_by(vec) + for c in self.coos: + tmp = c[0] + c[0]= -c[1] + c[1]= tmp + translate_by(self.coos[len(self.coos)//2]) + + def max(self): + if ~self.consistent(): + print "polyomino non consistent" + maxi = [0] * self.dim + for c in self.coos: + for i in range(self.dim): + maxi[i] = max(c[i],maxi[i]) + return maxi + + # The hashfunction asserts that dimension is less or equal than 16, whilst strictly bigger than 0 + # It furtherly asserts that the coordinates are not greater than 255, and nonnegative. + def __hash__(self): + if ~self.consistent(): + return -1 + hashcode = 0 + hashcode += hashName(self.name) + hashcode += (self.dim-1)<<4 + e=8 + for c in self.coos: + for i in range(self.dim): + hashcode += c[i]<4 : + return False + for c in selbst.coos: + tmp = c[0] + c[0]= -c[1] + c[1]= tmp + for j in range(self.dim): + selbst.coos[0][j]+=switchy(self.name) + else: + while selbst.coos[1][1]!=1: + i+=1 + if i>4 : + return False + for c in selbst.coos: + tmp = c[0] + c[0]= -c[1] + c[1]= tmp + #selbst should now be the same as selbstnorm. We check that: + if selbst.name!=selbstnorm.name: + return False + elif selbst.dim!=selbstnorm.dim: + return False + # selbst.coos == selbstnorm.coos would compare pointers, not entries, + # so we choose the difficult version + elif len(selbst.coos)!=len(selbstnorm.coos): + return False + else: + for i in range(len(selbst.coos)): + if selbst.dim!=len(selbstnorm.coos[i]): + return False + else: + for j in range(selbst.dim): + if selbst.coos[i][j]!=selbstnorm.coos[i][j]: + return False + return True + except: + return False + +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + + +def all_pentominos(): + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + +def fixed_pentominos_of(p): + t=TileSet([]) + pp= copy.deepcopy(p) + for i in range(4): + t.add(pp.turn90()) + return t + +nameInit= { + "F":F + "I":I + "L":L + "P":P + "N":N + "T":T + "U":U + "V":V + "W":W + "X":X + "Y":Y + "Z":Z +} + +hashName = { + "F":0 + "I":1 + "L":2 + "P":3 + "N":4 + "T":5 + "U":6 + "V":7 + "W":8 + "X":9 + "Y":10 + "Z":11 +} + +switchy = { + "F":1 + "T":2 + "V":0 + "W":0 + "X":1 + "Y":0 + "Z":2 +} + +coo2X = { + "F":True + "I":False + "L":False + "P":False + "N":False + "T":True + "U":False + "V":True + "W":True + "X":True + "Y":True + "Z":True +} + + +class TileSet(object): + def __init__(self, plist=[]): + self.set = set() + for p in plist: + self.add(p) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + tmp = copy.deepcopy(p) + vec = tmp.max() + for i in range(tmp.dim): + vec[i]=-vec[i] + tmp.translate_by(vec) + for i in range(tmp.dim): + tmp.normalize_coo(i) + append = True + for pp in self.set: + if pp.__eq__(tmp): + append = False + if append: + self.set.append(tmp) + + def size(self): + return len(self.set) + + def representation(self): + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep diff --git a/PublicKeyRobertLoewe.txt b/PublicKeyRobertLoewe.txt new file mode 100644 index 0000000..fa460fe --- /dev/null +++ b/PublicKeyRobertLoewe.txt @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: GPGTools - https://gpgtools.org + +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 +BKQxr7CkDOSX2tVIylORr7rW +=DOH+ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/coxeter_group_orbits/JonasLovis/Makefile.template b/coxeter_group_orbits/JonasLovis/Makefile.template new file mode 100644 index 0000000..8437f04 --- /dev/null +++ b/coxeter_group_orbits/JonasLovis/Makefile.template @@ -0,0 +1,18 @@ +SHELL = /bin/sh + +.SUFFIXES: +.SUFFIXES: .cc .o + +BOOSTDIR = /the/path/to/your/boost # was: /home/julian/software/boost_1_57_0 + +INCLUDEDIR = -I. -I$(BOOSTDIR) +LIBDIR = -L$(BOOSTDIR)/lib +LIBS = -lboost_unit_test_framework +CFLAGS = -Wall -Wextra -Wpedantic -std=c++1y -O3 -g +CC = g++ + +test_orbits: test_orbits.o + $(CC) $(LIBDIR) $(CFLAGS) $< $(LIBS) -o $@ + +test_orbits.o: test_orbits.cc orbit.h + $(CC) $(INCLUDEDIR) $(CFLAGS) -c $< -o $@ diff --git a/coxeter_group_orbits/JonasLovis/epsilonVector.h b/coxeter_group_orbits/JonasLovis/epsilonVector.h new file mode 100644 index 0000000..d590277 --- /dev/null +++ b/coxeter_group_orbits/JonasLovis/epsilonVector.h @@ -0,0 +1,91 @@ +// +// impreciseVector.h +// CoxeterOrbit +// +// Created by Jonas Neukamm on 04.06.15. +// Copyright (c) 2015 LovisJonas. All rights reserved. +// + +#ifndef __epsilonVector_h +#define __epsilonVector_h + +#include +#include + +const static double epsilon = 0.0000001; + +typedef double E; + +class EpsilonVector : public std::vector +{ +private: + + E scalarProduct(const EpsilonVector& b) const + { + E c = 0; + for ( int i = 0; i < b.size(); i++) + c += this->operator[](i) * b[i]; + return c; + } + +public: + + EpsilonVector() {} + + explicit EpsilonVector(int dim) + : std::vector(dim) + {} + + + template + EpsilonVector(std::initializer_list init) + : std::vector(init) + {} + + EpsilonVector mirror(const EpsilonVector& normal) const + { + double scalar = normal.scalarProduct(normal); + EpsilonVector mir (this->size()); + for ( int i = 0; i < this->size(); i++){ + for( int j = 0; j < this->size(); j++){ + mir[i] += normal[i]*normal[j]*this->operator[](j); + } + mir[i] *= (-2)/(scalar); + mir[i] += this->operator[](i); + } + return mir; + } + + bool operator==(const EpsilonVector& rhs) const + { + EpsilonVector a(*this); + for ( int i = 0; i < rhs.size() ; i++) { + if ( a[i] < rhs[i] - epsilon || a[i] > rhs[i] + epsilon ) + return false; + } + return true; + } + + // Comparison operator to be used by our Orbit. + bool operator < (const EpsilonVector& rhs) const + { + for ( int i = 0; i < rhs.size() ; i++) { + if ( (*this)[i] < rhs[i] - epsilon ) { + return true; + } else { + if ( (*this)[i] > rhs[i] + epsilon ) + return false; + } + } + return false; + } + + friend std::ostream& operator << (std::ostream& os, const EpsilonVector& v) + { + for (const auto& x : v) + os << x << " "; + return os; + } +}; // Klasse zuende. + +#endif diff --git a/coxeter_group_orbits/JonasLovis/main.cpp b/coxeter_group_orbits/JonasLovis/main.cpp new file mode 100644 index 0000000..c0d2876 --- /dev/null +++ b/coxeter_group_orbits/JonasLovis/main.cpp @@ -0,0 +1,38 @@ +// +// main.cpp +// CoxeterOrbit +// +// Created by Jonas Neukamm on 04.06.15. +// Copyright (c) 2015 LovisJonas. All rights reserved. +// + +#include +#include +#include "orbit.h" +#include + +const static char letter = 'B'; + +int main(int argc, const char * argv[]) { + for (int i = 8; i < 9; i++){ + VectorType vec (i); + if ( letter != 'I' && letter != 'F' ){ + for ( int j = 0 ; j < i ; j++){ + vec[j] = (i*j+0.7)*pow(-1, j); + } + }else{ + if (letter == 'I') + vec = {0.4231 , -17.33312 }; + else + vec = {0.4231 , -17.33312 , 89.23 , -200.02}; + } + GeneratorList list = simple_roots(letter, i); + std::cout << "Generator Size: " << list.size() << '\n'; + for ( int j = 0 ; j < list.size() ; j++) + std::cout << letter << j << ": " < +#include +#include +#include +#include +#include "epsilonVector.h" +#include + +class NotImplementedException : public std::exception {}; + + +// PI for cosine function & Radius,eps to compare points in Orbit +typedef double NumberType; +typedef EpsilonVector VectorType; +typedef std::vector GeneratorList; +typedef std::set Orbit; +typedef GeneratorList MatrixType; + +GeneratorList give_A(int dim) +{ + GeneratorList list; + for (int i = 0 ; i < dim ; i++ ) { + VectorType vec (dim+1); + vec[i]=1; + vec[i+1]=-1; + list.push_back(vec); + } + return list; +} + +GeneratorList give_B(int dim) +{ + GeneratorList list; + for ( int i = 0 ; i < dim-1 ; i++ ) { + VectorType vec (dim); + vec[i] = 1; + vec[i+1]=-1; + list.push_back(vec); + } + VectorType vec (dim); + vec[dim-1]=1; + list.push_back(vec); + return list; +} + +GeneratorList give_C(int dim) +{ + GeneratorList list = give_A(dim - 1); + VectorType v(dim); + v[dim - 1] = 2; + list.push_back(v); + return list; +} + +GeneratorList give_D(int dim) +{ + VectorType v(dim); + v[dim - 2] = v[dim - 1] = 1; + GeneratorList list = give_A(dim - 1); + std::cout << list.back() << '\n'; + list.push_back(v); + return list; +} + +GeneratorList give_E(int dim) +{ + GeneratorList list; + for ( int i = 0 ; i < dim-2 ; i++ ) { + VectorType vec(dim); + vec[i]=1; + vec[i+1]=-1; + list.push_back(vec); + } + if (dim == 6) + list.push_back({-0.5,-0.5,-0.5,-0.5,-0.5,sqrt(3)/2.}); + if (dim == 7) + list.push_back({-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,sqrt(2)/2.}); + if (dim == 8) + list.push_back({-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5}); + VectorType vec1 (dim); vec1[dim-3] = 1; vec1[dim-2] = 1; + list.push_back(vec1); + return list; +} + +GeneratorList give_F(){ + GeneratorList list={ {0.,1.,-1.,0.}, + {0.,0.,1.,-1.}, + {0.,0.,0.,1.}, + {0.5,-0.5,-0.5,-0.5} + }; + return list; +} + +GeneratorList give_G() +{ + GeneratorList list = { {0.,1.,-1.}, + {1.,-2.,1.} }; + return list; +} + + +GeneratorList give_H(int dim){ + const NumberType tau(0.5 + 0.5 * sqrt(5)); // golden ratio + GeneratorList list; + if (dim == 3){ + VectorType v(3); + v[0] = 2; + list.push_back(v); + VectorType v1(3); + v1[0] = -tau; + v1[1] = tau - 1; + v1[2] = -1; + list.push_back(v1); + VectorType v2(3); + v2[2] = 2; + list.push_back(v2); + } + if (dim == 4){ + VectorType v(4); + v[0] = (1 + tau) * 0.5; + v[1] = v[2] = v[3] = (1 - tau) * 0.5; + list.push_back(v); + VectorType v1(4); + v1[0] = -1; + v1[1] = 1; + list.push_back(v1); + VectorType v2(4); + v2[1] = -1; + v2[2] = 1; + list.push_back(v2); + VectorType v3(4); + v3[2] = -1; + v3[3] = 1; + list.push_back(v3); + } + return list; +} + +GeneratorList give_I(int dim) +{ + GeneratorList list {{1., 0.},{0.,1.}}; + double cosine = cos(M_PI/dim); + list[1][0]= cosine/sqrt(1.0-pow(cosine, 2)); + return list; +} + +GeneratorList simple_roots(char type, int dim) +{ + switch(type) { + case 'A': + if (dim > 0) return give_A(dim); + else throw new NotImplementedException(); + case 'B': + if (dim > 0) return give_B(dim); + else throw new NotImplementedException(); + case 'C': + if (dim > 0) return give_C(dim); + else throw new NotImplementedException(); + case 'D': + if (dim > 0) return give_D(dim); + else throw new NotImplementedException(); + case 'E': + if (dim < 9 || dim > 5 ) return give_E(dim); + else throw new NotImplementedException(); + case 'F': + if (dim == 4) return give_F(); + else throw new NotImplementedException(); + case 'G': + if (dim == 2) return give_G(); + else throw new NotImplementedException(); + case 'H': + if ( dim < 5 || dim > 2 ) return give_H(dim); + else throw new NotImplementedException(); + case 'I': + if (dim < 1) throw new NotImplementedException(); + else return give_I(dim); + default: + throw new NotImplementedException(); + } +} + +Orbit orbit(const GeneratorList& generators, const VectorType& v ) +{ + //Counting stuff + int counter = 0; + time_t start = time(NULL); + //endcount + Orbit orb; + GeneratorList newPoints {v}; + int n = generators.size(); + while (!newPoints.empty()){ + VectorType vec = newPoints.back(); + newPoints.pop_back(); + if ( std::get<1>(orb.insert(vec)) ){ + //Counting Stuff + counter += 1; + if ( counter == 2000000){ + time_t middle = time(NULL); + counter = 0; + double time3 = double(middle-start)/60; + std::cout << "Wir sind bei " << orb.size() << " nach " << time3 << " Minuten." << '\n'; + } + //Endcount + for (int i = 0 ; i < n ; i++){ + newPoints.push_back( vec.mirror(generators[i]) ); + } + } // endif + } // endwhile + //Counting... + time_t end = time(NULL); + double time1 = double(end-start); + double time2 = double(end-start)/60; + std::cout << "Time secs: " << time1 << " Time mins: " << time2 << '\n'; + //Endcount + return orb; +} + +#endif // __ORBIT_H_ + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: + + diff --git a/coxeter_group_orbits/JonasLovis/stl_wrappers.h b/coxeter_group_orbits/JonasLovis/stl_wrappers.h new file mode 100644 index 0000000..581011f --- /dev/null +++ b/coxeter_group_orbits/JonasLovis/stl_wrappers.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +//#ifndef __STL_WRAPPERS_H__ +//#define __STL_WRAPPERS_H__ + +#include +#include +#include +#include + + +template +inline std::ostream& +operator<<(std::ostream& wrapped, const std::array& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + + +// teach Boost.Test how to print std::vector +template +inline std::ostream& +operator<<(std::ostream& wrapped, std::vector const& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + +template +inline std::ostream& +operator<<(std::ostream& wrapped, std::pair const& item) +{ + return wrapped << '<' << item.first << ',' << item.second << '>'; +} + +template +inline std::ostream& +operator<<(std::ostream& wrapped, std::map const& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + + +//#endif // __STL_WRAPPERS_H__ + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: + diff --git a/coxeter_group_orbits/JonasLovis/test_orbits.cc b/coxeter_group_orbits/JonasLovis/test_orbits.cc new file mode 100644 index 0000000..d061d0c --- /dev/null +++ b/coxeter_group_orbits/JonasLovis/test_orbits.cc @@ -0,0 +1,98 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#define BOOST_TEST_MODULE orbits +#include + +#include "orbit.h" +#include "stl_wrappers.h" + +BOOST_AUTO_TEST_CASE( generators ) +{ + std::ostringstream oss; + oss << simple_roots_type_A(4) << std::endl + << simple_roots_type_B(4) << std::endl + << simple_roots_type_C(4) << std::endl + << simple_roots_type_D(4) << std::endl + << simple_roots_type_E6() << std::endl + << simple_roots_type_E7() << std::endl + << simple_roots_type_E8() << std::endl + << simple_roots_type_F4() << std::endl + << simple_roots_type_H3() << std::endl + << simple_roots_type_H4() << std::endl; + + BOOST_CHECK_EQUAL(oss.str(), + "{{1,-1,0,0,0},{0,1,-1,0,0},{0,0,1,-1,0},{0,0,0,1,-1}}\n" + "{{1,-1,0,0},{0,1,-1,0},{0,0,1,-1},{0,0,0,1}}\n" + "{{1,-1,0,0},{0,1,-1,0},{0,0,1,-1},{0,0,0,2}}\n" + "{{1,-1,0,0},{0,1,-1,0},{0,0,1,-1},{0,0,1,1}}\n" + "{{1,-1,0,0,0,0},{0,1,-1,0,0,0},{0,0,1,-1,0,0},{0,0,0,1,-1,0},{0,0,0,1,1,0},{-0.5,-0.5,-0.5,-0.5,-0.5,0.866025}}\n" + "{{1,-1,0,0,0,0,0},{0,1,-1,0,0,0,0},{0,0,1,-1,0,0,0},{0,0,0,1,-1,0,0},{0,0,0,0,1,-1,0},{0,0,0,0,1,1,0},{-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,0.707107}}\n" + "{{1,-1,0,0,0,0,0,0},{0,1,-1,0,0,0,0,0},{0,0,1,-1,0,0,0,0},{0,0,0,1,-1,0,0,0},{0,0,0,0,1,-1,0,0},{0,0,0,0,0,1,-1,0},{0,0,0,0,0,1,1,0},{-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5}}\n" + "{{1,-1,0,0},{0,1,-1,0},{0,0,1,0},{-0.5,-0.5,-0.5,-0.5}}\n" + "{{2,0,0},{-1.61803,0.618034,-1},{0,0,2}}\n" + "{{1.30902,-0.309017,-0.309017,-0.309017},{-1,1,0,0},{0,-1,1,0},{0,0,-1,1}}\n" + ); +} + +struct b3_fixture { + b3_fixture() + : generators(simple_roots('B', 3)) + {} + GeneratorList generators; +}; + +BOOST_FIXTURE_TEST_CASE( b3_orbit_012, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 3}).size(), (size_t) 48); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_12, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 3}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_02, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 2}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_01, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 0}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_0, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 0, 0}).size(), (size_t) 6); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_1, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 0}).size(), (size_t) 12); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_2, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 1}).size(), (size_t) 8); +} + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/ash/Makefile.template b/coxeter_group_orbits/ash/Makefile.template new file mode 100644 index 0000000..8437f04 --- /dev/null +++ b/coxeter_group_orbits/ash/Makefile.template @@ -0,0 +1,18 @@ +SHELL = /bin/sh + +.SUFFIXES: +.SUFFIXES: .cc .o + +BOOSTDIR = /the/path/to/your/boost # was: /home/julian/software/boost_1_57_0 + +INCLUDEDIR = -I. -I$(BOOSTDIR) +LIBDIR = -L$(BOOSTDIR)/lib +LIBS = -lboost_unit_test_framework +CFLAGS = -Wall -Wextra -Wpedantic -std=c++1y -O3 -g +CC = g++ + +test_orbits: test_orbits.o + $(CC) $(LIBDIR) $(CFLAGS) $< $(LIBS) -o $@ + +test_orbits.o: test_orbits.cc orbit.h + $(CC) $(INCLUDEDIR) $(CFLAGS) -c $< -o $@ diff --git a/coxeter_group_orbits/ash/orbit.h b/coxeter_group_orbits/ash/orbit.h new file mode 100644 index 0000000..145b894 --- /dev/null +++ b/coxeter_group_orbits/ash/orbit.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __ORBIT_H_ +#define __ORBIT_H_ + +#include +#include + +class NotImplementedException : public std::exception {}; + +typedef int NumberType; // this probably isn't going to work +typedef std::vector VectorType; +typedef std::vector GeneratorList; +typedef std::set Orbit; + +GeneratorList simple_roots(char type, int dim) +{ + switch(type) { + case 'b': + case 'B': + if (dim != 3) throw new NotImplementedException(); + return {{1,-1,0},{0,1,-1},{0,0,1}}; + + default: + throw new NotImplementedException(); + } +} + +Orbit orbit(const GeneratorList& generators, const VectorType& v) +{ + return std::set(); +} + + +#endif // __ORBIT_H_ + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/ash/test_orbits.cc b/coxeter_group_orbits/ash/test_orbits.cc new file mode 100644 index 0000000..1e6e1a9 --- /dev/null +++ b/coxeter_group_orbits/ash/test_orbits.cc @@ -0,0 +1,69 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#define BOOST_TEST_MODULE orbits +#include + +#include "orbit.h" + +struct b3_fixture { + b3_fixture() + : generators(simple_roots('B', 3)) + {} + GeneratorList generators; +}; + +BOOST_FIXTURE_TEST_CASE( b3_orbit_012, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 3}).size(), (size_t) 48); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_12, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 3}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_02, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 2}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_01, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 0}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_0, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 0, 0}).size(), (size_t) 6); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_1, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 0}).size(), (size_t) 12); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_2, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 1}).size(), (size_t) 8); +} + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/ay4me/Makefile.template b/coxeter_group_orbits/ay4me/Makefile.template new file mode 100644 index 0000000..8437f04 --- /dev/null +++ b/coxeter_group_orbits/ay4me/Makefile.template @@ -0,0 +1,18 @@ +SHELL = /bin/sh + +.SUFFIXES: +.SUFFIXES: .cc .o + +BOOSTDIR = /the/path/to/your/boost # was: /home/julian/software/boost_1_57_0 + +INCLUDEDIR = -I. -I$(BOOSTDIR) +LIBDIR = -L$(BOOSTDIR)/lib +LIBS = -lboost_unit_test_framework +CFLAGS = -Wall -Wextra -Wpedantic -std=c++1y -O3 -g +CC = g++ + +test_orbits: test_orbits.o + $(CC) $(LIBDIR) $(CFLAGS) $< $(LIBS) -o $@ + +test_orbits.o: test_orbits.cc orbit.h + $(CC) $(INCLUDEDIR) $(CFLAGS) -c $< -o $@ diff --git a/coxeter_group_orbits/ay4me/file.txt b/coxeter_group_orbits/ay4me/file.txt new file mode 100644 index 0000000..0f08b58 --- /dev/null +++ b/coxeter_group_orbits/ay4me/file.txt @@ -0,0 +1,2 @@ +D4 +{1 2 3 4} diff --git a/coxeter_group_orbits/ay4me/orbit.h b/coxeter_group_orbits/ay4me/orbit.h new file mode 100644 index 0000000..ddfcc69 --- /dev/null +++ b/coxeter_group_orbits/ay4me/orbit.h @@ -0,0 +1,412 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __ORBIT_H_ +#define __ORBIT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class NotImplementedException : public std::exception {}; +class InvalidInputException : public std::logic_error { +public: + InvalidInputException():std::logic_error("no error message") {}; + InvalidInputException(const std::string& s):std::logic_error(s) {}; +}; +class InvalidGeneratorException : public std::logic_error { +public: + InvalidGeneratorException():std::logic_error("no error message") {}; + InvalidGeneratorException(const std::string& s):std::logic_error(s) {}; +}; + +const static double epsilon = 0.00001; + +template +T relativeError(const std::vector& x, const std::vector& y) +{ + if (x.size() != y.size()) + { + throw std::logic_error("Comparison between vectors of different size."); + } + std::vector diff(x.size()); + for (std::size_t i=0;i < x.size();++i) + { + diff[i] = x[i]-y[i]; + } + T maxDiff = 0.0; + T maxVal = 0.0; + for (std::size_t i=0;i < x.size();++i) + { + if (std::fabs(diff[i]) >std::fabs(maxDiff)) + { + maxDiff = std::fabs(diff[i]); + } + if (std::fabs(x[i]) > std::fabs(maxVal)) + { + maxVal = std::fabs(x[i]); + } + } + if (maxVal == 0.0) + { + return maxDiff; + } + return maxDiff/maxVal; +} + +template +struct ImpreciseComp{ + bool operator()(const std::vector& x, const std::vector& y) const + { + if (relativeError(x,y) < epsilon) + { + return false; + } + return x < y; + } +}; + +typedef double NumberType; // this probably isn't going to work +typedef std::vector VectorType; +typedef std::vector GeneratorList; +typedef std::set> Orbit; + +void out(std::ostream& file,const Orbit& solution, bool outputOrbit); + +GeneratorList simple_roots(char type, std::size_t dim) +{ + switch(type) { + case 'b': + case 'B': + if (dim != 3) throw NotImplementedException(); + return {{1,-1,0},{0,1,-1},{0,0,1}}; + + default: + throw NotImplementedException(); + } +} + +void generateA(std::size_t dim, GeneratorList& generators) +{ + generators.resize(dim, VectorType(dim+1)); + for (std::size_t i=0; i> dim; + point.resize(dim); + switch(letter) { + case 'A': + generateA(dim, generators); + break; + case 'B': + generateB(dim, generators); + break; + case 'D': + generateD(dim, generators); + break; + case 'E': + break; + case 'F': + break; + case 'G': + break; + case 'H': + break; + case 'I': + break; + default: + throw InvalidInputException("Infinite or unknown coxeter group."); + } + getline( input, line ); + //process second line + if(line.length() < 2*dim+1) //at least one number per dimension and number of dimension minus one many spaces in between, 2 brackets + { + throw InvalidInputException("Point vector too short."); + } + if(line[0]!='{' || line[line.length()-1]!='}') + { + throw InvalidInputException("Malformed point vector."); + } + std::stringstream lineIn(line.substr(1,line.length()-2)); + for(std::size_t i = 0; i < dim; ++i) + { + lineIn >> point[i]; + } + if(getline( input, line )) + { + throw InvalidInputException("Wrong number of lines."); + } +} + +int factorial(int n) +{ + if (n == 0 || n == 1) + { + return 1; + } + return factorial(n-1)*n; +} + +bool divisor(int d, int n) +{ + return n%d == 0; +} + +void sanityCheck(int orbitSize, std::string filename) +{ + std::ifstream input( filename ); + std::string line; + getline( input, line ); + char letter = line[0]; //get name of coxeter + std::size_t dim = line[1]-'0'; //get dimension of coxeter + int maxOrbit = 0; + switch(letter) { + case 'A': + maxOrbit = factorial(dim+1); + if (!divisor(orbitSize,maxOrbit)) + { + throw InvalidGeneratorException("Orbitsize is not divisor of the maximum one."); + } + break; + case 'B': + if (dim < 4) + { + maxOrbit = factorial(dim+1); + } + else + { + maxOrbit = (1<> unmirroredPoints = {v}; + while(!unmirroredPoints.empty()) + { + // std::set::iterator it = unmirroredPoints.begin(); + // currentPoint = *it; + const VectorType& currentPoint(*(unmirroredPoints.begin())); + history.insert(currentPoint); + for(const auto& plane : generators) + { + VectorType mirroredPoint = mirror(currentPoint,plane); + //mirroredPoint = mirror(currentPoint,plane); + if(history.find(mirroredPoint) == history.end()) + { + unmirroredPoints.insert(mirroredPoint); + } + } + unmirroredPoints.erase(currentPoint); + } + return; +} + +Orbit orbit(const GeneratorList& generators, const VectorType& v) +{ + Orbit solution = {}; + iterorbit(generators, v, solution); + return solution; +} + + +void out(std::ostream& file,const Orbit& solution, bool outputOrbit) +{ + if(outputOrbit) + { + file << "{\n"; + for (const auto& point:solution) + { + file << " {"; + bool first = true; + for (const auto& val: point) + { + if(!first) + { + file << " "; + } + file << val; + first = false; + } + file << "}\n"; + } + file << "}\n"; + } + file << boost::lexical_cast(solution.size()); +} + + +#endif // __ORBIT_H_ + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: + +//out(std::cout, Orbit(generators.begin(),generators.end()),true); diff --git a/coxeter_group_orbits/ay4me/out.txt b/coxeter_group_orbits/ay4me/out.txt new file mode 100644 index 0000000..7862220 --- /dev/null +++ b/coxeter_group_orbits/ay4me/out.txt @@ -0,0 +1,195 @@ +{ + {-4 -3 -2 -1} + {-4 -3 -1 -2} + {-4 -3 1 2} + {-4 -3 2 1} + {-4 -2 -3 -1} + {-4 -2 -1 -3} + {-4 -2 1 3} + {-4 -2 3 1} + {-4 -1 -3 -2} + {-4 -1 -2 -3} + {-4 -1 2 3} + {-4 -1 3 2} + {-4 1 -3 2} + {-4 1 -2 3} + {-4 1 2 -3} + {-4 1 3 -2} + {-4 2 -3 1} + {-4 2 -1 3} + {-4 2 1 -3} + {-4 2 3 -1} + {-4 3 -2 1} + {-4 3 -1 2} + {-4 3 1 -2} + {-4 3 2 -1} + {-3 -4 -2 -1} + {-3 -4 -1 -2} + {-3 -4 1 2} + {-3 -4 2 1} + {-3 -2 -4 -1} + {-3 -2 -1 -4} + {-3 -2 1 4} + {-3 -2 4 1} + {-3 -1 -4 -2} + {-3 -1 -2 -4} + {-3 -1 2 4} + {-3 -1 4 2} + {-3 1 -4 2} + {-3 1 -2 4} + {-3 1 2 -4} + {-3 1 4 -2} + {-3 2 -4 1} + {-3 2 -1 4} + {-3 2 1 -4} + {-3 2 4 -1} + {-3 4 -2 1} + {-3 4 -1 2} + {-3 4 1 -2} + {-3 4 2 -1} + {-2 -4 -3 -1} + {-2 -4 -1 -3} + {-2 -4 1 3} + {-2 -4 3 1} + {-2 -3 -4 -1} + {-2 -3 -1 -4} + {-2 -3 1 4} + {-2 -3 4 1} + {-2 -1 -4 -3} + {-2 -1 -3 -4} + {-2 -1 3 4} + {-2 -1 4 3} + {-2 1 -4 3} + {-2 1 -3 4} + {-2 1 3 -4} + {-2 1 4 -3} + {-2 3 -4 1} + {-2 3 -1 4} + {-2 3 1 -4} + {-2 3 4 -1} + {-2 4 -3 1} + {-2 4 -1 3} + {-2 4 1 -3} + {-2 4 3 -1} + {-1 -4 -3 -2} + {-1 -4 -2 -3} + {-1 -4 2 3} + {-1 -4 3 2} + {-1 -3 -4 -2} + {-1 -3 -2 -4} + {-1 -3 2 4} + {-1 -3 4 2} + {-1 -2 -4 -3} + {-1 -2 -3 -4} + {-1 -2 3 4} + {-1 -2 4 3} + {-1 2 -4 3} + {-1 2 -3 4} + {-1 2 3 -4} + {-1 2 4 -3} + {-1 3 -4 2} + {-1 3 -2 4} + {-1 3 2 -4} + {-1 3 4 -2} + {-1 4 -3 2} + {-1 4 -2 3} + {-1 4 2 -3} + {-1 4 3 -2} + {1 -4 -3 2} + {1 -4 -2 3} + {1 -4 2 -3} + {1 -4 3 -2} + {1 -3 -4 2} + {1 -3 -2 4} + {1 -3 2 -4} + {1 -3 4 -2} + {1 -2 -4 3} + {1 -2 -3 4} + {1 -2 3 -4} + {1 -2 4 -3} + {1 2 -4 -3} + {1 2 -3 -4} + {1 2 3 4} + {1 2 4 3} + {1 3 -4 -2} + {1 3 -2 -4} + {1 3 2 4} + {1 3 4 2} + {1 4 -3 -2} + {1 4 -2 -3} + {1 4 2 3} + {1 4 3 2} + {2 -4 -3 1} + {2 -4 -1 3} + {2 -4 1 -3} + {2 -4 3 -1} + {2 -3 -4 1} + {2 -3 -1 4} + {2 -3 1 -4} + {2 -3 4 -1} + {2 -1 -4 3} + {2 -1 -3 4} + {2 -1 3 -4} + {2 -1 4 -3} + {2 1 -4 -3} + {2 1 -3 -4} + {2 1 3 4} + {2 1 4 3} + {2 3 -4 -1} + {2 3 -1 -4} + {2 3 1 4} + {2 3 4 1} + {2 4 -3 -1} + {2 4 -1 -3} + {2 4 1 3} + {2 4 3 1} + {3 -4 -2 1} + {3 -4 -1 2} + {3 -4 1 -2} + {3 -4 2 -1} + {3 -2 -4 1} + {3 -2 -1 4} + {3 -2 1 -4} + {3 -2 4 -1} + {3 -1 -4 2} + {3 -1 -2 4} + {3 -1 2 -4} + {3 -1 4 -2} + {3 1 -4 -2} + {3 1 -2 -4} + {3 1 2 4} + {3 1 4 2} + {3 2 -4 -1} + {3 2 -1 -4} + {3 2 1 4} + {3 2 4 1} + {3 4 -2 -1} + {3 4 -1 -2} + {3 4 1 2} + {3 4 2 1} + {4 -3 -2 1} + {4 -3 -1 2} + {4 -3 1 -2} + {4 -3 2 -1} + {4 -2 -3 1} + {4 -2 -1 3} + {4 -2 1 -3} + {4 -2 3 -1} + {4 -1 -3 2} + {4 -1 -2 3} + {4 -1 2 -3} + {4 -1 3 -2} + {4 1 -3 -2} + {4 1 -2 -3} + {4 1 2 3} + {4 1 3 2} + {4 2 -3 -1} + {4 2 -1 -3} + {4 2 1 3} + {4 2 3 1} + {4 3 -2 -1} + {4 3 -1 -2} + {4 3 1 2} + {4 3 2 1} +} +192 \ No newline at end of file diff --git a/coxeter_group_orbits/ay4me/program.cc b/coxeter_group_orbits/ay4me/program.cc new file mode 100755 index 0000000..ec51502 --- /dev/null +++ b/coxeter_group_orbits/ay4me/program.cc @@ -0,0 +1,22 @@ +#include "orbit.h" +#include + + +int main() +{ + GeneratorList generators; + VectorType v; + input("file.txt", v, generators); + Orbit generatedOrbit = orbit(generators, v); + //sanityCheck(generatedOrbit.size(),"file.txt"); + std::ofstream file; + file.open ("out.txt"); + out(file, generatedOrbit, true); + +} + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/ay4me/test_orbits.cc b/coxeter_group_orbits/ay4me/test_orbits.cc new file mode 100755 index 0000000..1e6e1a9 --- /dev/null +++ b/coxeter_group_orbits/ay4me/test_orbits.cc @@ -0,0 +1,69 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#define BOOST_TEST_MODULE orbits +#include + +#include "orbit.h" + +struct b3_fixture { + b3_fixture() + : generators(simple_roots('B', 3)) + {} + GeneratorList generators; +}; + +BOOST_FIXTURE_TEST_CASE( b3_orbit_012, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 3}).size(), (size_t) 48); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_12, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 3}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_02, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 2}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_01, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 0}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_0, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 0, 0}).size(), (size_t) 6); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_1, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 0}).size(), (size_t) 12); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_2, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 1}).size(), (size_t) 8); +} + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/constantin/input b/coxeter_group_orbits/constantin/input new file mode 100644 index 0000000..b3f00ca --- /dev/null +++ b/coxeter_group_orbits/constantin/input @@ -0,0 +1,4 @@ +1 1 +1 +22.2 0 +0 7.4 diff --git a/coxeter_group_orbits/constantin/orbit b/coxeter_group_orbits/constantin/orbit new file mode 100755 index 0000000..29e51c6 Binary files /dev/null and b/coxeter_group_orbits/constantin/orbit differ diff --git a/coxeter_group_orbits/constantin/orbit.cc b/coxeter_group_orbits/constantin/orbit.cc new file mode 100644 index 0000000..7a57a28 --- /dev/null +++ b/coxeter_group_orbits/constantin/orbit.cc @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include "stdlib.h" + +int main() +{ + std::ifstream iFile("input"); + std::ofstream oFile("output"); + std::string input = ""; + std::vector point; + int wordLength; + std::vector > normals; + double test; + + //read the input file + if (iFile.is_open()) { + //read the input point + if (iFile.good()) { + std::getline(iFile, input); + std::stringstream ss(input); + double coo = 0; + while (ss.good()) { + if (ss >> coo) { + point.push_back(coo); + } + } + } + //read the input word length + if (iFile.good()) { + std::getline(iFile, input); + std::stringstream ss(input); + int l; + while (ss.good()) { + if (ss >> l) { + wordLength = l; + } + } + } + //read the input normal vectors + while (iFile.good()) { + std::getline(iFile, input); + std::stringstream ss(input); + double coo = 0; + std::vector n; + while (ss.good()) { + if (ss >> coo) { + n.push_back(coo); + } + } + normals.push_back(n); + } + } + normals.pop_back(); + + //normalize the normal vectors + for (int i=0; i words(normals.size()-1); +// words.reserve(normals.size()-1); +// std::iota(words.begin(), words.end(),0); + + //generate the orbit (up to wordLength) + std::set > orbit = {point}; + for (int i=0; i > newSet; + for (auto p : orbit) { + for (auto n : normals) { + std::vector newPoint(p.size()); + double weight = 0; + weight = std::inner_product(p.begin(), p.end(), n.begin(), weight); + for (int j=0; j +#include +#include +#include "types.h" + +GeneratorList simple_roots_type_A (const int n) +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 0 ... 0 0 + 0 1 -1 0 ... 0 0 + ... + 0 0 0 0 ... 1 -1 + In particular, they lie in the plane (sum of coordinates = 0) + */ + GeneratorList R(n, n+1); + for (int i=0; i n-1, + */ + VectorType v(n); + v[n-1] = 1; + GeneratorList G = simple_roots_type_A(n-1); + G.push_back(v); + return G; +} + +GeneratorList simple_roots_type_C (const int n) +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 0 ... 0 0 + 0 1 -1 0 ... 0 0 + ... + 0 0 0 0 ... 1 -1 + 0 0 0 0 ... 0 2 + + The Dynkin diagram is: + + 0 ---- 1 ---- ... ---- n-2 <--(4)-- n-1, + */ + VectorType v(n); + v[n-1] = 2; + GeneratorList G = simple_roots_type_A(n-1); + G.push_back(v); + return G; +} + +GeneratorList simple_roots_type_D (const int n) +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 0 ... 0 0 + 0 1 -1 0 ... 0 0 + ... + 0 0 0 0 ... 1 -1 + 0 0 0 0 ... 1 1 + The indexing of the Dynkin diagram is + + n-2 + / + 0 - 1 - 2 - ... - n-3 + \ + n-1 + + */ + VectorType v(n); + v[n-2] = v[n-1] = 1; + GeneratorList G = simple_roots_type_A(n-1); + G.push_back(v); + return G; +} + +GeneratorList simple_roots_type_E6() +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 0 0 0 + 0 1 -1 0 0 0 + 0 0 1 -1 0 0 + 0 0 0 1 -1 0 + 0 0 0 1 1 0 +-1/2(1 1 1 1 1 -sqrt(3)) + + The indexing of the Dynkin diagram is + + + 3 + | + | + 0 ---- 1 ---- 2 ---- 4 ---- 5 + + */ + VectorType v(6); + for (int i=0; i<5; ++i) + v[i] = -0.5; + v[5] = 0.5 * sqrt(3); + GeneratorList G = simple_roots_type_D(5); + for (int i=0; i<5; ++i) + G[i].push_back(0); + G.push_back(v); + return G; +} + +GeneratorList simple_roots_type_E7() +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 0 0 0 0 + 0 1 -1 0 0 0 0 + 0 0 1 -1 0 0 0 + 0 0 0 1 -1 0 0 + 0 0 0 0 1 -1 0 + 0 0 0 0 1 1 0 +-1/2(1 1 1 1 1 1 -sqrt(2)) + + The indexing of the Dynkin diagram is + + + 4 + | + | + 0 ---- 1 ---- 2 ---- 3 ---- 5 ---- 6 + + */ + VectorType v(7); + for (int i=0; i<6; ++i) + v[i] = -0.5; + v[6] = 0.5 * sqrt(2); + GeneratorList G = simple_roots_type_D(6); + for (int i=0; i<6; ++i) + G[i].push_back(0); + G.push_back(v); + return G; +} + +GeneratorList simple_roots_type_E8() +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 0 0 0 0 0 + 0 1 -1 0 0 0 0 0 + ... + 0 0 0 0 0 1 -1 0 + 0 0 0 0 0 1 1 0 +-1/2(1 1 1 1 1 1 1 1) + + These are the coordinates in the even coordinate system. + The indexing of the Dynkin diagram is + + + 5 + | + | + 0 ---- 1 ---- 2 ---- 3 ---- 4 ---- 6 ---- 7 + + */ + VectorType v(8); + for (int i=0; i<8; ++i) + v[i] = -0.5; + GeneratorList G = simple_roots_type_D(7); + for (int i=0; i<7; ++i) + G[i].push_back(0); + G.push_back(v); + return G; +} + +GeneratorList simple_roots_type_F4() +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 0 + 0 1 -1 0 + 0 0 1 0 + -1/2 -1/2 -1/2 -1/2 + + The Dynkin diagram is: + + 0 ---- 1 --(4)--> 2 ---- 3 + */ + GeneratorList R(4,4); + R(0,0) = R(1,1) = R(2,2) = 1; + R(0,1) = R(1,2) = -1; + R(3,0) = R(3,1) = R(3,2) = R(3,3) = -0.5; + return R; +} + +GeneratorList simple_roots_type_G2() +{ + /* + Read rowwise, these simple root vectors are + 1 -1 0 + -1 2 -1 + + Notice that each row sums to zero. + + The Dynkin diagram is: + + 0 <--(6)-- 1 + */ + GeneratorList R(2,3); + R(0,0) = 1; + R(0,1) = R(1,0) = R(1,2) = -1; + R(1,1) = 2; + return R; +} + +GeneratorList simple_roots_type_H3() +{ + const NumberType tau(0.5 + 0.5 * sqrt(5)); // golden ratio + + /* + For H_3, the Dynkin diagram is + + 0 --(5)-- 1 ---- 2, + + and the simple root vectors are, + + 2 0 0 + a b -1 + 0 0 2 + + with a=-tau and b=1/tau. Notice they all have length 2. + + */ + + GeneratorList R(3,3); + R(0,0) = R(2,2) = 2; + R(1,0) = -tau; R(1,1) = tau - 1; R(1,2) = -1; + return R; +} + +GeneratorList simple_roots_type_H4() +{ + const NumberType tau(0.5 + 0.5 * sqrt(5)); // golden ratio + + /* + For H_4, the Dynkin diagram is + + 0 --(5)-- 1 ---- 2 ---- 3, + + and the simple root vectors are, according to + [John H. Stembridge, A construction of H_4 without miracles, + Discrete Comput. Geom. 22, No.3, 425-427 (1999)], + + a b b b + -1 1 0 0 + 0 -1 1 0 + 0 0 -1 1 + + with a=(1+tau)/2 and b=(1-tau)/2, so that the length of each root is sqrt{2}. + + */ + GeneratorList R(4, 4); + + R(0,0) = (1+tau) * 0.5; + R(0,1) = R(0,2) = R(0,3) = (1-tau) * 0.5; + + for (int i=0; i<3; ++i) { + R(i+1, i) = -1; + R(i+1, i+1) = 1; + } + return R; +} + + + +GeneratorList simple_roots(char type, int dim) +{ + switch(type) { + case 'a': + case 'A': + return simple_roots_type_A(dim); + + case 'b': + case 'B': + return simple_roots_type_B(dim); + + case 'c': + case 'C': + return simple_roots_type_C(dim); + + case 'd': + case 'D': + return simple_roots_type_D(dim); + + case 'e': + case 'E': + switch(dim) { + case 6: + return simple_roots_type_E6(); + case 7: + return simple_roots_type_E7(); + case 8: + return simple_roots_type_E8(); + default: + throw InvalidGroupException(); + } + + case 'f': + case 'F': + switch(dim) { + case 4: + return simple_roots_type_F4(); + default: + throw InvalidGroupException(); + } + + case 'g': + case 'G': + switch(dim) { + case 2: + return simple_roots_type_G2(); + default: + throw InvalidGroupException(); + } + + case 'h': + case 'H': + switch(dim) { + case 3: + return simple_roots_type_H3(); + case 4: + return simple_roots_type_H4(); + default: + throw InvalidGroupException(); + } + + default: + throw NotImplementedException(); + } +} + +#endif // __GENERATORS_H_ + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/neosonea/orbit.h b/coxeter_group_orbits/neosonea/orbit.h new file mode 100644 index 0000000..998943a --- /dev/null +++ b/coxeter_group_orbits/neosonea/orbit.h @@ -0,0 +1,162 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __ORBIT_H_ +#define __ORBIT_H_ + +#include +#include +#include +#include + +class NotImplementedException : public std::exception {}; + +typedef double NumberType; // this probably isn't going to work +typedef std::vector VectorType; +typedef std::vector GeneratorList; +typedef std::set Orbit; +//class Orbit : std::set{ +// bool operator<(const Orbit& other) const { + //Pento: return coos < other.coos || name < other.name; +// return this. < other.; +// } +//}; + + +GeneratorList simple_roots(char type, int dim) +{ + if (dim <= 1) throw new std::exception();//"dim has to be larger than 1"); + const float PI = 3.14159265359; + switch(type) { + case 'a': + case 'A':{ + GeneratorList gens (dim, VectorType (dim+1, 0)); + for( int i=0; i < dim; i++ ){ + gens[i][i] = 1; + gens[i][i+1] = -1; + } + return gens; + } + case 'b': + case 'c': + case 'C': + case 'B':{ + GeneratorList gens (dim, VectorType (dim, 0)); + for( int i=0; i < dim-1; i++ ){ + gens[i][i] = 1; + gens[i][i+1] = -1; + } + gens[dim-1][dim-1] = 1; + return gens; + } + case 'd': + case 'D':{ + GeneratorList gens (dim, VectorType (dim, 0)); + for( int i=0; i < dim-1; i++ ){ + gens[i][i] = 1; + gens[i][i+1] = -1; + } + gens[dim-1][dim-1] = 1; + gens[dim-1][dim-2] = 1; + return gens; + } + case 'e': + case 'E':{ + if (dim < 6 || dim > 8) throw new std::exception(); + GeneratorList gens (dim, VectorType (dim, 0)); + const double a = -2. - sqrt(3); + for( int i=0; i < dim-1; i++ ){ + gens[i][i] = 1; + gens[i][i+1] = -1; + gens[dim-1][i] = i < 3? a : 1; + } + gens[dim-1][dim-1] = 1; + return gens; + } + case 'f': + case 'F': + if (dim != 4) throw new NotImplementedException(); + return { {1,-1,0,0}, {0,1,-1,0}, {0,0,1,-1}, {-1,-1,-1,-1} }; + case 'g': + case 'G': + if (dim != 2) throw new NotImplementedException(); + return { {1,0}, {1,-1} }; + case 'h': + case 'H':{//TODO + if (dim < 2 || dim > 4) throw new std::exception(); + GeneratorList gens (dim, VectorType (dim, 0)); + const double a = -2. - sqrt(3); + for( int i=0; i < dim-1; i++ ){ + gens[i][i] = 1; + gens[i][i+1] = -1; + } + gens[dim-1][dim-1] = a; + return gens; + } + case 'i': + case 'I':{ + GeneratorList gens (2, VectorType (dim, 0)); + for( int i=0; i < dim-1; i++ ){ + gens[0][0] = 1; + gens[1][0] = -cos(PI/dim); + gens[1][1] = sin(PI/dim); + } + return gens; + } + + default: + throw new NotImplementedException(); + } +} + +VectorType times( double factor, VectorType& vector ){ + VectorType result(vector); + for( int i=0; i < vector.size(); i++ ) + result[i] *= factor; + return result; +} +double scalar_prod( VectorType& vector1, VectorType& vector2 ){ + double sum = 0; + for( int i=0; i < vector1.size(); i++ ) + sum += vector1[i] * vector2[i]; + return sum; +} +VectorType add( VectorType& vector1, VectorType& vector2 ){ + VectorType sum(vector1); + for( int i=0; i < vector1.size(); i++ ) + sum[i] += vector2[i]; + return sum; +} + +Orbit orbit(const GeneratorList& generators, const VectorType& v) +{ + if ( v.size() != generators[0].size() ) throw new NotImplementedException(); + Orbit mapped; + mapped.insert(v); + for( const auto& g : generators ){ + //mapped.insert( times( -2. * (*scalar_prod(g,v)), g) ); + } + return mapped; +} + + +#endif // __ORBIT_H_ + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/neosonea/test_orbits.cc b/coxeter_group_orbits/neosonea/test_orbits.cc new file mode 100644 index 0000000..1e6e1a9 --- /dev/null +++ b/coxeter_group_orbits/neosonea/test_orbits.cc @@ -0,0 +1,69 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#define BOOST_TEST_MODULE orbits +#include + +#include "orbit.h" + +struct b3_fixture { + b3_fixture() + : generators(simple_roots('B', 3)) + {} + GeneratorList generators; +}; + +BOOST_FIXTURE_TEST_CASE( b3_orbit_012, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 3}).size(), (size_t) 48); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_12, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 3}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_02, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 2}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_01, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 2, 0}).size(), (size_t) 24); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_0, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 0, 0}).size(), (size_t) 6); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_1, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 0}).size(), (size_t) 12); +} + +BOOST_FIXTURE_TEST_CASE( b3_orbit_2, b3_fixture ) +{ + BOOST_CHECK_EQUAL(orbit(generators, {1, 1, 1}).size(), (size_t) 8); +} + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/orbit.h b/coxeter_group_orbits/orbit.h new file mode 100644 index 0000000..3396c11 --- /dev/null +++ b/coxeter_group_orbits/orbit.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __ORBIT_H_ +#define __ORBIT_H_ + +#include +#include "types.h" +#include "generators.h" + + +Orbit orbit(const GeneratorList& generators, const VectorType& v) +{ + return std::set(); +} + + +#endif // __ORBIT_H_ + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/coxeter_group_orbits/specification.pdf b/coxeter_group_orbits/specification.pdf new file mode 100644 index 0000000..73e2271 Binary files /dev/null and b/coxeter_group_orbits/specification.pdf differ diff --git a/coxeter_group_orbits/specification.tex b/coxeter_group_orbits/specification.tex new file mode 100644 index 0000000..fdf75fd --- /dev/null +++ b/coxeter_group_orbits/specification.tex @@ -0,0 +1,85 @@ +\documentclass[11pt]{amsart} + +\usepackage{a4wide} +\usepackage{bbm} +\usepackage{graphicx} + +\newcommand{\R}{\mathbbm{R}} + +\title{Specification of the project\\``Orbits in Coxeter Groups''} +\author{Julian Pfeifle\\ Implementation of Geometric Algorithms, 2015} +\date{May, 2015} +\begin{document} + +\maketitle + +\section{Input} + +The input to your program consists of +\begin{itemize} +\item a string of length 2 of the form {\tt X}$n$, where {\tt X} is a letter and $n$ a number +\item A vector $v$ of length $n$ +\end{itemize} + +You should read this data from a file that contains the string on the first line and the vector on the second. + +Your code for processing this data should be in a separate function that is called from the function responsible for reading the input. This also makes it possible to test your program from the testsuite. + + +\section{Validation} + +\begin{itemize} +\item The input string must refer to a Coxeter arrangement of hyperplanes, i.e., be one of + \begin{center} + \ttfamily A$n$, B$n$, D$n$, E6, E7, E8, F4, G2, H3, H4, I$n$. + + \bigskip + \includegraphics[width=\linewidth]{finite-coxeter.png} + \end{center} +\item The vector $v$ should really have length $n$ +\end{itemize} + + +\section{Processing} + +\begin{enumerate} +\item First, you must determine a set of reflecting linear hyperplanes corresponding to the selected Coxeter group. These should be represented by their normal vectors, and these in turn should be hard-coded in your program. + +For example, a standard set of normal vectors for the Coxeter arrangement of type~$A_n$ is formed by the rows of the matrix +\[ + \begin{pmatrix} + 1 & -1 & 0 & 0 &\dots & 0 & 0 \\ + 0 & 1 & -1 & 0 &\dots & 0 & 0 \\ + \dots\\ + 0 & 0 & 0 & 0 &\dots & -1 & 0 \\ + 0 & 0 & 0 & 0 &\dots & 1 & -1 + \end{pmatrix}, +\] +and for type $B_n$ by the rows of the matrix +\[ + \begin{pmatrix} + 1 & -1 & 0 & 0 &\dots & 0 & 0\\ + 0 & 1 & -1 & 0 &\dots & 0 & 0\\ + \dots\\ + 0 & 0 & 0 & 0 &\dots & 1 & -1\\ + 0 & 0 & 0 & 0 &\dots & 0 & 1 + \end{pmatrix}. +\] +Notice that the matrix for $A_n$ has size $n\times(n+1)$, so it specifies $n$~normal vectors in $\R^{n+1}$. This is the only Coxeter group for which this happens, all the others (for example the group~$B_n$ in the second example) are generated by $n$~vectors in~$\R^n$. + +Also, you should check that the relation +\[ + \cos\frac{\pi}{p_{i,j}} + \ = \ + -\frac{\langle w_i, \; w_j\rangle}{\|w_i\|\|w_j\|} +\] +holds for any pair of vectors $w_i$, $w_j$ of $A_n$ and $B_n$, where $\frac{\pi}{p_{i,j}}$ is the angle between the hyperplanes with normal vectors $w_i$~and~$w_j$, and $p_{i,j}$~is encoded by the Coxeter-Dynkin diagram: Two nodes not connected by an edge have $p_{i,j}=2$, an undecorated edge between two nodes represents $p_{i,j}=3$, and in all other cases the edge is labeled with $p_{i,j}$. + +Can you find representative matrices for other Coxeter diagrams? +\end{enumerate} + +\section{Output} + +By default, you should output the size of the orbit of~$v$ that is obtained by repeatedly reflecting~$v$ in the hyperplanes given by the~$w_i$. Via a flag on the command line, you should be able to specify whether to additionally output the orbit itself. + +\end{document} diff --git a/coxeter_group_orbits/types.h b/coxeter_group_orbits/types.h new file mode 100644 index 0000000..665360a --- /dev/null +++ b/coxeter_group_orbits/types.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __TYPES_H_ +#define __TYPES_H_ + +#include +#include + +class NotImplementedException : public std::exception {}; +class InvalidGroupException : public std::exception {}; + +typedef long double NumberType; // this might work +typedef std::vector VectorType; +typedef std::set Orbit; + +class GeneratorList : public std::vector { +public: + GeneratorList(int r, int c) + : std::vector(r) + { + for (int i=0; i +#include + +namespace boost +{ + +// teach Boost.Test how to print std::array +template +inline wrap_stringstream& +operator<<(wrap_stringstream& wrapped, const std::array& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + + +// teach Boost.Test how to print std::vector +template +inline wrap_stringstream& +operator<<(wrap_stringstream& wrapped, std::vector const& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + +// teach Boost.Test how to print std::pair +template +inline wrap_stringstream& +operator<<(wrap_stringstream& wrapped, std::pair const& item) +{ + return wrapped << '<' << item.first << ',' << item.second << '>'; +} + + +} // end namespace boost + +namespace std { + +inline +bool operator!=(const array& left, const array& right) { + return + left[0] != right[0] || + left[1] != right[1]; +} + +} // end namespace std + +#endif // __BOOST_COUT_WRAPPERS_H + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/dancing_links/c++/dancing_links.h b/dancing_links/c++/dancing_links.h new file mode 100644 index 0000000..d9bbd3e --- /dev/null +++ b/dancing_links/c++/dancing_links.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __DANCING_LINKS_H__ +#define __DANCING_LINKS_H__ + +#include +#include "incidence_matrix.h" + +namespace dancing_links { + + using namespace incidence_matrix::incidence_matrix; + +typedef std::vector> Solution; + +Solution solution(const std::vector& OO, + int k) +{ + Solution solution; + for (int i=0; i row; + IncidenceCell* cur = OO[i]; + row.push_back(cur->list_header->name); + cur = cur->right; + while (cur != OO[i]) { + row.push_back(cur->list_header->name); + cur = cur->right; + } + solution.push_back(row); + } + return solution; +} + +ColumnObject* choose_column_object(ColumnObject* h) +{ + int s = std::numeric_limits::max(); + ColumnObject* j = h->right, *c(nullptr); + while (j != h) { + if (j->size < s) { + s = j->size; + c = j; + } + j = j->right; + } + return c; +} + +template +void search (int k, + IncidenceMatrix& I, + std::vector& OO, + std::vector& solutions) +{ + ColumnObject* h = I.column_object_of_name["root"]; + if (h->right == h) { + solutions.push_back(solution(OO,k)); + return; + } + + ColumnObject* c = choose_column_object(h); + I.cover_column(c); + IncidenceCell* r = static_cast(c->down); + while (static_cast(r) != static_cast(c)) { + OO.resize(k+1); + OO[k] = static_cast(r); + + IncidenceCell* j = r->right; + while(j != r) { + I.cover_column(j->list_header); + j = j->right; + } + + search(k+1, I, OO, solutions); + + r = OO[k]; + c = r->list_header; + + j = r->left; + while (j != r) { + I.uncover_column(j->list_header); + j = j->left; + } + + r = static_cast(r->down); + } + I.uncover_column(c); +} + +template +std::vector Algorithm_X(IncidenceMatrix& I) +{ + std::vector OO; + std::vector solutions; + search(0, I, OO, solutions); + return solutions; +} + +} // end namespace dancing_links + +#endif // __DANCING_LINKS_H__ + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: + + diff --git a/dancing_links/c++/incidence_matrix.h b/dancing_links/c++/incidence_matrix.h new file mode 100644 index 0000000..351e992 --- /dev/null +++ b/dancing_links/c++/incidence_matrix.h @@ -0,0 +1,350 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __INCIDENCE_MATRIX_H__ +#define __INCIDENCE_MATRIX_H__ + +#include +#include +#include +#include +#include +#include "stl_wrappers.h" + + + +namespace incidence_matrix { + +std::string to_string(const std::array& p) +{ + std::string concat_p("<"); + bool first = true; + for (const auto& x : p) { + concat_p += (!first ? "," : "") + std::to_string(x); + first = false; + } + concat_p += ">"; + return concat_p; +} + +std::string to_string(const std::string& p) +{ + return p; +} + +class ForbiddenPlacementException : public std::exception {}; + +typedef std::array CellRepType; +typedef std::vector ColRepType; +typedef std::vector RowRepType; + +class IncidenceCellBase { +public: + IncidenceCellBase* up; + IncidenceCellBase* down; + std::string name; + + IncidenceCellBase() {} + + IncidenceCellBase(IncidenceCellBase* up, + IncidenceCellBase* down, + const std::string& name) + : up(up) + , down(down) + , name(name) + {} + + IncidenceCellBase(const std::string& name) + : up(this) + , down(this) + , name(name) + {} +}; + +class ColumnObject; + +class IncidenceCell : public IncidenceCellBase { +public: + IncidenceCell* left; + IncidenceCell* right; + ColumnObject* list_header; + + IncidenceCell() {} + + IncidenceCell(IncidenceCell* left, + IncidenceCell* right, + IncidenceCellBase* up, + IncidenceCellBase* down, + ColumnObject* list_header, + const std::string& name) + : IncidenceCellBase(up, down, name) + , left(left) + , right(right) + , list_header(list_header) + {} + + CellRepType representation() const { + return { "c", name, left->name, right->name, up->name, down->name }; + } + +}; + +class ColumnObject : public IncidenceCellBase { +public: + ColumnObject* left; + ColumnObject* right; + int size; + ColumnObject(ColumnObject* left, + ColumnObject* right, + IncidenceCellBase* up, + IncidenceCellBase* down, + const std::string& name) + : IncidenceCellBase(up, down, name) + , left(left) + , right(right) + , size(0) + {} + + ColumnObject(const std::string& name) + : IncidenceCellBase(name) + , left(this) + , right(this) + , size(0) + {} + + ColRepType representation() const { + ColRepType representation; + representation.push_back( { "h(" + std::to_string(size) + ")", name, left->name, right->name, up->name, down->name } ); + IncidenceCellBase* current_cell(down); + while (current_cell != this) { + // We know that all cells except "this" are really IncidenceCells! + representation.push_back(static_cast(current_cell)->representation()); + current_cell = current_cell->down; + } + return representation; + } +}; + + +template +class IncidenceMatrix { +public: + ColumnObject* h; + int rows; + std::map column_object_of_name; + std::map index_of_piece_placement; + + IncidenceMatrix(const std::vector& names) + : h(new ColumnObject("root")) + , rows(0) + , column_object_of_name{ { "root", h } } + { + ColumnObject* current_column_object{h}; + for (const auto& n : names) { + index_of_piece_placement[n] = 0; + insert_column_object(current_column_object, h, n); + current_column_object = current_column_object->right; + column_object_of_name[n] = current_column_object; + } + } + + void insert_column_object(ColumnObject* left, + ColumnObject* right, + const std::string& name) { + ColumnObject* x = new ColumnObject(name); + x->left = left; + x->right = right; + x->up = x; + x->down = x; + right->left = x; + left->right = x; + } + + std::vector representation() const { + ColRepType root_rep; + root_rep.push_back( { "r(0)", "root", h->left->name, h->right->name, h->up->name, h->down->name } ); + std::vector representation; + representation.push_back(root_rep); + + ColumnObject* current_column_object{h->right}; + while (current_column_object->name != "root") { + representation.push_back(current_column_object->representation()); + current_column_object = current_column_object->right; + } + return representation; + } + + std::vector row_representation() const { + std::vector row_representation; + ColumnObject* current_column_object{h->right}; + while (current_column_object->name != "root" && + current_column_object->name.find_first_of("{ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") != std::string::npos) { + IncidenceCellBase* head_elt = current_column_object->down; + while (head_elt != current_column_object) { + const IncidenceCell* alias = static_cast(head_elt); + RowRepType row_rep { alias->name }; + IncidenceCell* current_elt (alias->right); + while (current_elt != alias) { + row_rep.push_back(current_elt->list_header->name); + current_elt = current_elt->right; + } + row_representation.push_back(row_rep); + head_elt = head_elt->down; + } + current_column_object = current_column_object->right; + } + return row_representation; + } + + void append_row(const std::string& tile_name, + const std::vector& placement) { + ColumnObject* row_header_col = column_object_of_name[tile_name]; + IncidenceCell* row_header = new IncidenceCell(nullptr, + nullptr, + row_header_col->up, + row_header_col, + row_header_col, + tile_name + "{" + std::to_string(index_of_piece_placement[tile_name]) + "}"); + row_header->left = row_header->right = row_header; + row_header_col->up->down = row_header; + row_header_col->up = row_header; + ++row_header_col->size; + ++index_of_piece_placement[tile_name]; + for (const auto& p : placement) { + const std::string concat_p { to_string(p) }; + ColumnObject* pos_col = column_object_of_name[concat_p]; + IncidenceCell* x = new IncidenceCell(row_header->left, row_header, pos_col->up, pos_col, pos_col, tile_name + concat_p); + x->up->down = x->down->up = x->right->left = x->left->right = x; + ++pos_col->size; + } + ++rows; + } + + typedef std::map>> RequiredPlacementType; + + template + void append_translates_2d(const TileContainer& tiles, + const CooType& board_size, + std::function is_allowed = [](const CooType&) -> bool { return true; }, + const RequiredPlacementType& required_placements = RequiredPlacementType()) { + for (const auto& tile : tiles) { + typename RequiredPlacementType::const_iterator tit = required_placements.find(tile.name); + if (tit != required_placements.end()) { + append_required_placements(tile, tit->second, is_allowed, board_size); + } else { + append_unrestricted_translates_2d(tile, board_size, is_allowed); + } + } + } + + template + bool is_legal(const Placement& placement, + std::function is_allowed, + const CooType& board_size) { + bool legal(true); + for (typename Placement::const_iterator pit = placement.begin(), pend = placement.end(); legal && pit != pend; ++pit) { + const CooType coo(*pit); + if (!is_allowed(coo)) { + legal = false; + } + for (unsigned int i=0; legal && i= board_size[i]) { + legal = false; + } + } + } + return legal; + } + + template + void append_required_placements(const Tile& tile, + const PlacementContainer& placements, + std::function is_allowed, + const CooType& board_size) { + for (const auto& placement : placements) { + if (!is_legal(placement, is_allowed, board_size)) { + throw ForbiddenPlacementException(); + } + append_row(tile.name, placement); + } + } + + template + void append_unrestricted_translates_2d(const Tile& _tile, + const CooType& board_size, + std::function is_allowed) + { + Tile tile(_tile); + const CooType infty_norm = tile.max(); + for (int i=0; i < board_size[0] - infty_norm[0]; ++i) { + for (int j=0; j < board_size[1] - infty_norm[1]; ++j) { + if (is_legal(tile.coos, is_allowed, board_size)) { + append_row(tile.name, tile.coos); + } + tile.translate_one(1); + } + tile.translate_coo(1, infty_norm[1] - board_size[1]); + tile.translate_one(0); + } + } + + void cover_column(ColumnObject* c) { + c->right->left = c->left; + c->left->right = c->right; + IncidenceCellBase* i = c->down; + while (i != c) { + // we know that i points to an IncidenceCell, not a ColumnObject + IncidenceCell* j = static_cast(i)->right; + while (j != static_cast(i)) { + j->down->up = j->up; + j->up->down = j->down; + --j->list_header->size; + j = j->right; + } + i = i->down; + } + } + + void uncover_column(ColumnObject* c) { + IncidenceCellBase* i = c->up; + while (i != c) { + // we know that i points to an IncidenceCell, not a ColumnObject + IncidenceCell* j = static_cast(i)->left; + while (j != static_cast(i)) { + ++j->list_header->size; + j->down->up = j; + j->up->down = j; + j = j->left; + } + i = i->up; + } + c->right->left = c; + c->left->right = c; + } + +}; + +} // end namespace incidence_matrix + +#endif // __INCIDENCE_MATRIX_H__ + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: + diff --git a/dancing_links/c++/pentominos.h b/dancing_links/c++/pentominos.h new file mode 100644 index 0000000..117bd3a --- /dev/null +++ b/dancing_links/c++/pentominos.h @@ -0,0 +1,237 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#ifndef __PENTOMINOS_H__ +#define __PENTOMINOS_H__ + +#include +#include +#include +#include +#include +#include + +namespace pentominos { + +class InvalidPentominoException: public std::exception {}; + +typedef std::array CooType; + +class Pentomino { + +public: + std::string name; + std::vector> coos; + + int min_in_coo(int coo) const { + int min(std::numeric_limits::max()); + for (const auto& c : coos) { + if (c[coo] < min) min = c[coo]; + } + return min; + } + + int max_in_coo(int coo) const { + int max(std::numeric_limits::min()); + for (const auto& c : coos) { + if (c[coo] > max) max = c[coo]; + } + return max; + } + + void normalize_coo(int coo) { + const int min = min_in_coo(coo); + for (auto& c : coos) { + c[coo] -= min; + } + } + +public: + Pentomino& normalize() { + for (int i : {0, 1}) { + normalize_coo(i); + } + std::sort(coos.begin(), coos.end()); + return *this; + } + + Pentomino(const std::string& name, + const std::vector>& coos) + : name{name} + , coos{coos} + { + normalize(); + } + + Pentomino(const std::string& x) + : name{x} + { + switch(x[0]) { // because switch doesn't work on strings + case 'F': + coos = {{0,1},{1,0},{1,1},{1,2},{2,2}}; break; + case 'I': + coos = {{0,0},{0,1},{0,2},{0,3},{0,4}}; break; + case 'L': + coos = {{0,0},{0,1},{0,2},{0,3},{1,0}}; break; + case 'N': + coos = {{0,0},{0,1},{1,1},{1,2},{1,3}}; break; + case 'P': + coos = {{0,0},{0,1},{0,2},{1,1},{1,2}}; break; + case 'T': + coos = {{0,2},{1,0},{1,1},{1,2},{2,2}}; break; + case 'U': + coos = {{0,0},{0,1},{1,0},{2,0},{2,1}}; break; + case 'V': + coos = {{0,0},{1,0},{2,0},{2,1},{2,2}}; break; + case 'W': + coos = {{0,0},{1,0},{1,1},{2,1},{2,2}}; break; + case 'X': + coos = {{0,1},{1,0},{1,1},{1,2},{2,1}}; break; + case 'Y': + coos = {{0,0},{1,0},{2,0},{2,1},{3,0}}; break; + case 'Z': + coos = {{0,2},{1,0},{1,1},{1,2},{2,0}}; break; + default: + throw new InvalidPentominoException(); + } + } + + Pentomino& flip(int coo) { + for (auto& c : coos) { + c[coo] = -c[coo]; + } + normalize(); + return *this; + } + + Pentomino& translate_one(int coo) { + for (auto& c : coos) { + ++c[coo]; + } + return *this; + } + + Pentomino& translate_coo(int coo, int amount) { + for (auto& c : coos) { + c[coo] += amount; + } + return *this; + } + + Pentomino& translate_by(const CooType& by_vector) { + for (int i : {0,1}) { + translate_coo(i, by_vector[i]); + } + return *this; + } + + Pentomino& turn90() { + for (auto& c : coos) { + std::swap(c[0], c[1]); + c[1] = -c[1]; + } + normalize(); + return *this; + } + + CooType max() const { + return CooType{max_in_coo(0), max_in_coo(1)}; + } + + friend std::ostream& operator<<(std::ostream& os, + const Pentomino& P) { + os << "[" << P.name << ":{"; + bool first_coo(true); + for (const auto& c : P.coos) { + if (first_coo) first_coo = false; else os << ","; + os << "{"; + bool first(true); + for (const auto& x : c) { + if (first) first = false; else os << ","; + os << x; + } + os << "}"; + } + os << "}]"; + return os; + } + + inline + bool operator<(const Pentomino& other) const { + return coos < other.coos || name < other.name; + } + +}; + +std::array all_pentominos() +{ + return std::array{ + Pentomino{"F"}, + Pentomino{"I"}, + Pentomino{"L"}, + Pentomino{"P"}, + Pentomino{"N"}, + Pentomino{"T"}, + Pentomino{"U"}, + Pentomino{"V"}, + Pentomino{"W"}, + Pentomino{"X"}, + Pentomino{"Y"}, + Pentomino{"Z"}}; +} + +std::set rotated_pentominos_of(const Pentomino& P) { + std::set rotated_pentominos_of; + Pentomino R(P); + for (int i=0; i<4; ++i) { + rotated_pentominos_of.insert(R); + R.turn90(); + } + return rotated_pentominos_of; +} + +std::set fixed_pentominos_of(const Pentomino& P) { + std::set fixed_pentominos_of; + for (const auto& RR : rotated_pentominos_of(P)) { + Pentomino R(RR); + fixed_pentominos_of.insert(R); + R.flip(0); + fixed_pentominos_of.insert(R); + } + return fixed_pentominos_of; +} + +std::set all_fixed_pentominos() { + std::set all_fixed_pentominos; + for (const auto& P : all_pentominos()) { + for (const auto& F : fixed_pentominos_of(P)) { + all_fixed_pentominos.insert(F); + } + } + return all_fixed_pentominos; +} + +} // end namespace pentominos + +#endif // __PENTOMINOS_H__ + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: + diff --git a/dancing_links/c++/stl_wrappers.h b/dancing_links/c++/stl_wrappers.h new file mode 100644 index 0000000..581011f --- /dev/null +++ b/dancing_links/c++/stl_wrappers.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +//#ifndef __STL_WRAPPERS_H__ +//#define __STL_WRAPPERS_H__ + +#include +#include +#include +#include + + +template +inline std::ostream& +operator<<(std::ostream& wrapped, const std::array& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + + +// teach Boost.Test how to print std::vector +template +inline std::ostream& +operator<<(std::ostream& wrapped, std::vector const& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + +template +inline std::ostream& +operator<<(std::ostream& wrapped, std::pair const& item) +{ + return wrapped << '<' << item.first << ',' << item.second << '>'; +} + +template +inline std::ostream& +operator<<(std::ostream& wrapped, std::map const& item) +{ + wrapped << '{'; + bool first = true; + for (auto const& element : item) { + wrapped << (!first ? "," : "") << element; + first = false; + } + return wrapped << '}'; +} + + +//#endif // __STL_WRAPPERS_H__ + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: + diff --git a/dancing_links/c++/test_algorithm_x.cc b/dancing_links/c++/test_algorithm_x.cc new file mode 100644 index 0000000..db8a84a --- /dev/null +++ b/dancing_links/c++/test_algorithm_x.cc @@ -0,0 +1,246 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#include "dancing_links.h" +#include "stl_wrappers.h" + +using namespace pentominos; +using namespace incidence_matrix; + +struct running_example_fixture { + IncidenceMatrix I; + + running_example_fixture() + : I( { "A", "B", "C", "D", "E", "F", "G" } ) + { + I.append_row("C", {"E", "F"}); + I.append_row("A", {"D", "G"}); + I.append_row("B", {"C", "F"}); + I.append_row("A", {"D"}); + I.append_row("B", {"G"}); + I.append_row("D", {"E", "G"}); + } +}; + +BOOST_FIXTURE_TEST_CASE( algorithm_X_running, running_example_fixture ) +{ + std::vector + solutions = dancing_links::Algorithm_X(I), + expected { + {{{"A", "D"}, {"E", "F", "C"}, {"B", "G"}}} + }; + + BOOST_CHECK_EQUAL_COLLECTIONS(solutions.begin(), solutions.end(), + expected.begin(), expected.end()); +} + +struct scott_example_fixture { + static std::set holes; + IncidenceMatrix I; + + scott_example_fixture() + : I(scott_names()) {}; + + static bool allow_outside_hole(const CooType& c) { + return holes.find(c) == holes.end(); + } + + std::vector scott_names() { + std::vector scott_names { "F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z" }; + for (int i=0; i<8; ++i) + for (int j=0; j<8; ++j) + if (allow_outside_hole({i,j})) + scott_names.push_back(to_string(CooType{i,j})); + return scott_names; + } +}; + +std::set scott_example_fixture::holes { {3,3}, {3,4}, {4,3}, {4,4 } }; + +BOOST_FIXTURE_TEST_CASE( scott_type_a, scott_example_fixture ) +{ + const std::set reps { all_fixed_pentominos() }; + Pentomino P("X"); + P.translate_by({ 0, 1 }); + const IncidenceMatrix::RequiredPlacementType required_placements { {P.name, { P.coos } } }; + I.append_translates_2d(reps, + CooType { 8, 8 }, + allow_outside_hole, + required_placements); + std::vector + solutions = dancing_links::Algorithm_X(I); + BOOST_CHECK_EQUAL(solutions.size(), (size_t) 19); +} + +BOOST_FIXTURE_TEST_CASE( scott_type_b, scott_example_fixture ) +{ + const std::set reps { all_fixed_pentominos() }; + Pentomino P("X"); + P.translate_by({ 0, 2 }); + const IncidenceMatrix::RequiredPlacementType required_placements { { P.name, { P.coos } } }; + I.append_translates_2d(reps, + CooType { 8, 8 }, + allow_outside_hole, + required_placements); + std::vector + solutions = dancing_links::Algorithm_X(I); + BOOST_CHECK_EQUAL(solutions.size(), (size_t) 20); +} + + +BOOST_FIXTURE_TEST_CASE( scott_type_c, scott_example_fixture ) +{ + std::vector reps; + for (const auto& p : all_pentominos()) { + if (p.name != "P") { + for (const auto& q : fixed_pentominos_of(p)) { + reps.push_back(q); + } + } else { + for (const auto& q : rotated_pentominos_of(p)) { + reps.push_back(q); + } + } + } + Pentomino P("X"); + P.translate_by({ 1, 1 }); + const IncidenceMatrix::RequiredPlacementType required_placements { { P.name, { P.coos } } }; + I.append_translates_2d(reps, + CooType { 8, 8 }, + allow_outside_hole, + required_placements); + std::vector + solutions = dancing_links::Algorithm_X(I); + BOOST_CHECK_EQUAL(solutions.size(), (size_t) 26); +} + +BOOST_AUTO_TEST_CASE( y_pentomino_0 ) +{ + Pentomino + Y0("Y0", { {0,0},{0,1},{1,1},{0,2},{0,3} }), + Y1("Y1", { {1,0},{0,1},{1,1},{1,2},{1,3} }), + Y2("Y2", { {0,0},{0,1},{0,2},{1,2},{0,3} }), + Y3("Y3", { {1,0},{1,1},{0,2},{1,2},{1,3} }); + Y2.translate_by({ 0, 11 }); + Y3.translate_by({ 11, 11 }); + IncidenceMatrix::RequiredPlacementType required_placements { + { Y0.name, { Y0.coos } }, + { Y1.name, { Y1.coos } }, + { Y2.name, { Y2.coos } }, + { Y3.name, { Y3.coos } } + }; + const std::set tiles(fixed_pentominos_of(Y1)); + std::vector names; + for (unsigned int i=0; i I(names); + I.append_translates_2d(tiles, + CooType { 15, 15 }, + [](const CooType&) -> bool { return true; }, + required_placements); + std::vector + solutions = dancing_links::Algorithm_X(I); + BOOST_CHECK_EQUAL(solutions.size(), (size_t) 0); +} + +BOOST_AUTO_TEST_CASE( chess_square ) +{ + const std::set tiles { Pentomino("S", { {0,0}, {0,1}, {1,0}, {1,1} }) }; + const int board_size = 2; + std::vector names; + for (const auto& tile : tiles) { + names.push_back(tile.name); + } + for (int i=0; i I(names); + I.append_translates_2d(tiles, + CooType { board_size, board_size }); + BOOST_CHECK_EQUAL(I.rows, 1); + + std::vector solutions = dancing_links::Algorithm_X(I); + BOOST_CHECK_EQUAL(solutions.size(), (size_t) 1); +} + +BOOST_AUTO_TEST_CASE( chess_4_square ) +{ + std::vector tiles; + for (int i=0; i<4; ++i) { + tiles.push_back(Pentomino("S" + std::to_string(i), { {0,0}, {0,1}, {1,0}, {1,1} }) ); + } + const int board_size = 4; + std::vector names; + for (const auto& tile : tiles) { + names.push_back(tile.name); + } + for (int i=0; i I(names); + I.append_translates_2d(tiles, + CooType { board_size, board_size }); + BOOST_CHECK_EQUAL(I.rows, 36); // 4 squares * 9 positions + std::vector solutions = dancing_links::Algorithm_X(I); + BOOST_CHECK_EQUAL(solutions.size(), (size_t) 24); // 4! placements of four 2x2 squares on a 4x4 grid +} + + +BOOST_AUTO_TEST_CASE( y_pentominos_45 ) +{ + const std::set Ys(fixed_pentominos_of(Pentomino("Y"))); + std::vector tiles; + for (int i=0; i<45; ++i) { + int j(0); + for (const auto& _Y : Ys) { + Pentomino Y(_Y); + Y.name = "Y_" + std::to_string(i) + "_" + std::to_string(j++); + tiles.push_back(Y); + } + } + BOOST_CHECK_EQUAL(tiles.size(), (size_t) 360); + std::vector names; + for (const auto& tile : tiles) { + names.push_back(tile.name); + } + const int board_size = 15; + for (int i=0; i expected_names { + "Y_0_0","Y_0_1","Y_0_2","Y_0_3","Y_0_4","Y_0_5","Y_0_6","Y_0_7","Y_1_0","Y_1_1","Y_1_2","Y_1_3","Y_1_4","Y_1_5","Y_1_6","Y_1_7","Y_2_0","Y_2_1","Y_2_2","Y_2_3","Y_2_4","Y_2_5","Y_2_6","Y_2_7","Y_3_0","Y_3_1","Y_3_2","Y_3_3","Y_3_4","Y_3_5","Y_3_6","Y_3_7","Y_4_0","Y_4_1","Y_4_2","Y_4_3","Y_4_4","Y_4_5","Y_4_6","Y_4_7","Y_5_0","Y_5_1","Y_5_2","Y_5_3","Y_5_4","Y_5_5","Y_5_6","Y_5_7","Y_6_0","Y_6_1","Y_6_2","Y_6_3","Y_6_4","Y_6_5","Y_6_6","Y_6_7","Y_7_0","Y_7_1","Y_7_2","Y_7_3","Y_7_4","Y_7_5","Y_7_6","Y_7_7","Y_8_0","Y_8_1","Y_8_2","Y_8_3","Y_8_4","Y_8_5","Y_8_6","Y_8_7","Y_9_0","Y_9_1","Y_9_2","Y_9_3","Y_9_4","Y_9_5","Y_9_6","Y_9_7","Y_10_0","Y_10_1","Y_10_2","Y_10_3","Y_10_4","Y_10_5","Y_10_6","Y_10_7","Y_11_0","Y_11_1","Y_11_2","Y_11_3","Y_11_4","Y_11_5","Y_11_6","Y_11_7","Y_12_0","Y_12_1","Y_12_2","Y_12_3","Y_12_4","Y_12_5","Y_12_6","Y_12_7","Y_13_0","Y_13_1","Y_13_2","Y_13_3","Y_13_4","Y_13_5","Y_13_6","Y_13_7","Y_14_0","Y_14_1","Y_14_2","Y_14_3","Y_14_4","Y_14_5","Y_14_6","Y_14_7","Y_15_0","Y_15_1","Y_15_2","Y_15_3","Y_15_4","Y_15_5","Y_15_6","Y_15_7","Y_16_0","Y_16_1","Y_16_2","Y_16_3","Y_16_4","Y_16_5","Y_16_6","Y_16_7","Y_17_0","Y_17_1","Y_17_2","Y_17_3","Y_17_4","Y_17_5","Y_17_6","Y_17_7","Y_18_0","Y_18_1","Y_18_2","Y_18_3","Y_18_4","Y_18_5","Y_18_6","Y_18_7","Y_19_0","Y_19_1","Y_19_2","Y_19_3","Y_19_4","Y_19_5","Y_19_6","Y_19_7","Y_20_0","Y_20_1","Y_20_2","Y_20_3","Y_20_4","Y_20_5","Y_20_6","Y_20_7","Y_21_0","Y_21_1","Y_21_2","Y_21_3","Y_21_4","Y_21_5","Y_21_6","Y_21_7","Y_22_0","Y_22_1","Y_22_2","Y_22_3","Y_22_4","Y_22_5","Y_22_6","Y_22_7","Y_23_0","Y_23_1","Y_23_2","Y_23_3","Y_23_4","Y_23_5","Y_23_6","Y_23_7","Y_24_0","Y_24_1","Y_24_2","Y_24_3","Y_24_4","Y_24_5","Y_24_6","Y_24_7","Y_25_0","Y_25_1","Y_25_2","Y_25_3","Y_25_4","Y_25_5","Y_25_6","Y_25_7","Y_26_0","Y_26_1","Y_26_2","Y_26_3","Y_26_4","Y_26_5","Y_26_6","Y_26_7","Y_27_0","Y_27_1","Y_27_2","Y_27_3","Y_27_4","Y_27_5","Y_27_6","Y_27_7","Y_28_0","Y_28_1","Y_28_2","Y_28_3","Y_28_4","Y_28_5","Y_28_6","Y_28_7","Y_29_0","Y_29_1","Y_29_2","Y_29_3","Y_29_4","Y_29_5","Y_29_6","Y_29_7","Y_30_0","Y_30_1","Y_30_2","Y_30_3","Y_30_4","Y_30_5","Y_30_6","Y_30_7","Y_31_0","Y_31_1","Y_31_2","Y_31_3","Y_31_4","Y_31_5","Y_31_6","Y_31_7","Y_32_0","Y_32_1","Y_32_2","Y_32_3","Y_32_4","Y_32_5","Y_32_6","Y_32_7","Y_33_0","Y_33_1","Y_33_2","Y_33_3","Y_33_4","Y_33_5","Y_33_6","Y_33_7","Y_34_0","Y_34_1","Y_34_2","Y_34_3","Y_34_4","Y_34_5","Y_34_6","Y_34_7","Y_35_0","Y_35_1","Y_35_2","Y_35_3","Y_35_4","Y_35_5","Y_35_6","Y_35_7","Y_36_0","Y_36_1","Y_36_2","Y_36_3","Y_36_4","Y_36_5","Y_36_6","Y_36_7","Y_37_0","Y_37_1","Y_37_2","Y_37_3","Y_37_4","Y_37_5","Y_37_6","Y_37_7","Y_38_0","Y_38_1","Y_38_2","Y_38_3","Y_38_4","Y_38_5","Y_38_6","Y_38_7","Y_39_0","Y_39_1","Y_39_2","Y_39_3","Y_39_4","Y_39_5","Y_39_6","Y_39_7","Y_40_0","Y_40_1","Y_40_2","Y_40_3","Y_40_4","Y_40_5","Y_40_6","Y_40_7","Y_41_0","Y_41_1","Y_41_2","Y_41_3","Y_41_4","Y_41_5","Y_41_6","Y_41_7","Y_42_0","Y_42_1","Y_42_2","Y_42_3","Y_42_4","Y_42_5","Y_42_6","Y_42_7","Y_43_0","Y_43_1","Y_43_2","Y_43_3","Y_43_4","Y_43_5","Y_43_6","Y_43_7","Y_44_0","Y_44_1","Y_44_2","Y_44_3","Y_44_4","Y_44_5","Y_44_6","Y_44_7","<0,0>","<0,1>","<0,2>","<0,3>","<0,4>","<0,5>","<0,6>","<0,7>","<0,8>","<0,9>","<0,10>","<0,11>","<0,12>","<0,13>","<0,14>","<1,0>","<1,1>","<1,2>","<1,3>","<1,4>","<1,5>","<1,6>","<1,7>","<1,8>","<1,9>","<1,10>","<1,11>","<1,12>","<1,13>","<1,14>","<2,0>","<2,1>","<2,2>","<2,3>","<2,4>","<2,5>","<2,6>","<2,7>","<2,8>","<2,9>","<2,10>","<2,11>","<2,12>","<2,13>","<2,14>","<3,0>","<3,1>","<3,2>","<3,3>","<3,4>","<3,5>","<3,6>","<3,7>","<3,8>","<3,9>","<3,10>","<3,11>","<3,12>","<3,13>","<3,14>","<4,0>","<4,1>","<4,2>","<4,3>","<4,4>","<4,5>","<4,6>","<4,7>","<4,8>","<4,9>","<4,10>","<4,11>","<4,12>","<4,13>","<4,14>","<5,0>","<5,1>","<5,2>","<5,3>","<5,4>","<5,5>","<5,6>","<5,7>","<5,8>","<5,9>","<5,10>","<5,11>","<5,12>","<5,13>","<5,14>","<6,0>","<6,1>","<6,2>","<6,3>","<6,4>","<6,5>","<6,6>","<6,7>","<6,8>","<6,9>","<6,10>","<6,11>","<6,12>","<6,13>","<6,14>","<7,0>","<7,1>","<7,2>","<7,3>","<7,4>","<7,5>","<7,6>","<7,7>","<7,8>","<7,9>","<7,10>","<7,11>","<7,12>","<7,13>","<7,14>","<8,0>","<8,1>","<8,2>","<8,3>","<8,4>","<8,5>","<8,6>","<8,7>","<8,8>","<8,9>","<8,10>","<8,11>","<8,12>","<8,13>","<8,14>","<9,0>","<9,1>","<9,2>","<9,3>","<9,4>","<9,5>","<9,6>","<9,7>","<9,8>","<9,9>","<9,10>","<9,11>","<9,12>","<9,13>","<9,14>","<10,0>","<10,1>","<10,2>","<10,3>","<10,4>","<10,5>","<10,6>","<10,7>","<10,8>","<10,9>","<10,10>","<10,11>","<10,12>","<10,13>","<10,14>","<11,0>","<11,1>","<11,2>","<11,3>","<11,4>","<11,5>","<11,6>","<11,7>","<11,8>","<11,9>","<11,10>","<11,11>","<11,12>","<11,13>","<11,14>","<12,0>","<12,1>","<12,2>","<12,3>","<12,4>","<12,5>","<12,6>","<12,7>","<12,8>","<12,9>","<12,10>","<12,11>","<12,12>","<12,13>","<12,14>","<13,0>","<13,1>","<13,2>","<13,3>","<13,4>","<13,5>","<13,6>","<13,7>","<13,8>","<13,9>","<13,10>","<13,11>","<13,12>","<13,13>","<13,14>","<14,0>","<14,1>","<14,2>","<14,3>","<14,4>","<14,5>","<14,6>","<14,7>","<14,8>","<14,9>","<14,10>","<14,11>","<14,12>","<14,13>","<14,14>" + }; + BOOST_CHECK_EQUAL_COLLECTIONS(names.begin(), names.end(), + expected_names.begin(), expected_names.end()); + + IncidenceMatrix I(names); + I.append_translates_2d(tiles, + CooType { board_size, board_size }); + BOOST_CHECK_EQUAL(I.rows, 60480); + // std::vector solutions = dancing_links::Algorithm_X(I); + // BOOST_CHECK_EQUAL(solutions.size(), (size_t) 212); +} + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/dancing_links/c++/test_dancing_links.cc b/dancing_links/c++/test_dancing_links.cc new file mode 100644 index 0000000..f370995 --- /dev/null +++ b/dancing_links/c++/test_dancing_links.cc @@ -0,0 +1,42 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#define BOOST_TEST_MODULE dancing_links +#include +#include +#include +#include "pentominos.h" +#include "boost_cout_wrappers.h" + + +BOOST_AUTO_TEST_SUITE( pentominos ) + +#include "test_pentominos.cc" + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE( incidence_matrix ) + +#include "test_incidence_matrix.cc" + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE( dancing_links ) + +#include "test_algorithm_x.cc" + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/dancing_links/c++/test_incidence_matrix.cc b/dancing_links/c++/test_incidence_matrix.cc new file mode 100644 index 0000000..1913ee0 --- /dev/null +++ b/dancing_links/c++/test_incidence_matrix.cc @@ -0,0 +1,427 @@ +/* Copyright (c) 2015 + Julian Pfeifle + julian.pfeifle@upc.edu + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3, or (at your option) any + later version: http://www.gnu.org/licenses/gpl.txt. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------------- +*/ + +#include "incidence_matrix.h" + +using namespace pentominos; +using namespace incidence_matrix; + +struct scott_example_fixture { + static std::set holes; + IncidenceMatrix I; + + scott_example_fixture() + : I(scott_names()) {}; + + static bool allow_outside_hole(const CooType& c) { + return holes.find(c) == holes.end(); + } + + std::vector scott_names() { + std::vector scott_names { "F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z" }; + for (int i=0; i<8; ++i) + for (int j=0; j<8; ++j) + if (allow_outside_hole({i,j})) + scott_names.push_back(to_string(CooType{i,j})); + return scott_names; + } +}; + +std::set scott_example_fixture::holes { {3,3}, {3,4}, {4,3}, {4,4 } }; + +BOOST_AUTO_TEST_CASE( constructor_test ) +{ + IncidenceMatrix I ({"0", "1", "2"}); + const std::vector rep { I.representation() }, + expected { + // h(size), name, left, right, up, down + { {"r(0)", "root", "2", "0", "root", "root"} }, + { {"h(0)", "0", "root", "1", "0", "0"} }, + { {"h(0)", "1", "0", "2", "1", "1"} }, + { {"h(0)", "2", "1", "root", "2", "2"} } + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( append_one_row, scott_example_fixture ) +{ + I.append_row("I", { {0,0}, {0,1}, {0,2}, {0,3}, {0,4} } ); + std::vector rep; + for (const auto& i : { "I", "<0,0>", "<0,1>", "<0,2>", "<0,3>", "<0,4>" }) { + rep.push_back(I.column_object_of_name[i]->representation()); + } + std::vector expected { + {{"h(1)", "I", "F", "L", "I{0}", "I{0}"}, {"c", "I{0}", "I<0,4>", "I<0,0>", "I", "I" }}, + {{"h(1)", "<0,0>", "Z", "<0,1>", "I<0,0>", "I<0,0>"}, {"c", "I<0,0>", "I{0}", "I<0,1>", "<0,0>", "<0,0>" }}, + {{"h(1)", "<0,1>", "<0,0>", "<0,2>", "I<0,1>", "I<0,1>"}, {"c", "I<0,1>", "I<0,0>", "I<0,2>", "<0,1>", "<0,1>" }}, + {{"h(1)", "<0,2>", "<0,1>", "<0,3>", "I<0,2>", "I<0,2>"}, {"c", "I<0,2>", "I<0,1>", "I<0,3>", "<0,2>", "<0,2>" }}, + {{"h(1)", "<0,3>", "<0,2>", "<0,4>", "I<0,3>", "I<0,3>"}, {"c", "I<0,3>", "I<0,2>", "I<0,4>", "<0,3>", "<0,3>" }}, + {{"h(1)", "<0,4>", "<0,3>", "<0,5>", "I<0,4>", "I<0,4>"}, {"c", "I<0,4>", "I<0,3>", "I{0}", "<0,4>", "<0,4>" }} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( append_two_rows, scott_example_fixture ) +{ + I.append_row("I", { {0,0}, {0,1}, {0,2}, {0,3}, {0,4} } ); + I.append_row("I", { {0,1}, {0,2}, {0,3}, {0,4}, {0,5} } ); + std::vector rep; + for (const auto& i : { "I", "<0,0>", "<0,1>", "<0,2>", "<0,3>", "<0,4>" }) { + rep.push_back(I.column_object_of_name[i]->representation()); + } + std::vector expected { + {{"h(2)", "I", "F", "L", "I{1}", "I{0}"}, {"c", "I{0}", "I<0,4>", "I<0,0>", "I", "I{1}"}, {"c", "I{1}", "I<0,5>", "I<0,1>", "I{0}", "I"}}, + {{"h(1)", "<0,0>", "Z", "<0,1>", "I<0,0>", "I<0,0>"}, {"c", "I<0,0>", "I{0}", "I<0,1>", "<0,0>", "<0,0>" }}, + {{"h(2)", "<0,1>", "<0,0>", "<0,2>", "I<0,1>", "I<0,1>"}, {"c", "I<0,1>", "I<0,0>", "I<0,2>", "<0,1>", "I<0,1>" }, {"c", "I<0,1>", "I{1}", "I<0,2>", "I<0,1>", "<0,1>"}}, + {{"h(2)", "<0,2>", "<0,1>", "<0,3>", "I<0,2>", "I<0,2>"}, {"c", "I<0,2>", "I<0,1>", "I<0,3>", "<0,2>", "I<0,2>" }, {"c", "I<0,2>", "I<0,1>", "I<0,3>", "I<0,2>", "<0,2>" }}, + {{"h(2)", "<0,3>", "<0,2>", "<0,4>", "I<0,3>", "I<0,3>"}, {"c", "I<0,3>", "I<0,2>", "I<0,4>", "<0,3>", "I<0,3>" }, {"c", "I<0,3>", "I<0,2>", "I<0,4>", "I<0,3>", "<0,3>" }}, + {{"h(2)", "<0,4>", "<0,3>", "<0,5>", "I<0,4>", "I<0,4>"}, {"c", "I<0,4>", "I<0,3>", "I{0}", "<0,4>", "I<0,4>" }, {"c", "I<0,4>", "I<0,3>", "I<0,5>", "I<0,4>", "<0,4>" }} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( append_allow_none, scott_example_fixture ) +{ + I.append_translates_2d(std::array { Pentomino("I") }, + CooType { 6, 3 }, + [](const CooType&)->bool { return false; }); + BOOST_CHECK_EQUAL(I.rows, 0); +} + +BOOST_FIXTURE_TEST_CASE( append_translates, scott_example_fixture ) +{ + Pentomino P("I"); + I.append_translates_2d(std::array { Pentomino("I") }, + CooType { 3, 6 }); + std::vector rep; + for (const auto& i : { "I", "<0,0>", "<0,1>", "<0,2>", "<0,3>", "<0,4>", "<0,5>", "<1,0>", "<1,1>", "<1,2>", "<1,3>", "<1,4>", "<1,5>", "<2,0>", "<2,1>", "<2,2>", "<2,3>", "<2,4>", "<2,5>" }) { + rep.push_back(I.column_object_of_name[i]->representation()); + } + + std::vector expected { + {{"h(6)", "I", "F", "L", "I{5}", "I{0}"}, {"c", "I{0}", "I<0,4>", "I<0,0>", "I", "I{1}"}, {"c", "I{1}", "I<0,5>", "I<0,1>", "I{0}", "I{2}"}, {"c", "I{2}", "I<1,4>", "I<1,0>", "I{1}", "I{3}"}, {"c", "I{3}", "I<1,5>", "I<1,1>", "I{2}", "I{4}"}, {"c", "I{4}", "I<2,4>", "I<2,0>", "I{3}", "I{5}"}, {"c", "I{5}", "I<2,5>", "I<2,1>", "I{4}", "I"}}, + {{"h(1)", "<0,0>", "Z", "<0,1>", "I<0,0>", "I<0,0>"}, {"c", "I<0,0>", "I{0}", "I<0,1>", "<0,0>", "<0,0>"}}, + {{"h(2)", "<0,1>", "<0,0>", "<0,2>", "I<0,1>", "I<0,1>"}, {"c", "I<0,1>", "I<0,0>", "I<0,2>", "<0,1>", "I<0,1>"}, {"c", "I<0,1>", "I{1}", "I<0,2>", "I<0,1>", "<0,1>"}}, + {{"h(2)", "<0,2>", "<0,1>", "<0,3>", "I<0,2>", "I<0,2>"}, {"c", "I<0,2>", "I<0,1>", "I<0,3>", "<0,2>", "I<0,2>"}, {"c", "I<0,2>", "I<0,1>", "I<0,3>", "I<0,2>", "<0,2>"}}, + {{"h(2)", "<0,3>", "<0,2>", "<0,4>", "I<0,3>", "I<0,3>"}, {"c", "I<0,3>", "I<0,2>", "I<0,4>", "<0,3>", "I<0,3>"}, {"c", "I<0,3>", "I<0,2>", "I<0,4>", "I<0,3>", "<0,3>"}}, + {{"h(2)", "<0,4>", "<0,3>", "<0,5>", "I<0,4>", "I<0,4>"}, {"c", "I<0,4>", "I<0,3>", "I{0}", "<0,4>", "I<0,4>"}, {"c", "I<0,4>", "I<0,3>", "I<0,5>", "I<0,4>", "<0,4>"}}, + {{"h(1)", "<0,5>", "<0,4>", "<0,6>", "I<0,5>", "I<0,5>"}, {"c", "I<0,5>", "I<0,4>", "I{1}", "<0,5>", "<0,5>"}}, + {{"h(1)", "<1,0>", "<0,7>", "<1,1>", "I<1,0>", "I<1,0>"}, {"c", "I<1,0>", "I{2}", "I<1,1>", "<1,0>", "<1,0>"}}, + {{"h(2)", "<1,1>", "<1,0>", "<1,2>", "I<1,1>", "I<1,1>"}, {"c", "I<1,1>", "I<1,0>", "I<1,2>", "<1,1>", "I<1,1>"}, {"c", "I<1,1>", "I{3}", "I<1,2>", "I<1,1>", "<1,1>"}}, + {{"h(2)", "<1,2>", "<1,1>", "<1,3>", "I<1,2>", "I<1,2>"}, {"c", "I<1,2>", "I<1,1>", "I<1,3>", "<1,2>", "I<1,2>"}, {"c", "I<1,2>", "I<1,1>", "I<1,3>", "I<1,2>", "<1,2>"}}, + {{"h(2)", "<1,3>", "<1,2>", "<1,4>", "I<1,3>", "I<1,3>"}, {"c", "I<1,3>", "I<1,2>", "I<1,4>", "<1,3>", "I<1,3>"}, {"c", "I<1,3>", "I<1,2>", "I<1,4>", "I<1,3>", "<1,3>"}}, + {{"h(2)", "<1,4>", "<1,3>", "<1,5>", "I<1,4>", "I<1,4>"}, {"c", "I<1,4>", "I<1,3>", "I{2}", "<1,4>", "I<1,4>"}, {"c", "I<1,4>", "I<1,3>", "I<1,5>", "I<1,4>", "<1,4>"}}, + {{"h(1)", "<1,5>", "<1,4>", "<1,6>", "I<1,5>", "I<1,5>"}, {"c", "I<1,5>", "I<1,4>", "I{3}", "<1,5>", "<1,5>"}}, + {{"h(1)", "<2,0>", "<1,7>", "<2,1>", "I<2,0>", "I<2,0>"}, {"c", "I<2,0>", "I{4}", "I<2,1>", "<2,0>", "<2,0>"}}, + {{"h(2)", "<2,1>", "<2,0>", "<2,2>", "I<2,1>", "I<2,1>"}, {"c", "I<2,1>", "I<2,0>", "I<2,2>", "<2,1>", "I<2,1>"}, {"c", "I<2,1>", "I{5}", "I<2,2>", "I<2,1>", "<2,1>"}}, + {{"h(2)", "<2,2>", "<2,1>", "<2,3>", "I<2,2>", "I<2,2>"}, {"c", "I<2,2>", "I<2,1>", "I<2,3>", "<2,2>", "I<2,2>"}, {"c", "I<2,2>", "I<2,1>", "I<2,3>", "I<2,2>", "<2,2>"}}, + {{"h(2)", "<2,3>", "<2,2>", "<2,4>", "I<2,3>", "I<2,3>"}, {"c", "I<2,3>", "I<2,2>", "I<2,4>", "<2,3>", "I<2,3>"}, {"c", "I<2,3>", "I<2,2>", "I<2,4>", "I<2,3>", "<2,3>"}}, + {{"h(2)", "<2,4>", "<2,3>", "<2,5>", "I<2,4>", "I<2,4>"}, {"c", "I<2,4>", "I<2,3>", "I{4}", "<2,4>", "I<2,4>"}, {"c", "I<2,4>", "I<2,3>", "I<2,5>", "I<2,4>", "<2,4>"}}, + {{"h(1)", "<2,5>", "<2,4>", "<2,6>", "I<2,5>", "I<2,5>"}, {"c", "I<2,5>", "I<2,4>", "I{5}", "<2,5>", "<2,5>"}} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( append_one_with_hole, scott_example_fixture ) +{ + Pentomino P("I"); + P.translate_coo(1,3); + I.append_translates_2d(std::array { Pentomino("I") }, + CooType { 6, 4 }, + allow_outside_hole); + BOOST_CHECK_EQUAL(I.rows, 0); +} + +BOOST_FIXTURE_TEST_CASE( append_with_hole, scott_example_fixture ) +{ + const std::set reps { all_fixed_pentominos() }; + I.append_translates_2d(reps, + CooType { 8, 8 }, + allow_outside_hole); + BOOST_CHECK_EQUAL(I.rows, 1568); +} + +BOOST_FIXTURE_TEST_CASE( query_required_placements_1, scott_example_fixture ) +{ + Pentomino P("I"); + P.translate_coo(0,3); + const IncidenceMatrix::RequiredPlacementType required_placements { { P.name, { P.coos } } }; + std::vector allowed; + for (const auto& coo : P.coos) { + allowed.push_back(allow_outside_hole(coo)); + } + const std::vector expected { true, true, true, false, false }; + BOOST_CHECK_EQUAL_COLLECTIONS(allowed.begin(), allowed.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( query_required_placements_2, scott_example_fixture ) +{ + Pentomino P("I"); + P.translate_coo(0,3); + const IncidenceMatrix::RequiredPlacementType required_placements { { P.name, { P.coos } } }; + BOOST_CHECK_EQUAL(I.is_legal(P.coos, allow_outside_hole, { 5, 5 }), false); +} + +BOOST_FIXTURE_TEST_CASE( required_placements, scott_example_fixture ) +{ + Pentomino P("I"); + P.translate_coo(0,3); + const IncidenceMatrix::RequiredPlacementType required_placements { {P.name, { P.coos } } }; + BOOST_CHECK_THROW(I.append_translates_2d(std::array { P }, + CooType { 8, 8 }, + allow_outside_hole, + required_placements), + ForbiddenPlacementException); +} + +BOOST_FIXTURE_TEST_CASE( append_translates_with_hole, scott_example_fixture ) +{ + Pentomino P("I"); + I.append_translates_2d(std::array { P }, + CooType { 3, 6 }); + std::vector rep; + for (const auto& i : { "I", "<0,0>", "<0,1>", "<0,2>", "<0,3>", "<0,4>", "<0,5>", "<1,0>", "<1,1>", "<1,2>", "<1,3>", "<1,4>", "<1,5>", "<2,0>", "<2,1>", "<2,2>", "<2,3>", "<2,4>", "<2,5>" }) { + rep.push_back(I.column_object_of_name[i]->representation()); + } + std::vector expected { + {{"h(6)", "I", "F", "L", "I{5}", "I{0}"}, {"c", "I{0}", "I<0,4>", "I<0,0>", "I", "I{1}"}, {"c", "I{1}", "I<0,5>", "I<0,1>", "I{0}", "I{2}"}, {"c", "I{2}", "I<1,4>", "I<1,0>", "I{1}", "I{3}"}, {"c", "I{3}", "I<1,5>", "I<1,1>", "I{2}", "I{4}"}, {"c", "I{4}", "I<2,4>", "I<2,0>", "I{3}", "I{5}"}, {"c", "I{5}", "I<2,5>", "I<2,1>", "I{4}", "I"}}, + {{"h(1)", "<0,0>", "Z", "<0,1>", "I<0,0>", "I<0,0>"}, {"c", "I<0,0>", "I{0}", "I<0,1>", "<0,0>", "<0,0>"}}, + {{"h(2)", "<0,1>", "<0,0>", "<0,2>", "I<0,1>", "I<0,1>"}, {"c", "I<0,1>", "I<0,0>", "I<0,2>", "<0,1>", "I<0,1>"}, {"c", "I<0,1>", "I{1}", "I<0,2>", "I<0,1>", "<0,1>"}}, + {{"h(2)", "<0,2>", "<0,1>", "<0,3>", "I<0,2>", "I<0,2>"}, {"c", "I<0,2>", "I<0,1>", "I<0,3>", "<0,2>", "I<0,2>"}, {"c", "I<0,2>", "I<0,1>", "I<0,3>", "I<0,2>", "<0,2>"}}, + {{"h(2)", "<0,3>", "<0,2>", "<0,4>", "I<0,3>", "I<0,3>"}, {"c", "I<0,3>", "I<0,2>", "I<0,4>", "<0,3>", "I<0,3>"}, {"c", "I<0,3>", "I<0,2>", "I<0,4>", "I<0,3>", "<0,3>"}}, + {{"h(2)", "<0,4>", "<0,3>", "<0,5>", "I<0,4>", "I<0,4>"}, {"c", "I<0,4>", "I<0,3>", "I{0}", "<0,4>", "I<0,4>"}, {"c", "I<0,4>", "I<0,3>", "I<0,5>", "I<0,4>", "<0,4>"}}, + {{"h(1)", "<0,5>", "<0,4>", "<0,6>", "I<0,5>", "I<0,5>"}, {"c", "I<0,5>", "I<0,4>", "I{1}", "<0,5>", "<0,5>"}}, + {{"h(1)", "<1,0>", "<0,7>", "<1,1>", "I<1,0>", "I<1,0>"}, {"c", "I<1,0>", "I{2}", "I<1,1>", "<1,0>", "<1,0>"}}, + {{"h(2)", "<1,1>", "<1,0>", "<1,2>", "I<1,1>", "I<1,1>"}, {"c", "I<1,1>", "I<1,0>", "I<1,2>", "<1,1>", "I<1,1>"}, {"c", "I<1,1>", "I{3}", "I<1,2>", "I<1,1>", "<1,1>"}}, + {{"h(2)", "<1,2>", "<1,1>", "<1,3>", "I<1,2>", "I<1,2>"}, {"c", "I<1,2>", "I<1,1>", "I<1,3>", "<1,2>", "I<1,2>"}, {"c", "I<1,2>", "I<1,1>", "I<1,3>", "I<1,2>", "<1,2>"}}, + {{"h(2)", "<1,3>", "<1,2>", "<1,4>", "I<1,3>", "I<1,3>"}, {"c", "I<1,3>", "I<1,2>", "I<1,4>", "<1,3>", "I<1,3>"}, {"c", "I<1,3>", "I<1,2>", "I<1,4>", "I<1,3>", "<1,3>"}}, + {{"h(2)", "<1,4>", "<1,3>", "<1,5>", "I<1,4>", "I<1,4>"}, {"c", "I<1,4>", "I<1,3>", "I{2}", "<1,4>", "I<1,4>"}, {"c", "I<1,4>", "I<1,3>", "I<1,5>", "I<1,4>", "<1,4>"}}, + {{"h(1)", "<1,5>", "<1,4>", "<1,6>", "I<1,5>", "I<1,5>"}, {"c", "I<1,5>", "I<1,4>", "I{3}", "<1,5>", "<1,5>"}}, + {{"h(1)", "<2,0>", "<1,7>", "<2,1>", "I<2,0>", "I<2,0>"}, {"c", "I<2,0>", "I{4}", "I<2,1>", "<2,0>", "<2,0>"}}, + {{"h(2)", "<2,1>", "<2,0>", "<2,2>", "I<2,1>", "I<2,1>"}, {"c", "I<2,1>", "I<2,0>", "I<2,2>", "<2,1>", "I<2,1>"}, {"c", "I<2,1>", "I{5}", "I<2,2>", "I<2,1>", "<2,1>"}}, + {{"h(2)", "<2,2>", "<2,1>", "<2,3>", "I<2,2>", "I<2,2>"}, {"c", "I<2,2>", "I<2,1>", "I<2,3>", "<2,2>", "I<2,2>"}, {"c", "I<2,2>", "I<2,1>", "I<2,3>", "I<2,2>", "<2,2>"}}, + {{"h(2)", "<2,3>", "<2,2>", "<2,4>", "I<2,3>", "I<2,3>"}, {"c", "I<2,3>", "I<2,2>", "I<2,4>", "<2,3>", "I<2,3>"}, {"c", "I<2,3>", "I<2,2>", "I<2,4>", "I<2,3>", "<2,3>"}}, + {{"h(2)", "<2,4>", "<2,3>", "<2,5>", "I<2,4>", "I<2,4>"}, {"c", "I<2,4>", "I<2,3>", "I{4}", "<2,4>", "I<2,4>"}, {"c", "I<2,4>", "I<2,3>", "I<2,5>", "I<2,4>", "<2,4>"}}, + {{"h(1)", "<2,5>", "<2,4>", "<2,6>", "I<2,5>", "I<2,5>"}, {"c", "I<2,5>", "I<2,4>", "I{5}", "<2,5>", "<2,5>"}} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( restricted_scott_construction, scott_example_fixture ) +{ + const std::set reps { all_fixed_pentominos() }; + Pentomino P("X"); + P.translate_by({ 0, 1 }); + const IncidenceMatrix::RequiredPlacementType required_placements { { P.name, { P.coos } } }; + I.append_translates_2d(reps, + CooType { 8, 8 }, + allow_outside_hole, + required_placements); + BOOST_CHECK_EQUAL(I.rows, 1545); +} + +struct running_example_fixture { + IncidenceMatrix I; + + running_example_fixture() + : I( { "A", "B", "C", "D", "E", "F", "G" } ) + { + I.append_row("C", {"E", "F"}); + I.append_row("A", {"D", "G"}); + I.append_row("B", {"C", "F"}); + I.append_row("A", {"D"}); + I.append_row("B", {"G"}); + I.append_row("D", {"E", "G"}); + } +}; + +BOOST_FIXTURE_TEST_CASE( construct_running_example, running_example_fixture ) +{ + const std::vector + rep { I.representation() }, + expected { + {{"r(0)", "root", "G", "A", "root", "root"}}, + {{"h(2)", "A", "root", "B", "A{1}", "A{0}"}, {"c", "A{0}", "AG", "AD", "A", "A{1}"}, {"c", "A{1}", "AD", "AD", "A{0}", "A"}}, + {{"h(2)", "B", "A", "C", "B{1}", "B{0}"}, {"c", "B{0}", "BF", "BC", "B", "B{1}"}, {"c", "B{1}", "BG", "BG", "B{0}", "B"}}, + {{"h(2)", "C", "B", "D", "BC", "C{0}"}, {"c", "C{0}", "CF", "CE", "C", "BC"}, {"c", "BC", "B{0}", "BF", "C{0}", "C"}}, + {{"h(3)", "D", "C", "E", "D{0}", "AD"}, {"c", "AD", "A{0}", "AG", "D", "AD"}, {"c", "AD", "A{1}", "A{1}", "AD", "D{0}"}, {"c", "D{0}", "DG", "DE", "AD", "D"}}, + {{"h(2)", "E", "D", "F", "DE", "CE"}, {"c", "CE", "C{0}", "CF", "E", "DE"}, {"c", "DE", "D{0}", "DG", "CE", "E"}}, + {{"h(2)", "F", "E", "G", "BF", "CF"}, {"c", "CF", "CE", "C{0}", "F", "BF"}, {"c", "BF", "BC", "B{0}", "CF", "F"}}, + {{"h(3)", "G", "F", "root", "DG", "AG"}, {"c", "AG", "AD", "A{0}", "G", "BG"}, {"c", "BG", "B{1}", "B{1}", "AG", "DG"}, {"c", "DG", "DE", "D{0}", "BG", "G"}} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( cover_running_example, running_example_fixture ) +{ + I.cover_column(I.column_object_of_name["A"]); + const std::vector + rep { I.representation() }, + expected { + {{"r(0)", "root", "G", "B", "root", "root"}}, + {{"h(2)", "B", "root", "C", "B{1}", "B{0}"},{"c", "B{0}", "BF", "BC", "B", "B{1}"},{"c", "B{1}", "BG", "BG", "B{0}", "B"}}, + {{"h(2)", "C", "B", "D", "BC", "C{0}"}, {"c", "C{0}", "CF", "CE", "C", "BC"}, {"c", "BC", "B{0}", "BF", "C{0}", "C"}}, + {{"h(1)", "D", "C", "E", "D{0}", "D{0}"}, {"c", "D{0}", "DG", "DE", "D", "D"}}, + {{"h(2)", "E", "D", "F", "DE", "CE"}, {"c", "CE", "C{0}", "CF", "E", "DE"}, {"c", "DE", "D{0}", "DG", "CE", "E"}}, + {{"h(2)", "F", "E", "G", "BF", "CF"}, {"c", "CF", "CE", "C{0}", "F", "BF"}, {"c", "BF", "BC", "B{0}", "CF", "F"}}, + {{"h(2)", "G", "F", "root", "DG", "BG"}, {"c", "BG", "B{1}", "B{1}", "G", "DG"}, {"c", "DG", "DE", "D{0}", "BG", "G"}} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( cover_and_uncover_running_example, running_example_fixture ) +{ + const auto expected = I.representation(); + I.cover_column(I.column_object_of_name["A"]); + I.uncover_column(I.column_object_of_name["A"]); + const auto rep = I.representation(); + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( cover_3_running_example, running_example_fixture ) +{ + for (const auto& n : { "A", "D", "G" }) { + I.cover_column(I.column_object_of_name[n]); + } + const std::vector + rep { I.representation() }, + expected { + {{"r(0)", "root", "F", "B", "root", "root"}}, + {{"h(1)", "B", "root", "C", "B{0}", "B{0}"}, {"c", "B{0}", "BF", "BC", "B", "B"}}, + {{"h(2)", "C", "B", "E", "BC", "C{0}"}, {"c", "C{0}", "CF", "CE", "C", "BC"}, {"c", "BC", "B{0}", "BF", "C{0}", "C"}}, + {{"h(1)", "E", "C", "F", "CE", "CE"}, {"c", "CE", "C{0}", "CF", "E", "E"}}, + {{"h(2)", "F", "E", "root", "BF", "CF"}, {"c", "CF", "CE", "C{0}", "F", "BF"}, {"c", "BF", "BC", "B{0}", "CF", "F"}} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE( chess_square ) +{ + const std::set tiles { Pentomino("S", { {0,0}, {0,1}, {1,0}, {1,1} }) }; + const int board_size = 2; + std::vector names; + for (const auto& tile : tiles) { + names.push_back(tile.name); + } + for (int i=0; i I(names); + I.append_translates_2d(tiles, + CooType { board_size, board_size }); + BOOST_CHECK_EQUAL(I.rows, 1); + + const std::vector + rep { I.representation() }, + expected { + {{"r(0)", "root", "<1,1>", "S", "root", "root"}}, + {{"h(1)", "S", "root", "<0,0>", "S{0}", "S{0}"}, {"c", "S{0}", "S<1,1>", "S<0,0>", "S", "S"}}, + {{"h(1)", "<0,0>", "S", "<0,1>", "S<0,0>", "S<0,0>"}, {"c", "S<0,0>", "S{0}", "S<0,1>", "<0,0>", "<0,0>"}}, + {{"h(1)", "<0,1>", "<0,0>", "<1,0>", "S<0,1>", "S<0,1>"}, {"c", "S<0,1>", "S<0,0>", "S<1,0>", "<0,1>", "<0,1>"}}, + {{"h(1)", "<1,0>", "<0,1>", "<1,1>", "S<1,0>", "S<1,0>"}, {"c", "S<1,0>", "S<0,1>", "S<1,1>", "<1,0>", "<1,0>"}}, + {{"h(1)", "<1,1>", "<1,0>", "root", "S<1,1>", "S<1,1>"}, {"c", "S<1,1>", "S<1,0>", "S{0}", "<1,1>", "<1,1>"}} + }; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE( chess_square_row_rep ) +{ + const std::set tiles { Pentomino("S", { {0,0}, {0,1}, {1,0}, {1,1} }) }; + const int board_size = 2; + std::vector names; + for (const auto& tile : tiles) { + names.push_back(tile.name); + } + for (int i=0; i I(names); + I.append_translates_2d(tiles, + CooType { board_size, board_size }); + BOOST_CHECK_EQUAL(I.rows, 1); + + const std::vector + rep { I.row_representation() }, + expected {{"S{0}","<0,0>","<0,1>","<1,0>","<1,1>"}}; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE( chess_square_2_row_rep ) +{ + const std::set tiles { Pentomino("S", { {0,0}, {0,1}, {1,0}, {1,1} }) }; + const int board_size = 4; + std::vector names; + for (const auto& tile : tiles) { + names.push_back(tile.name); + } + for (int i=0; i I(names); + I.append_translates_2d(tiles, + CooType { board_size, board_size }); + BOOST_CHECK_EQUAL(I.rows, 9); + const std::vector + rep { I.row_representation() }, + expected {{{"S{0}", "<0,0>", "<0,1>", "<1,0>", "<1,1>"}, {"S{1}", "<0,1>", "<0,2>", "<1,1>", "<1,2>"}, {"S{2}", "<0,2>", "<0,3>", "<1,2>", "<1,3>"}, {"S{3}", "<1,0>", "<1,1>", "<2,0>", "<2,1>"}, {"S{4}", "<1,1>", "<1,2>", "<2,1>", "<2,2>"}, {"S{5}", "<1,2>", "<1,3>", "<2,2>", "<2,3>"}, {"S{6}", "<2,0>", "<2,1>", "<3,0>", "<3,1>"}, {"S{7}", "<2,1>", "<2,2>", "<3,1>", "<3,2>"}, {"S{8}", "<2,2>", "<2,3>", "<3,2>", "<3,3>"}}}; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE( chess_4_square_with_dummy_copy ) +{ + const std::set tiles { + Pentomino("Sa", { {0,0}, {0,1}, {1,0}, {1,1} }), + Pentomino("Sb", { {0,0}, {0,1}, {1,0}, {1,1} }) }; + const int board_size = 4; + std::vector names; + for (const auto& tile : tiles) { + names.push_back(tile.name); + } + for (int i=0; i I(names); + I.append_translates_2d(tiles, + CooType { board_size, board_size }); + BOOST_CHECK_EQUAL(I.rows, 18); + const std::vector + rep { I.row_representation() }, + expected {{"Sa{0}", "<0,0>", "<0,1>", "<1,0>", "<1,1>"}, {"Sa{1}", "<0,1>", "<0,2>", "<1,1>", "<1,2>"}, {"Sa{2}", "<0,2>", "<0,3>", "<1,2>", "<1,3>"}, {"Sa{3}", "<1,0>", "<1,1>", "<2,0>", "<2,1>"}, {"Sa{4}", "<1,1>", "<1,2>", "<2,1>", "<2,2>"}, {"Sa{5}", "<1,2>", "<1,3>", "<2,2>", "<2,3>"}, {"Sa{6}", "<2,0>", "<2,1>", "<3,0>", "<3,1>"}, {"Sa{7}", "<2,1>", "<2,2>", "<3,1>", "<3,2>"}, {"Sa{8}", "<2,2>", "<2,3>", "<3,2>", "<3,3>"}, {"Sb{0}", "<0,0>", "<0,1>", "<1,0>", "<1,1>"}, {"Sb{1}", "<0,1>", "<0,2>", "<1,1>", "<1,2>"}, {"Sb{2}", "<0,2>", "<0,3>", "<1,2>", "<1,3>"}, {"Sb{3}", "<1,0>", "<1,1>", "<2,0>", "<2,1>"}, {"Sb{4}", "<1,1>", "<1,2>", "<2,1>", "<2,2>"}, {"Sb{5}", "<1,2>", "<1,3>", "<2,2>", "<2,3>"}, {"Sb{6}", "<2,0>", "<2,1>", "<3,0>", "<3,1>"}, {"Sb{7}", "<2,1>", "<2,2>", "<3,1>", "<3,2>"}, {"Sb{8}", "<2,2>", "<2,3>", "<3,2>", "<3,3>"}}; + BOOST_CHECK_EQUAL_COLLECTIONS(rep.begin(), rep.end(), + expected.begin(), expected.end()); +} + + + + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/dancing_links/c++/test_pentominos.cc b/dancing_links/c++/test_pentominos.cc new file mode 100644 index 0000000..7d3e0b0 --- /dev/null +++ b/dancing_links/c++/test_pentominos.cc @@ -0,0 +1,128 @@ +struct pentomino_fixture { + pentomino_fixture() : I("I") {} + pentominos::Pentomino I; +}; + +BOOST_FIXTURE_TEST_CASE( constructor_test, pentomino_fixture ) +{ + BOOST_CHECK_EQUAL(I.coos.size(), (size_t)5); +} + +BOOST_FIXTURE_TEST_CASE( coordinate_test, pentomino_fixture ) +{ + const std::vector expected_I_coos{{0,0},{0,1},{0,2},{0,3},{0,4}}; + BOOST_CHECK_EQUAL_COLLECTIONS(I.coos.begin(), I.coos.end(), + expected_I_coos.begin(), expected_I_coos.end()); +} + +BOOST_FIXTURE_TEST_CASE( representation_test, pentomino_fixture ) +{ + std::ostringstream oss; + oss << I; + std::string I_expected{"[I:{{0,0},{0,1},{0,2},{0,3},{0,4}}]"}; + BOOST_CHECK_EQUAL(oss.str(), I_expected); +} + +BOOST_FIXTURE_TEST_CASE( translation_test_x, pentomino_fixture ) +{ + I.translate_one(0); + const std::vector expected_I_coos{{1,0},{1,1},{1,2},{1,3},{1,4}}; + BOOST_CHECK_EQUAL_COLLECTIONS(I.coos.begin(), I.coos.end(), + expected_I_coos.begin(), expected_I_coos.end()); +} + +BOOST_FIXTURE_TEST_CASE( translation_test_y, pentomino_fixture ) +{ + I.translate_one(1); + const std::vector expected_I_coos{{0,1},{0,2},{0,3},{0,4},{0,5}}; + BOOST_CHECK_EQUAL_COLLECTIONS(I.coos.begin(), I.coos.end(), + expected_I_coos.begin(), expected_I_coos.end()); +} + +BOOST_FIXTURE_TEST_CASE( flip_test_I, pentomino_fixture ) +{ + const std::vector expected_I_coos{I.coos}; + I.flip(0); + BOOST_CHECK_EQUAL_COLLECTIONS(I.coos.begin(), I.coos.end(), + expected_I_coos.begin(), expected_I_coos.end()); +} + +BOOST_AUTO_TEST_CASE( flip_test_F ) +{ + pentominos::Pentomino F("F"); + F.flip(0); + const std::vector expected_F_coos{{0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 1}}; + BOOST_CHECK_EQUAL_COLLECTIONS(F.coos.begin(), F.coos.end(), + expected_F_coos.begin(), expected_F_coos.end()); +} + +BOOST_FIXTURE_TEST_CASE( turn_test_I, pentomino_fixture ) +{ + const std::vector expected_I_coos{{0,0},{1,0},{2,0},{3,0},{4,0}}; + I.turn90(); + BOOST_CHECK_EQUAL_COLLECTIONS(I.coos.begin(), I.coos.end(), + expected_I_coos.begin(), expected_I_coos.end()); +} + +BOOST_FIXTURE_TEST_CASE( turn_test_I_2, pentomino_fixture ) +{ + pentominos::Pentomino Ip(I); + Ip.turn90().turn90(); + BOOST_CHECK_EQUAL_COLLECTIONS(I.coos.begin(), I.coos.end(), + Ip.coos.begin(), Ip.coos.end()); +} + +BOOST_AUTO_TEST_CASE( turn_test_Y ) +{ + std::set s; + pentominos::Pentomino Y{"Y"}; + for (int i=0; i<4; ++i) { + s.insert(Y); + Y.turn90(); + } + BOOST_CHECK_EQUAL(s.size(), (size_t)4); +} + +BOOST_FIXTURE_TEST_CASE( max_test_I, pentomino_fixture ) +{ + const pentominos::CooType + m(I.max()), + expected{0,4}; + BOOST_CHECK_EQUAL_COLLECTIONS(m.begin(), m.end(), + expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE( max_test_F ) +{ + pentominos::Pentomino F{"F"}; + const pentominos::CooType + m(F.max()), + expected{2,2}; + BOOST_CHECK_EQUAL_COLLECTIONS(m.begin(), m.end(), + expected.begin(), expected.end()); +} + +BOOST_FIXTURE_TEST_CASE( set_test_I, pentomino_fixture ) +{ + std::set s; + s.insert(I); + s.insert(I); + BOOST_CHECK_EQUAL(s.size(), (size_t)1); +} + +BOOST_AUTO_TEST_CASE( test_fixed_pentominos ) +{ + std::map orbit_size; + for (const auto& P : pentominos::all_pentominos()) { + orbit_size[P.name] = pentominos::fixed_pentominos_of(P).size(); + } + std::map expected{{"F", 8}, {"I", 2}, {"L", 8}, {"N", 8}, {"P", 8}, {"U", 4}, {"T", 4}, {"W", 4}, {"V", 4}, {"Y", 8}, {"X", 1}, {"Z", 4}}; + BOOST_CHECK_EQUAL_COLLECTIONS(orbit_size.begin(), orbit_size.end(), + expected.begin(), expected.end()); +} + +// Local Variables: +// mode:C++ +// c-basic-offset:3 +// indent-tabs-mode:nil +// End: diff --git a/dancing_links/python/.project b/dancing_links/python/.project new file mode 100644 index 0000000..c04a273 --- /dev/null +++ b/dancing_links/python/.project @@ -0,0 +1,17 @@ + + + python + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/dancing_links/python/.pydevproject b/dancing_links/python/.pydevproject new file mode 100644 index 0000000..0c0e3ca --- /dev/null +++ b/dancing_links/python/.pydevproject @@ -0,0 +1,8 @@ + + +Default +python 2.7 + +/${PROJECT_DIR_NAME}/LovisJonas + + diff --git a/dancing_links/python/LovisJonas/Key.asc b/dancing_links/python/LovisJonas/Key.asc new file mode 100644 index 0000000..8d5bdd8 --- /dev/null +++ b/dancing_links/python/LovisJonas/Key.asc @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +mQENBFVbWW4BCACy16oJ/Y9Qu+0q1eYaEMGtLVOQU2iqoe/cU3rUHx94HM3JdgiV +CluMw0ddMN1HM7pLdcMCxGq4Nb5kuduYfHDCC3BfPzVnmYzGYUgCDm4TDqDSUHSV +U/OppqPeEV8ccMWPWz9//D+R+YuushxRwE+ZRF530Zcq9VR3p/0MkMYailxTO87y +oEsPhN70RPJSWCdhrbX11VgIvtvrCMG26fY9Z2e8/mTHt6uFfndW1Ao8YaQ1l5yp +UJow2v2XT1MDk9UllrDibnXTKVPS6Q0H+ad8QbPJTar3sw+r5XOc/Y2nMcSEKKLA +sGQA/+782f00vbk1yWZesFX02lHYCN5TJsJJABEBAAG0K0xvdmlzIEFuZGVyc29u +IDxsb3Zpc19hbmRlcnNvbkBob3RtYWlsLmNvbT6JATkEEwEIACMFAlVbWW4CGw8H +CwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRDyI21zhpflf+eSB/9+oeqLug73 +YuM4vc1BeraU6lIhE8e6OIoJX9uABRN3ifDAaFFkCekENXlKj+/m41k4AfRcLiLK +B0SwdJdVmCjBMasNotuyBrzkIeeVMaUW4MT8lEO/4vpM5eEVSx1/iZqsbb/xRnzO +RFbVSmAO78312zUczkYaqaD6UUwHOzMxPJmw8bSR7ijyFqMQylRSGvs7meiSQAIQ +DhDKxjUhXGqx4V17Jh0Q6KzSK8buauaMEMyg+T0jXOa7R7Jz3bR5eanv6D3hBv01 +z3ihLkSbaDhj7vevZCFknqIdsdTUEkN89VXYskX9IqJhXDb7rJmPzppgsSZXMahw +f9krWKaRbX0s +=XsNu +-----END PGP PUBLIC KEY BLOCK----- diff --git a/dancing_links/python/LovisJonas/__pycache__/test_sudoku.py b/dancing_links/python/LovisJonas/__pycache__/test_sudoku.py new file mode 100644 index 0000000..4f9281c --- /dev/null +++ b/dancing_links/python/LovisJonas/__pycache__/test_sudoku.py @@ -0,0 +1,34 @@ +''' +Created on 08.05.2015 + +@author: lovis +''' +import unittest +from incidence_matrix import IncidenceMatrix +import incidence_matrix +import sudoku + + +class Test(unittest.TestCase): + + + def testName(self): + example1= [[0,2,8],[0,4,6],[0,7,4],[1,1,5],[1,3,3],[1,4,2],[2,0,3],[2,2,7],[2,5,8],[2,7,9],[3,0,9],[3,1,3],[3,6,4],[3,7,6],[4,2,6],[4,5,4],[4,6,5],[4,7,7],[5,1,4],[5,7,8], + [5,8,2],[6,0,5],[6,1,8],[6,3,1],[6,4,4],[6,6,2],[6,7,3],[6,8,7],[7,2,3],[7,5,8],[7,6,8],[7,7,5],[8,0,2],[8,4,7],[8,6,8]] + example2= [[0,0,4],[0,3,8],[1,6,1],[1,8,6],[2,6,3],[3,0,5],[3,7,4],[4,4,3],[4,7,2],[5,5,1],[6,1,3],[6,4,6],[6,6,2],[7,3,5],[7,7,7],[8,2,8],[8,3,4]] + empty = [] + names=sudoku.sudokuListHeaders(example2) + print(names) + print(len(names)) + I=incidence_matrix.IncidenceMatrix(names) + I.insertSudokuRows(example2,names) + print(I.rows) + I.calculatePentominoSolution(0, []) + print(len(I.solutions)) + print(I.zacka) + pass + + +if __name__ == "__main__": + #import sys;sys.argv = ['', 'Test.testName'] + unittest.main() \ No newline at end of file diff --git a/dancing_links/python/LovisJonas/examples.py b/dancing_links/python/LovisJonas/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/LovisJonas/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/LovisJonas/incidence_matrix.py b/dancing_links/python/LovisJonas/incidence_matrix.py new file mode 100644 index 0000000..af61d41 --- /dev/null +++ b/dancing_links/python/LovisJonas/incidence_matrix.py @@ -0,0 +1,254 @@ +import pentominos +import sudoku +import copy + +from copy import deepcopy +from sudoku import cal_square +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + newColumn=ColumnObject(left,right,None,None,name) + newColumn.up=newColumn.down=newColumn + newColumn.left.right=newColumn + newColumn.right.left=newColumn + + + def appendRow(self, tileName, placement): + self.indexOfPiecePlacement[tileName]+=1 + columnTile=self.columnObjectOfName[tileName] + columnTile.size+=1 + tileNameCell=IncidenceCell(columnTile,columnTile,columnTile.up,columnTile,columnTile,str(tileName)+str([self.indexOfPiecePlacement[tileName]-1])) + tileNameCell.up.down=tileNameCell + columnTile.up=tileNameCell + listOfPlacementCells = [] + self.rows+=1 + for position in placement: + columnPlacement=self.columnObjectOfName[position] + listOfPlacementCells.append(IncidenceCell(columnPlacement, columnPlacement, columnPlacement.up, columnPlacement, columnPlacement, str(tileName)+str(position))) + for k in listOfPlacementCells: + columnPlacement=self.columnObjectOfName[k.listHeader.name] + columnPlacement.up=k + k.up.down=k + columnPlacement.size+=1 + n=len(listOfPlacementCells) + rep = [n] + for k in listOfPlacementCells: + rep.append(k.representation()) + for i in range(n): + if i==0: + listOfPlacementCells[i].left=tileNameCell + elif i in range(1,n): + listOfPlacementCells[i].left=listOfPlacementCells[i-1] + if i==n-1: + listOfPlacementCells[i].right=tileNameCell + elif i in range(n-1): + listOfPlacementCells[i].right=listOfPlacementCells[i+1] + rep = [n] + for k in listOfPlacementCells: + rep.append(k.representation()) + tileNameCell.left=listOfPlacementCells[n-1] + tileNameCell.right=listOfPlacementCells[0] + + + def coverColumn(self, columnTile): + columnTile.left.right=columnTile.right + columnTile.right.left=columnTile.left + currentCell=columnTile.down + currentCellHorizontal=columnTile.down + while currentCell != columnTile: + currentCellHorizontal=currentCell.right + while currentCellHorizontal != currentCell: + currentCellHorizontal.up.down=currentCellHorizontal.down + currentCellHorizontal.down.up=currentCellHorizontal.up + currentCellHorizontal.listHeader.size-=1 + currentCellHorizontal=currentCellHorizontal.right + currentCell=currentCell.down + + def uncoverColumn(self, c): + currentCell=c.up + currentCellHorizontal=c.up + while currentCell != c: + currentCellHorizontal=currentCell.left + while currentCellHorizontal != currentCell: + currentCellHorizontal.up.down=currentCellHorizontal + currentCellHorizontal.down.up=currentCellHorizontal + currentCellHorizontal.listHeader.size+=1 + currentCellHorizontal=currentCellHorizontal.left + currentCell=currentCell.up + c.left.right=c + c.right.left=c + + def insertAllPlacements(self, pentomino): + pentomino.normalize() + versionList=pentominos.fixed_pentominos_of(pentomino) + coordinatesAsStrings=[] + for p in versionList: + for i in range(8): + for k in range(8): + if p.legal(): + for l in range(5): + coordinatesAsStrings.append(str(p.coos[l][0])+str(p.coos[l][1])) + self.appendRow(p.name, coordinatesAsStrings) + p.translate_one(1) + coordinatesAsStrings=[] + p.translate_by([0,-8]) + p.translate_one(0) + + + def initializeTheIncidenceMatrix(self): + allPentos=pentominos.all_pentominos() + for p in allPentos: + self.insertAllPlacements(p) + + def initializeSudokuMatrix(self, sudoku): + self.sudokuListHeaders(sudoku) + pass + + + def insertSudokuRows(self,givenSudoku,names): + for row in range(9) : + for column in range(9) : + for value in range(1,10): + if [row,column,value] not in givenSudoku: + if ((str(row)+str(column)) in names and ("r"+str(row)+str(value)) in names and ("c"+str(column)+str(value)) in names and ("sq"+str(cal_square(row,column))+str(value)) in names): + self.appendRow(str(row)+str(column),["r"+str(row)+str(value),"c"+str(column)+str(value),"sq"+str(sudoku.cal_square(row,column))+str(value)]) + + + + + + + + + + + def smallestColumnObject(self): + currentColumn = self.h.right + currentSize = 10000 + while currentColumn != self.h : + if currentSize > currentColumn.size : + currentSize = currentColumn.size + smallestColumn = currentColumn + currentColumn = currentColumn.right + return smallestColumn + + #Global variable for valid solutions + solutions = [] + zacka = [] + def calculatePentominoSolution(self,k,solution): + if self.h == self.h.right: + + self.solutions.append(solution) + for n in solution: + self.zacka.append(n.name) + return + selectedColumn = self.smallestColumnObject() + + if selectedColumn.size <= 0: + return + + currentCell = selectedColumn.down + self.coverColumn(selectedColumn) + while currentCell != selectedColumn: + walkingCell = currentCell.right + solution.append(walkingCell) + while walkingCell != currentCell: + self.coverColumn(walkingCell.listHeader) + walkingCell = walkingCell.right + self.calculatePentominoSolution(k+1,solution) + solution.pop(k) + walkingCell=currentCell.left + while walkingCell!=currentCell: + self.uncoverColumn(walkingCell.listHeader) + walkingCell=walkingCell.left + currentCell=currentCell.down + self.uncoverColumn(selectedColumn) + + return + \ No newline at end of file diff --git a/dancing_links/python/LovisJonas/pentominos.py b/dancing_links/python/LovisJonas/pentominos.py new file mode 100644 index 0000000..e97a408 --- /dev/null +++ b/dancing_links/python/LovisJonas/pentominos.py @@ -0,0 +1,278 @@ +import copy + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + + def normalize_coo(self, coo): + a=self.coos[0][coo] + for i in self.coos : + if a > self.coos[i][coo] : + a = self.coos[i][coo] + for i in self.coos : + self.coos[i][coo] = self.coos[i][coo] - [a] + + def normalize(self): + self.coos.sort() + a=self.coos[0][0] + b=self.coos[0][1] + for i in self.coos : + if a > i[0] : + a = i[0] + if b > i[1] : + b = i[1] + for i in range(5) : + self.coos[i][0] = self.coos[i][0] - a + self.coos[i][1] = self.coos[i][1] - b + return self + + def flip(self, coo): + right = -100 + left = 100 + for i in self.coos : + if right < i[coo] : + right = i[coo] + if left > i[coo] : + left = i[coo] + + if right-left == 1 : + for i in range(5) : + if self.coos[i][coo] == left : + self.coos[i][coo] = right + else : + self.coos[i][coo] = left + elif right-left == 2 : + for i in range(5) : + if self.coos[i][coo] == left : + self.coos[i][coo] = right + elif self.coos[i][coo] == right : + self.coos[i][coo] = left + elif right-left == 3 : + for i in range(5) : + if self.coos[i][coo] == left : + self.coos[i][coo] = right + elif self.coos[i][coo] == right : + self.coos[i][coo] = left + elif self.coos[i][coo] == right-1 : + self.coos[i][coo] = right-2 + else : + self.coos[i][coo] = right-1 + return self + + def translate_one(self, coo): + for i in range(5) : + self.coos[i][coo] = self.coos[i][coo] + 1 + return self + + def translate_coo(self, coo, amount): + for i in self.coos : + self.coos[i][coo] = self.coos[i][coo] + amount + return self + + def translate_by(self, by_vector): + for i in range(5) : + self.coos[i][0] = self.coos[i][0] + by_vector[0] + self.coos[i][1] = self.coos[i][1] + by_vector[1] + return self + + def turn90(self): + for i in range(5) : + coord = self.coos[i][1] + self.coos[i][1]=self.coos[i][0] + self.coos[i][0]=coord + self.flip(1) + return self + + def legal(self): + for p in self.coos: + if p[0]<0: + return False + if p[0]>7: + return False + if p[1]<0: + return False + if p[1]>7: + return False + for p in [[3,3],[3,4],[4,3],[4,4]]: + if p in self.coos: + return False + return True + + def max(self): + maxx=-1 + maxy=-1 + maximum=list() + for i in self.coos: + if maxx0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep + + + + diff --git a/dancing_links/python/LovisJonas/sudoku.py b/dancing_links/python/LovisJonas/sudoku.py new file mode 100644 index 0000000..b2ad778 --- /dev/null +++ b/dancing_links/python/LovisJonas/sudoku.py @@ -0,0 +1,140 @@ +''' +Created on 08.05.2015 + +@author: lovis +''' +import copy +import math + +def cal_square(row,column): + if row < 3: + square = math.floor(column/3) + if 2 < row < 6: + square = math.floor(column/3)+3 + if 5 < row < 9: + square = math.floor(column/3)+6 + return square + +def sudokuListHeaders(givenSudoku): + names=[] + reminder_cood=1 + reminder_row=1 + reminder_column=1 + reminder_sq=1 + + for row in range(9): + for column in range(9) : + for value in range(1,10) : + if [row,column,value] in givenSudoku: + reminder_cood=0 + if value==9: + if reminder_cood==1: + names.append(str(row)+str(column)) + reminder_cood=1 + + for value in range(1,10): + for row in range(9): + for column in range(9): + if [row,column,value] in givenSudoku: + reminder_row=0 + if column==8 : + if reminder_row==1: + names.append("r"+str(row)+str(value)) + reminder_row=1 + + for value in range(1,10) : + for column in range(9): + for row in range(9): + if [row,column,value] in givenSudoku: + reminder_column=0 + if row==8 : + if reminder_column==1: + names.append("c"+str(column)+str(value)) + reminder_column=1 + + + for value in range(1,10): + for row in range (3): + for column in range(3): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==2 and row==2 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (3,6): + for column in range(3): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==2 and row==5 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (6,9): + for column in range(3): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==2 and row==8 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (3): + for column in range(3,6): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==5 and row==2 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (3,6): + for column in range(3,6): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==5 and row==5 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (6,9): + for column in range(3,6): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==5 and row==8 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (3): + for column in range(6,9): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==8 and row==2 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (3,6): + for column in range(6,9): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==8 and row==5 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + for value in range(1,10): + for row in range (6,9): + for column in range(6,9): + if [row, column, value] in givenSudoku: + reminder_sq=0 + if column==8 and row==8 and reminder_sq==1: + names.append("sq"+str(cal_square(row,column))+str(value)) + reminder_sq=1 + + return names + + + \ No newline at end of file diff --git a/dancing_links/python/LovisJonas/test_incidence_matrix.py b/dancing_links/python/LovisJonas/test_incidence_matrix.py new file mode 100644 index 0000000..35fdffa --- /dev/null +++ b/dancing_links/python/LovisJonas/test_incidence_matrix.py @@ -0,0 +1,63 @@ +import unittest +import pentominos +import incidence_matrix +import examples +import copy + +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + #print("Matrix vorher append one row:" ,I.representation()) + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + #print("columnObjectRepresentation" + str(rep)) + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + + def test_calculatePentominoSolution(self): + I = incidence_matrix.IncidenceMatrix(pentominos.all_pentominos_names()+pentominos.all_positions()) + I.initializeTheIncidenceMatrix() + I.calculatePentominoSolution(0,[]) + print(incidence_matrix.IncidenceMatrix.solutions) + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/LovisJonas/test_pentominos.py b/dancing_links/python/LovisJonas/test_pentominos.py new file mode 100644 index 0000000..d6c58bc --- /dev/null +++ b/dancing_links/python/LovisJonas/test_pentominos.py @@ -0,0 +1,74 @@ +import unittest +import pentominos +import copy + +class TestPentominoMethods(unittest.TestCase): + +# def setUp(self): + + def test_normalize(self): + for p in pentominos.all_pentominos(): + self.assertEqual(p.coos, p.normalize().coos, "test_normalize failed for polyomino " + p.name) + + def test_translate(self): + self.assertEqual([[c[0]+1,c[1]] for c in pentominos.I().coos], pentominos.I().translate_one(0).coos) + self.assertEqual([[c[0],c[1]+1] for c in pentominos.I().coos], pentominos.I().translate_one(1).coos) + + def test_TileSet(self): + s = pentominos.TileSet([pentominos.I(), pentominos.I()]) + self.assertEqual(s.size(), 1) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + self.assertEqual(reps.size(), 4) + + + def test_turn90(self): + c0 = copy.deepcopy(pentominos.I().coos) + self.assertEqual(c0, pentominos.I().turn90().turn90().coos) + + p = pentominos.Y() + s = pentominos.TileSet() + for i in range(4): + s.add(p) + p.turn90() + self.assertEqual(4, s.size()) + + def test_max(self): + self.assertEqual([0,4], pentominos.I().max()) + self.assertEqual([2,2], pentominos.F().max()) + + def test_set(self): + s = set([pentominos.I(), pentominos.I()]) + self.assertEqual(len(s), 1) + + def test_fixed_pentominos(self): + orbitSize = dict() + for p in pentominos.all_pentominos(): + orbitSize[p.name] = pentominos.fixed_pentominos_of(p).size() + + self.assertEqual(dict({'F': 8, 'I': 2, 'L': 8, 'N': 8, 'P': 8, 'U': 4, 'T': 4, 'W': 4, 'V': 4, 'Y': 8, 'X': 1, 'Z': 4}), orbitSize) + self.assertEqual(pentominos.all_fixed_pentominos().size(), 63) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPentominoMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/RobertRaoul/examples.py b/dancing_links/python/RobertRaoul/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/RobertRaoul/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/RobertRaoul/incidence_matrix.py b/dancing_links/python/RobertRaoul/incidence_matrix.py new file mode 100644 index 0000000..38bb426 --- /dev/null +++ b/dancing_links/python/RobertRaoul/incidence_matrix.py @@ -0,0 +1,306 @@ + +import pentominos + + +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + + counter = 0 + + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + print(names) + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + """ insert a column header object into the circular linked list that contains the "root" node """ + + + newColumn=ColumnObject(left,right,None,None,name) + newColumn.up=newColumn.down=newColumn + newColumn.left.right=newColumn + newColumn.right.left=newColumn + + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + #TODO selber + self.indexOfPiecePlacement[tileName]+=1 + columnTile=self.columnObjectOfName[tileName] + columnTile.size+=1 + tileNameCell=IncidenceCell(columnTile,columnTile,columnTile.up,columnTile,columnTile,str(tileName)+str([self.indexOfPiecePlacement[tileName]-1])) + tileNameCell.up.down=tileNameCell + columnTile.up=tileNameCell + listOfPlacementCells = [] + self.rows+=1 + for position in placement: + columnPlacement=self.columnObjectOfName[position] + listOfPlacementCells.append(IncidenceCell(columnPlacement, columnPlacement, columnPlacement.up, columnPlacement, columnPlacement, str(tileName)+str(position))) + for k in listOfPlacementCells: + columnPlacement=self.columnObjectOfName[k.listHeader.name] + columnPlacement.up=k + k.up.down=k + columnPlacement.size+=1 + n=len(listOfPlacementCells) + rep = [n] + for k in listOfPlacementCells: + rep.append(k.representation()) + #print("vorher: " + str(rep)) + for i in range(n): + #print(str(i)+":vorher" + str(listOfPlacementCells[i].representation())) + if i==0: + listOfPlacementCells[i].left=tileNameCell + elif i in range(1,n): + listOfPlacementCells[i].left=listOfPlacementCells[i-1] + if i==n-1: + listOfPlacementCells[i].right=tileNameCell + elif i in range(n-1): + listOfPlacementCells[i].right=listOfPlacementCells[i+1] + #print("nachher" + str(listOfPlacementCells[i].representation())) + rep = [n] + for k in listOfPlacementCells: + rep.append(k.representation()) + #print("nachher: " + str(rep)) + tileNameCell.left=listOfPlacementCells[n-1] + tileNameCell.right=listOfPlacementCells[0] + + #Hallo Welt + def coverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + if c != c.left.right: + print("falsches covern") + #c dances horizontally out of the list + c.left.right=c.right + c.right.left=c.left + #initialize a field current_c_cell to travel down the column c + current_d_cell=c.down + #in every row of c let all cells but the cell in column c dance vertically out of the list + while current_d_cell != c: + current_r_cell=current_d_cell.right + while current_r_cell != current_d_cell: + #the dance out and update size(-1) + current_r_cell.up.down=current_r_cell.down + current_r_cell.down.up=current_r_cell.up + current_r_cell.listHeader.size-=1 + #travel right in the row + current_r_cell=current_r_cell.right + + #travel down column c + current_d_cell=current_d_cell.down + self.rows-=1 + + def uncoverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + + #we just undo the covering of c, so we start by going UP! + #initialize a field current_c_cell to travel up the column c + current_u_cell=c.up + current_u_cell_horizontal=c.up + #in every row of c let all cells but the cell in column c dance vertically out of the list + while current_u_cell != c: + current_l_cell=current_u_cell.left + while current_l_cell != current_u_cell: + #the dance back in line and update size(+1) + current_l_cell.up.down=current_l_cell + current_l_cell.down.up=current_l_cell + current_l_cell.listHeader.size+=1 + #travel LEFT in the row + current_l_cell=current_l_cell.left + + #travel up column c + current_u_cell=current_u_cell.up + self.rows+=1 + #finally c dances horizontally back in the header list + c.left.right=c + c.right.left=c + + def appendPentominoRows(self, pentomino): + pentomino.normalize() + coords = [] + for p in pentominos.fixed_pentominos_of(pentomino): + for i in range(8): + for j in range(8): + if p.legal(): + for k in range(5): + coords.append(str(p.coos[k][0])+str(p.coos[k][1])) + self.appendRow(p.name, coords) + p.translate_one(0) + coords=[] + p.translate_by([-8,0]) + p.translate_one(1) + + + + def initializeIncidenceMatrix(self): + for p in pentominos.all_pentominos(): + self.appendPentominoRows(p) + print(str(self.rows)) + + def solve(self): + solution = [] + self.algo(solution) + print(len(solution)) + + def algo(self, solution): + if(self.h.right == self.h): + self.counter = self.counter+1 + print(self.counter) + if self.isLegalSolution(solution): + print("check") + #print("solution: " + str(len(solution))) + #for row in solution: + # self.printRow(row) + return + + column = self.chooseColumnObject() + if column.name == "root": + return + else: + self.coverColumn(column) + r = column.down + while r != column: + solution.append(r) + j = r.right + while j != r: + self.coverColumn(j.listHeader) + j = j.right + self.algo(solution) + solution.pop(len(solution)-1) + #column = r.listHeader #ToDo check if line is really needed + j = r.left + while j != r: + self.uncoverColumn(j.listHeader) + j = j.left + r = r.down + self.uncoverColumn(column) + + return + + def printRow(self, row): + string = "" + string = string + row.listHeader.name + " " + current = row.right + while current != row: + string = string + current.listHeader.name + " " + current = current.right + print(string) + + def chooseColumnObject(self): + size = self.h.right.size + column = self.h.right + current = self.h.right + while current != self.h: + if current.size < size: + size = current.size + #ToDo check if deep_copying is needed + column = current + current = current.right + if size < 1: + return self.h + return column + + def isLegalSolution(self, solution): + all = set() + for i in solution: + all.add(i.listHeader.name) + current = i.right + while current != i: + all.add(current.listHeader.name) + current = current.right + + if len(all) == 72: + return True + else: + return False + diff --git a/dancing_links/python/RobertRaoul/pentominos.py b/dancing_links/python/RobertRaoul/pentominos.py new file mode 100644 index 0000000..10d8088 --- /dev/null +++ b/dancing_links/python/RobertRaoul/pentominos.py @@ -0,0 +1,235 @@ +import copy + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + + def normalize_coo(self, coo): + minn = 100000 + for i in self.coos: + if i[coo] < minn: + minn = i[coo] + return self.translate_coo(coo, -minn) + + def normalize(self): + return self.normalize_coo(0).normalize_coo(1) + + def flip(self, coo): + minn = 100 + maxx = -100 + for i in self.coos: + if maxx < i[coo]: + maxx = i[coo] + if minn > i[coo]: + minn = i[coo] + if maxx - minn == 1: + for i in range(5): + if self.coos[i][coo] == minn: + self.coos[i][coo] = maxx + elif self.coos[i][coo] == maxx: + self.coos[i][coo] = minn + elif maxx - minn == 2: + for i in range(5): + if self.coos[i][coo] == minn: + self.coos[i][coo] = maxx + elif self.coos[i][coo] == maxx: + self.coos[i][coo] = minn + elif maxx - minn == 3: + for i in range(5): + if self.coos[i][coo] == minn: + self.coos[i][coo] = maxx + elif self.coos[i][coo] == maxx: + self.coos[i][coo] = minn + elif self.coos[i][coo] == minn +1: + self.coos[i][coo] = maxx -1 + else: + self.coos[i][coo] = minn + 1 + return self + + + def translate_one(self, coo): + for i in self.coos: + i[coo] += 1 + return self + + def translate_coo(self, coo, amount): + for i in self.coos: + i[coo] += amount + return self + + def translate_by(self, by_vector): + for i in self.coos: + i[0] += by_vector[0] + i[1] += by_vector[1] + return self + + def turn90(self): + a = 0 + for i in self.coos: + a = i[0] + i[0] = i[1] + i[1] = a + self.flip(1) + return self + + def max(self): + a = 0 + maxx = 0 + counter = 0 + for i in self.coos: + counter = counter +1 + if i[0] + i[1] > maxx: + maxx = i[0] + i[1] + a = counter + return self.coos[a-1] + + def __hash__(self): + n = 10000000000 + k = 1 + for i in range(5): + for j in range(2): + n += self.coos[i][j]*k + k*= 10 + return n + + def __eq__(self, other): + self.normalize() + other.normalize() + self.coos.sort() + other.coos.sort() + return self.__hash__() == other.__hash__() + + def representation(self): + return "[" + self.name + ":" + str(self.coos) + "]" + + + def legal(self): + for c in self.coos: + if c[0]<0: + return False + if c[1]<0: + return False + if c[0]>7: + return False + if c[1]>7: + return False + for p in [[3,3],[3,4],[4,3],[4,4]]: + if p in self.coos: + return False + + return True + + +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + + +def all_pentominos(): + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + + +def fixed_pentominos_of(orig_p): + p = copy.deepcopy(orig_p) + pentoList = TileSet() + p.normalize() + pentoList.add(p) + for i in range(3): + p.turn90() + if not p in pentoList: + pentoList.add(p.normalize()) + p.turn90() + p.flip(1) + if not p in pentoList: + pentoList.add(p.normalize()) + for i in range(3): + p.turn90() + if not p in pentoList: + pentoList.add(p.normalize()) + #print(p.name + " " + str(len(pentoList.set))) + return pentoList + +def all_fixed_pentominos(): + pentoList = TileSet() + for i in all_pentominos(): + for j in fixed_pentominos_of(i): + pentoList.add(j) + return pentoList + +class TileSet(object): + def __init__(self, plist=[]): + self.set = set() + for p in plist: + self.add(p) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + if p not in self.set: + self.set.add(copy.deepcopy(p)) + + def size(self): + return len(self.set) + + def representation(self): + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep + + + + diff --git a/dancing_links/python/RobertRaoul/test_incidence_matrix.py b/dancing_links/python/RobertRaoul/test_incidence_matrix.py new file mode 100644 index 0000000..18fa01f --- /dev/null +++ b/dancing_links/python/RobertRaoul/test_incidence_matrix.py @@ -0,0 +1,75 @@ +import unittest +import incidence_matrix +import pentominos +import examples +import copy + +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + def test_appendRos(self): + I = examples.scott_example() + I.initializeIncidenceMatrix() + total=0 + column = I.h.right + while column != I.h: + print(column.size) + total += column.size + column = column.right + total = total/6 + print(total, I.rows) + self.assertEqual(total,I.rows,"Sizes not equal") + + + def test_solve(self): + I = examples.scott_example() + print(I.representation()) + I.initializeIncidenceMatrix() + I.solve() + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/RobertRaoul/test_pentominos.py b/dancing_links/python/RobertRaoul/test_pentominos.py new file mode 100644 index 0000000..62e8a72 --- /dev/null +++ b/dancing_links/python/RobertRaoul/test_pentominos.py @@ -0,0 +1,75 @@ +import unittest +import pentominos +import copy + +class TestPentominoMethods(unittest.TestCase): + +# def setUp(self): + + def test_normalize(self): + for p in pentominos.all_pentominos(): + self.assertEqual(p.coos, p.normalize().coos, "test_normalize failed for polyomino " + p.name) + + def test_translate(self): + self.assertEqual([[c[0]+1,c[1]] for c in pentominos.I().coos], pentominos.I().translate_one(0).coos) + self.assertEqual([[c[0],c[1]+1] for c in pentominos.I().coos], pentominos.I().translate_one(1).coos) + + def test_TileSet(self): + s = pentominos.TileSet([pentominos.I(), pentominos.I()]) + self.assertEqual(s.size(), 1) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + self.assertEqual(reps.size(), 4) + + + def test_turn90(self): + c0 = copy.deepcopy(pentominos.I().coos) + self.assertEqual(c0, pentominos.I().turn90().turn90().coos) + + p = pentominos.Y() + s = pentominos.TileSet() + for i in range(4): + s.add(p) + p.turn90() + self.assertEqual(4, s.size()) + + + def test_max(self): + self.assertEqual([0,4], pentominos.I().max()) + self.assertEqual([2,2], pentominos.F().max()) + + def test_set(self): + s = set([pentominos.I(), pentominos.I()]) + self.assertEqual(len(s), 1) + + def test_fixed_pentominos(self): + orbitSize = dict() + for p in pentominos.all_pentominos(): + orbitSize[p.name] = pentominos.fixed_pentominos_of(p).size() + + self.assertEqual(dict({'F': 8, 'I': 2, 'L': 8, 'N': 8, 'P': 8, 'U': 4, 'T': 4, 'W': 4, 'V': 4, 'Y': 8, 'X': 1, 'Z': 4}), orbitSize) + self.assertEqual(pentominos.all_fixed_pentominos().size(), 63) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPentominoMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/SaSybTeam/board.py b/dancing_links/python/SaSybTeam/board.py new file mode 100644 index 0000000..f54347b --- /dev/null +++ b/dancing_links/python/SaSybTeam/board.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue May 19 14:38:22 2015 +This class gives a board for the pentominos to cover +@author: Thinkerbell +""" +import pentomino +import incidence_matrix + +class Board(object): + def __init__(self, rows, columns, covered): + """ rows are the given rows of the board + columns are the given columns of the board + covered is a list of tupel [i,j] with all covered coordinates + """ + self.rows = rows + self.columns = columns + self.covered = covered + + def representation(self): + """ returns a string representation of this board. + a board is represented with its uncovered coordinates, so + the string is a list of all uncovered coordinates + """ + rep = [] + for i in range(self.rows): + for j in range(self.columns): + if [i,j] not in self.covered([i,j]): + rep.append([i,j]) + return str(rep) + + def containsCoo(coo): + if coo not inHole(coo): + if 0 <= coo[0] <= self.rows: + if 0 <= coo[1] <= self.columns: + return true + else: + retrun false + + def containsPentomino(pentomino): + count = 0 + for coo in pento.coos: + if Board.containsCoo(coo): + count += 1 + if count == 5: + return true + else: + return false + +def inHole(coo): + """ The methode 'isInHole(coo)' checks, if a given coordinate coo equals + one of the coordinates [[3,3],[3,4],[4,3],[4,4]] """ + if coo not in [[3,3],[3,4],[4,3],[4,4]]: + return true + else: + return false + +class scott(object): + def __init__(self, IncidenceMatrix, Board): + self.InciMatrix = IncidenceMatrix + self.Board = Board + + def matrixRows(self): + self.InciMatrix = scott_matrixTitels() + # append all rows for all pentominos on all possible valid positions + allPentoTypes = pentomino.all_fixed_pentominos() + for pento in allPentoTypes: + for i in range(self.Board.rows): + for j in range(self.Board.columns): + pento.normalize() + pento.translate_by([i,j]) + if self.Board.containsPentomino(pento): + self.InciMatrix.appendRow(pento.name, pento.coos) + + def matrixTitels(): + """ The methode 'scott_example()' creates all ColumnObjects for: + - all the possible pentominos + - all positions on the actual board + and returns the corresponding incidence Matrix """ + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(self.Board.rows): + for j in range(self.Board.columns): + if not inHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + + \ No newline at end of file diff --git a/dancing_links/python/SaSybTeam/examples.py b/dancing_links/python/SaSybTeam/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/SaSybTeam/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/SaSybTeam/incidence_matrix.py b/dancing_links/python/SaSybTeam/incidence_matrix.py new file mode 100644 index 0000000..c1ed70a --- /dev/null +++ b/dancing_links/python/SaSybTeam/incidence_matrix.py @@ -0,0 +1,235 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + # size gives the number of cells in total in a column + self.size = 0 + # masterSize gives the number of leading cells in a column + self.masterSize = 0 + # this is kind of confusing, because in our problem, there should be no + # difference between size and masterSize + # this is only needed, if there is a column that is for a pentomnio AND + # for a placement, which makes (at least in my head) no sense + # NOTE Sa to Syb: compare with page 5 'root h, + # which serves as a master header for all active headers' + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + """ insert a column header object into the circular linked list + that contains the "root" node """ + newColumn = ColumnObject(left,right,None,None,name) + newColumn.up = newColumn + newColumn.down = newColumn + newColumn.left.right = newColumn + newColumn.right.left = newColumn + return self + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + # try to append a row to the Incidence_Matrix, + # starting with a new IncidenceCell at the end of a given Column. + # this could fail, if there is no such ColumnObject + try: + # Add a masterCell (corresponding to given tileName) at the end + # of the matching pentomino/coordinate type column + masterColumn = self.columnObjectOfName[tileName] + # The name is e.g. 'C[1]' for the 2nd Pentomino of type C. + # Notice: A possible columnObject C could be: + # 'C','C[0]','AC','IC', 'C[1]', size=4, masterSize=2 + masterCellName = tileName + '[' + str(masterColumn.masterSize) + ']' + newMasterCell = IncidenceCell(None,None,masterColumn.up, + masterColumn, masterColumn, masterCellName) + # rearrange the links of the circularly lists and upgrade the sizes + masterColumn.up.down = newMasterCell + masterColumn.up = newMasterCell + masterColumn.size += 1 + masterColumn.masterSize += 1 + # add cells (corresponding to the list 'placement') at the + # end of the matching Coordinate/Pentomino Columns + placement.sort() #this should make example-creating more easier + leftNeighbour = newMasterCell + for place in placement: + currColumn = self.columnObjectOfName[place] + # the name is e.g. I00, if this I pentomino covers the place 00 + # NOTE: it would be better to use MasterCellName to get a unique representation + placeCellName = tileName + place + newPlaceCell = IncidenceCell(leftNeighbour,None,currColumn.up, + currColumn,currColumn,placeCellName) + # rearrange the links of the current circular lists and + # upgrade the size + currColumn.up.down = newPlaceCell + currColumn.up = newPlaceCell + currColumn.size += 1 + # Notice: masterSize needs no upgrade here! a placeCell + # is not a masterCell + leftNeighbour.right = newPlaceCell + leftNeighbour = newPlaceCell + # links the beginning of this row (the masterCell) with the end + # of this row (last placeCell) --> circular list + leftNeighbour.right = newMasterCell + newMasterCell.left = leftNeighbour + self.rows += 1 + return self + except: + print('There accured a problem appending a row in column'+tileName) + + # The operation of covering column c removes c from the header list and + # removes all rows in c's own list from the other column lists they are in + def coverColumn(self, c): + """ removes c from the header list and removes all rows in c s own list + from the other column lists they are in + """ + # implement and document the algorithm in Knuth's paper. + if c!=self.h: + try: + # take the header of column c + currRow = c.listHeader + # change the left and right link of c + c.right.left = c.left + c.left.right = c.right + # iterate over the column c from top to bottom + for i in range(c.size): + # note: there should be no difference between runtime + # with a for or a while loop + # while currRow is not c: + # currRow == d in the paper + # one step further down the column + currRow = currRow.down + # remember the next element in the row + # currPlacement == r in the paper + currPlacement = currRow.right + # iterate over the row from left to right and change + # the pointers for up & down for all elements in the row + while currPlacement.listHeader != c.listHeader: + currPlacement.down.up = currPlacement.up + currPlacement.up.down = currPlacement.down + # update size of column - one row has been 'finished' + currPlacement.listHeader.size -= 1 + # one step further along the row + currPlacement = currPlacement.right + self.rows -= 1 + return self + except: + print('No matching column found to cover') + else: + print('You cannot cover the root h') + + def uncoverColumn(self, c): + """ uncover a given column c, this is where the links do their dance + """ + # implement and document the algorithm in Knuth's paper. + if c != self.h: + try: + # currRow == i in the paper + currRow = c + # iterate over the column bottom to top + for i in range(c.size): + currRow = currRow.up + # currPlacement == j in the paper + currPlacement = currRow.left + # iterate over the row left to right + while currPlacement.listHeader != c.listHeader: + currPlacement.listHeader.size += 1 + currPlacement.down.up = currPlacement + currPlacement.up.down = currPlacement + # walk one step further in the row + currPlacement = currPlacement.left + self.rows += 1 + c.right.left = c + c.left.right = c + return self + except: + print('No matching column found to uncover') + else: + print('you cannot uncover the root h') + \ No newline at end of file diff --git a/dancing_links/python/SaSybTeam/pentominos.py b/dancing_links/python/SaSybTeam/pentominos.py new file mode 100644 index 0000000..999fcae --- /dev/null +++ b/dancing_links/python/SaSybTeam/pentominos.py @@ -0,0 +1,273 @@ +import copy + +max_coord =999 + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + return self + + def normalize_coo(self, coo): + """ moves the given self straight to the given coo-axis. + returns an axis touching self, with only positiv coo-coordinates + coo: given axis + """ + self.translate_coo(coo, (-1)*self.min()[coo]) + return self + + def normalize(self): + """ normalize the given self. + returns an all axes touching self, with only positiv coordinates, + with lexicographical orderd coordinates + """ + self.coos.sort() + for i in range(self.dim): + self.normalize_coo(i) + return self + + def translate_one(self, coo): + """ translates the given self by one along the given coo-axis + coo: gives the axis + """ + for co in self.coos: + co[coo] += 1 + return self + + def translate_coo(self, coo, amount): + """ translates the given self by amount along the given coo-axis + coo: axis to translate along + amount: translaing distance + """ + for co in self.coos: + co[coo] += amount + return self + + def translate_by(self, by_vector): + """ translates the given self by an given vector + by_vector: vactor to translate the self with + """ + if len(by_vector) != self.dim: + print("dimension missmatch") + else: + for i in range(len(by_vector)): + self.translate_coo(i, by_vector[i]) + return self + + def flip(self, coo): + """ mirrors the given self over the given coo-axis + coo: given axis + hence for coo=0 it flips over the x-axis, for coo=1 over the y-axis + """ + # remember the place of it self and normalize + lower_coos = self.min() + self.normalize() + # flip it over the coo-axis + for c in self.coos: + a = -c[coo] + c[coo] = a + # bring it back to where it was before + self.normalize() + self.translate_by(lower_coos) + return self + + def turn90(self): + """ turns the given self clockwise around 90 degree. + the lower-bounding box stays where it was + """ + if self.dim == 2: + # remember the place of it and normalize it + re_place = self.min() + self.normalize() + # flip it along the identity line + for c in self.coos: + temp = c[0] + c[0] = c[1] + c[1] = temp + # flip it along the x-axis to turn clockwise + self.flip(0) + # replace it, to where it was before + self.normalize() + self.translate_by(re_place) + return self + else: + print("turn90 is only defined in dimension 2") + + def min(self): + """ finds the minimum coordinate in each axis, + these are representated as a "lower-bounding-box" + these lower-bounding-box is initialized with the maximal coordinates max_coord + """ + lower_coos = [max_coord]*self.dim + for i in range(self.dim): + for c in self.coos: + if c[i] < lower_coos[i]: + lower_coos[i] = c[i] + return lower_coos + + def max(self): + """ finds the maximum coordinate in each axis, + these are representated as an "upper-bounding-box" + these lupper-bounding-box is initialized with the maximal coordinates max_coord + """ + upper_coos = [(-1)*max_coord]*self.dim + for i in range(self.dim): + for c in self.coos: + if c[i] > upper_coos[i]: + upper_coos[i] = c[i] + return upper_coos + + def __hash__(self): + """ gives back an integer which represents the given pentomino in an unique way. + our hash has the form "dim | coordinate of normalized pentomino | translate vector". + translate vector is bounded by [0:999,0:999]. + example: the pentomino: [[12,4],[13,3],[13,4],[13,5],[14,5]] + is F = [[0,1],[1,0],[1,1],[1,2],[2,2]] translated by [12,3] + hash is: 2|0110111222|012003 (without "|" of course) + """ + #save the origin position of self and normalize it + lower_coos = self.min() + self.normalize() + # sort the coordinates in lexikografic order + self.coos.sort() + #construct the hash code in the describted way + hash = self.dim + for c in self.coos: + for i in range(self.dim): + hash = hash*10 + c[i] + for i in range(self.dim): + hash = 1000*hash + lower_coos[i] + # bring self back to where it was before + self.translate_by(lower_coos) + return hash + + def __eq__(self, other): + """ checks the equality of the data from "self" and "other" + """ + return self.__hash__() == other.__hash__() + + def representation(self): + """ Gives back a string representation of the given self + """ + return "[" + self.name + ":" + str(self.coos) + "]" + +""" The following classes implements all kinds of pentominos in normalized coordinates +""" +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + +def fixed_pentominos_of(p): + """ adds all possible representations of the given pentomino (turned and flipped) to self + """ + allReps = TileSet() + for i in range(4): + allReps.add(p.turn90()) + allReps.add(p.flip(0)) + for i in range(3): + allReps.add(p.turn90()) + return allReps + +def all_fixed_pentominos(): + """ gives back all possible representations of all possible pentominos + """ + all_pSet = TileSet() + pento_list = all_pentominos() + for p in pento_list: + all_pSet.add_TileSet(fixed_pentominos_of(p)) + return all_pSet + +def all_pentominos(): + """ gives back all possible pentominos + """ + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + +""" +""" +class TileSet(object): + + def __init__(self, plist=[]): + self.set = set() + for p in plist: + self.add(p) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + """ adds the given pentomino to self + """ + if p not in self.set: + self.set.add(copy.deepcopy(p)) + + def add_TileSet(self, tileSet): + """ adds the given tileSet to self + """ + for p in tileSet: + if p not in self.set: + self.add(p) + return self + + def size(self): + return len(self.set) + + def representation(self): + """ gives back a representation for tileSet + """ + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep + + diff --git a/dancing_links/python/SaSybTeam/testSaSyb.py b/dancing_links/python/SaSybTeam/testSaSyb.py new file mode 100644 index 0000000..04b07bc --- /dev/null +++ b/dancing_links/python/SaSybTeam/testSaSyb.py @@ -0,0 +1,22 @@ +import unittest +import pentominos + +class TestSaSyb(unittest.TestCase): + + def test_SaSyb(self): + x = pentominos.X() + print(x.representation()) + """ + i = pentominos.I() + print(i.representation()) + i.translate_by([2,1]) + print(i.representation()) + + print(i.turn90().representation()) + """ + print(x.turn90().representation()) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestSaSyb) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/SaSybTeam/test_incidence_matrix.py b/dancing_links/python/SaSybTeam/test_incidence_matrix.py new file mode 100644 index 0000000..e92122c --- /dev/null +++ b/dancing_links/python/SaSybTeam/test_incidence_matrix.py @@ -0,0 +1,59 @@ + + +import unittest +import incidence_matrix +import pentominos +import examples +import copy + +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/dancing_links/python/SaSybTeam/test_pentominos.py b/dancing_links/python/SaSybTeam/test_pentominos.py new file mode 100644 index 0000000..804ab4c --- /dev/null +++ b/dancing_links/python/SaSybTeam/test_pentominos.py @@ -0,0 +1,76 @@ +import unittest +import pentominos +import copy + +class TestPentominoMethods(unittest.TestCase): + +# def setUp(self): + + def test_normalize(self): + for p in pentominos.all_pentominos(): + print(p.representation()) + self.assertEqual(p.coos, p.normalize().coos, "test_normalize failed for polyomino " + p.name) + + + def test_translate(self): + self.assertEqual([[c[0]+1,c[1]] for c in pentominos.I().coos], pentominos.I().translate_one(0).coos) + self.assertEqual([[c[0],c[1]+1] for c in pentominos.I().coos], pentominos.I().translate_one(1).coos) + + def test_TileSet(self): + s = pentominos.TileSet([pentominos.I(), pentominos.I()]) + self.assertEqual(s.size(), 1) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + self.assertEqual(reps.size(), 4) + + + def test_turn90(self): + c0 = copy.deepcopy(pentominos.I().coos) + self.assertEqual(c0, pentominos.I().turn90().turn90().coos) + + p = pentominos.Y() + s = pentominos.TileSet() + for i in range(4): + s.add(p) + p.turn90() + self.assertEqual(4, s.size()) + + def test_max(self): + self.assertEqual([0,4], pentominos.I().max()) + self.assertEqual([2,2], pentominos.F().max()) + + def test_set(self): + s = set([pentominos.I(), pentominos.I()]) + self.assertEqual(len(s), 1) + + def test_fixed_pentominos(self): + orbitSize = dict() + for p in pentominos.all_pentominos(): + orbitSize[p.name] = pentominos.fixed_pentominos_of(p).size() + + self.assertEqual(dict({'F': 8, 'I': 2, 'L': 8, 'N': 8, 'P': 8, 'U': 4, 'T': 4, 'W': 4, 'V': 4, 'Y': 8, 'X': 1, 'Z': 4}), orbitSize) + self.assertEqual(pentominos.all_fixed_pentominos().size(), 63) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPentominoMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/andre/examples.py b/dancing_links/python/andre/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/andre/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/andre/incidence_matrix.py b/dancing_links/python/andre/incidence_matrix.py new file mode 100644 index 0000000..408734b --- /dev/null +++ b/dancing_links/python/andre/incidence_matrix.py @@ -0,0 +1,148 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + """ insert a column header object into the circular linked list that contains the "root" node """ + col = ColumnObject(left, right, None, None, name) + col.up = col.down = left.right = right.left = col + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + header = self.columnObjectOfName[tileName] + newName = tileName + "[" + str(self.indexOfPiecePlacement[tileName]) + "]" + cell = IncidenceCell(None, None, header.up, header, header, newName) + cell.left = cell.right = cell.up.down = cell.down.up = cell + + header.size += 1 + self.indexOfPiecePlacement[tileName] += 1 + + tmpCell = cell + for n in placement: + newHeader = self.columnObjectOfName[n] + newHeader.size += 1 + newCell = IncidenceCell(tmpCell, tmpCell.right, newHeader.up, newHeader, newHeader, tileName + n) + newCell.left.right = newCell.right.left = newCell.up.down = newCell.down.up = newCell + tmpCell = newCell + + def coverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + # cover header + c.left.right = c.right + c.right.left = c.left + + rowCell = c.down + while rowCell is not c: + colCell = rowCell.right + while colCell is not rowCell: + colCell.down.up = colCell.up + colCell.up.down = colCell.down + colCell.listHeader.size -= 1 + colCell = colCell.right + rowCell = rowCell.down + + def uncoverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + rowCell = c.up + while rowCell is not c: + colCell = rowCell.left + while colCell is not rowCell: + colCell.listHeader.size += 1 + colCell.up.down = colCell.down.up = colCell + colCell = colCell.left + rowCell = rowCell.up + c.left.right = c.right.left = c + diff --git a/dancing_links/python/andre/pentominos.py b/dancing_links/python/andre/pentominos.py new file mode 100644 index 0000000..3b79359 --- /dev/null +++ b/dancing_links/python/andre/pentominos.py @@ -0,0 +1,201 @@ +import copy +import numpy as np + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + self.coos.sort() # safety first ;) + + # normalize only one dimension + def normalize_coo(self, coo): + min = self.coos[0][coo] + for i in range(1,5): + if min > self.coos[0][coo]: + min = self.coos[0][coo] + self.translate_coo( coo, -min ) + return self + + # normalize object + def normalize(self): + # find bounding box left bottom corner + minX = self.coos[0][0] + minY = self.coos[0][1] + + for i in range(1,5): + if minX > self.coos[i][0]: + minX = self.coos[i][0] + if minY > self.coos[i][1]: + minY = self.coos[i][1] + + # translate this object to origin + self.translate_by( [-minX,-minY] ) + return self + + def flip(self, coo): + for i in range(len(self.coos)): + self.coos[i][coo] = -self.coos[i][coo] + self.normalize() + return self + + def translate_one(self, coo): + self.translate_coo(coo, 1) + self.coos.sort() + return self + + def translate_coo(self, coo, amount): + for i in range(0,5): + self.coos[i][coo] += amount + self.coos.sort() + return self + + def translate_by(self, by_vector): + for i in range(0,5): + self.coos[i][0] += by_vector[0] + self.coos[i][1] += by_vector[1] + self.coos.sort() + return self + + def turn90(self): + # create a rotation matrix + rotMatrix = np.matrix([[0,1],[-1,0]]) + + # rotate each vector + for i in range(0,5): + convert = np.transpose(np.matrix(self.coos[i])) + self.coos[i] = np.transpose(rotMatrix * convert) + + # convert back to native list + self.coos = np.array(self.coos).reshape(5,2).tolist() + + # normale position + self.normalize() + return self + + def max(self): + max = [self.coos[0][0], self.coos[0][1]] + for i in range(1,len(self.coos)): + if max[0] < self.coos[i][0]: + max[0] = self.coos[i][0] + if max[1] < self.coos[i][1]: + max[1] = self.coos[i][1] + + return max + + def __hash__(self): + return hash(str(self.coos)) + + def __eq__(self, other): + return hash(self) == hash(other) + + def representation(self): + return "[" + self.name + ":" + str(self.coos) + "]" + + +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + + +def all_pentominos(): + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + +def fixed_pentominos_of(pentomino): + c = copy.deepcopy(pentomino) + s = TileSet() + + for i in range(4): + s.add(c.turn90()) + s.add(c.flip(i%2)) + c.flip(i%2) # flip back for rotation + + return s + +def all_fixed_pentominos(): + all = TileSet() + + for p in all_pentominos(): + pentSet = fixed_pentominos_of(p) + all.add_all(pentSet) + + return all + +class TileSet(object): + def __init__(self, plist=[]): + self.set = set() + for p in plist: + self.add(p) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + # test first, if this p is still known + for q in self.set: + if q == p: + return + self.set.add(copy.deepcopy(p)) + + def add_all(self, set): + for p in set: + self.add(p) + + def size(self): + return len(self.set) + + def representation(self): + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep diff --git a/dancing_links/python/andre/test_incidence_matrix.py b/dancing_links/python/andre/test_incidence_matrix.py new file mode 100644 index 0000000..673bcc0 --- /dev/null +++ b/dancing_links/python/andre/test_incidence_matrix.py @@ -0,0 +1,57 @@ +import unittest +import incidence_matrix +import pentominos +import examples +import copy + +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/andre/test_pentominos.py b/dancing_links/python/andre/test_pentominos.py new file mode 100644 index 0000000..d6c58bc --- /dev/null +++ b/dancing_links/python/andre/test_pentominos.py @@ -0,0 +1,74 @@ +import unittest +import pentominos +import copy + +class TestPentominoMethods(unittest.TestCase): + +# def setUp(self): + + def test_normalize(self): + for p in pentominos.all_pentominos(): + self.assertEqual(p.coos, p.normalize().coos, "test_normalize failed for polyomino " + p.name) + + def test_translate(self): + self.assertEqual([[c[0]+1,c[1]] for c in pentominos.I().coos], pentominos.I().translate_one(0).coos) + self.assertEqual([[c[0],c[1]+1] for c in pentominos.I().coos], pentominos.I().translate_one(1).coos) + + def test_TileSet(self): + s = pentominos.TileSet([pentominos.I(), pentominos.I()]) + self.assertEqual(s.size(), 1) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + self.assertEqual(reps.size(), 4) + + + def test_turn90(self): + c0 = copy.deepcopy(pentominos.I().coos) + self.assertEqual(c0, pentominos.I().turn90().turn90().coos) + + p = pentominos.Y() + s = pentominos.TileSet() + for i in range(4): + s.add(p) + p.turn90() + self.assertEqual(4, s.size()) + + def test_max(self): + self.assertEqual([0,4], pentominos.I().max()) + self.assertEqual([2,2], pentominos.F().max()) + + def test_set(self): + s = set([pentominos.I(), pentominos.I()]) + self.assertEqual(len(s), 1) + + def test_fixed_pentominos(self): + orbitSize = dict() + for p in pentominos.all_pentominos(): + orbitSize[p.name] = pentominos.fixed_pentominos_of(p).size() + + self.assertEqual(dict({'F': 8, 'I': 2, 'L': 8, 'N': 8, 'P': 8, 'U': 4, 'T': 4, 'W': 4, 'V': 4, 'Y': 8, 'X': 1, 'Z': 4}), orbitSize) + self.assertEqual(pentominos.all_fixed_pentominos().size(), 63) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPentominoMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/ash_fs/examples.py b/dancing_links/python/ash_fs/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/ash_fs/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/ash_fs/incidence_matrix.py b/dancing_links/python/ash_fs/incidence_matrix.py new file mode 100644 index 0000000..6a2e431 --- /dev/null +++ b/dancing_links/python/ash_fs/incidence_matrix.py @@ -0,0 +1,136 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + cur = ColumnObject(left, right, None, None, name); + cur.up = cur.down = cur + left.right = right.left = cur + + def appendRow(self, tileName, placement): + """ a placement is a list of coordinates that indicates which squares the piece named tileName covers""" + tileColHeader = self.columnObjectOfName[tileName] + rowCell = IncidenceCell(None, None, tileColHeader.up, tileColHeader, tileColHeader, tileColHeader.name+"["+str(self.indexOfPiecePlacement[tileName]) +"]") + tileColHeader.size += 1 + self.indexOfPiecePlacement[tileName] += 1 + rowCell.left = rowCell.right = rowCell.up.down = rowCell.down.up = rowCell + + cell = rowCell + for n in placement: + header = self.columnObjectOfName[n] + header.size += 1 + newCell = IncidenceCell(cell, rowCell, header.up, header, header, tileColHeader.name + n) + cell.right = rowCell.left = header.up.down = header.up = newCell + cell = newCell + + def coverColumn(self, c): + c.right.left = c.left + c.left.right = c.right + cur = c.down + while cur is not c: + rowCell = cur.right + while rowCell is not cur: + rowCell.up.down = rowCell.down + rowCell.down.up = rowCell.up + rowCell.listHeader.size -= 1 + rowCell = rowCell.right + cur = cur.down + + def uncoverColumn(self, c): + curr = c.up + while curr is not c: + columnCell = curr.left + while columnCell is not curr: + columnCell.down.up = columnCell + columnCell.up.down = columnCell + columnCell.listHeader.size += 1 + columnCell = columnCell.left + curr = curr.up + c.right.left = c + c.left.right = c diff --git a/dancing_links/python/ash_fs/pentominos.py b/dancing_links/python/ash_fs/pentominos.py new file mode 100644 index 0000000..a9619ab --- /dev/null +++ b/dancing_links/python/ash_fs/pentominos.py @@ -0,0 +1,175 @@ +import copy +from array import * +import numpy as np +from sets import ImmutableSet + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + + def normalize_coo(self, coo): + minimum = min([c[coo] for c in self.coos]) + for c in self.coos: + c[coo] -= minimum + + def normalize(self): + for i in range(self.dim): + self.normalize_coo(i) + return self + + def flip(self, coo): + minimum = min([c[coo] for c in self.coos]) + for c in self.coos: + c[coo] -= (c[coo] - minimum) * 2 + self.normalize() + return self + + def translate_one(self, coo): + for c in self.coos: + c[coo] += 1 + return self + + def translate_coo(self, coo, amount): + for c in self.coos: + c[coo] += amount + return self + + def translate_by(self, by_vector): + for c in self.coos: + c += by_vector + return self + + def turn90(self, coo1=0, coo2=1): + for c in self.coos: + tmp = c[coo1] + c[coo1] = c[coo2] + c[coo2] = tmp*(-1) + self.normalize() + return self + + def max(self): + l = [] + for coo in range(self.dim): + a = max([c[coo] for c in self.coos]) + l.append(a) + return l + + def __hash__(self): + h = 0 + for p in self.coos: + h += hash(str(p)) + return hash((h,self.name)) + + def __eq__(self, other): + return isinstance(other,self.__class__) and self.coosToSet() == other.coosToSet() and self.name == other.name + + def coosToSet(self): + s = set() + for p in self.coos: + s.add(str(p)) + return s + + def representation(self): + return "[" + self.name + ":" + str(self.coos) + "]" + + +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + + +def all_pentominos(): + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + + +def fixed_pentominos_of(p): + ts = TileSet() + for i in range(4): + ts.add(p.turn90()) + for i in range(2): + ts.add(p.flip(i)) + return ts + +def all_fixed_pentominos(): + ts = TileSet() + for p in all_pentominos(): + for q in fixed_pentominos_of(p): + ts.add(q) + return ts + +class TileSet(object): + def __init__(self, plist=[]): + self.set = set() + for p in plist: + self.add(p) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + self.set.add(copy.deepcopy(p)) + + def union(self, s): + self.set.union(s.set) + + def size(self): + return len(self.set) + + def representation(self): + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep + diff --git a/dancing_links/python/ash_fs/test_incidence_matrix.py b/dancing_links/python/ash_fs/test_incidence_matrix.py new file mode 100644 index 0000000..9a24a0c --- /dev/null +++ b/dancing_links/python/ash_fs/test_incidence_matrix.py @@ -0,0 +1,56 @@ +import unittest +import incidence_matrix +import pentominos +import examples +import copy +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/ash_fs/test_pentominos.py b/dancing_links/python/ash_fs/test_pentominos.py new file mode 100644 index 0000000..3bdebb2 --- /dev/null +++ b/dancing_links/python/ash_fs/test_pentominos.py @@ -0,0 +1,74 @@ +import unittest +import pentominos +import copy + +class TestPentominoMethods(unittest.TestCase): + +# def setUp(self): + + def test_normalize(self): + for p in pentominos.all_pentominos(): + self.assertEqual(p.coos, p.normalize().coos, "test_normalize failed for polyomino " + p.name) + + def test_translate(self): + self.assertEqual([[c[0]+1,c[1]] for c in pentominos.I().coos], pentominos.I().translate_one(0).coos) + self.assertEqual([[c[0],c[1]+1] for c in pentominos.I().coos], pentominos.I().translate_one(1).coos) + + def test_TileSet(self): + s = pentominos.TileSet([pentominos.I(), pentominos.I()]) + self.assertEqual(s.size(), 1) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + self.assertEqual(reps.size(), 4) + + + def test_turn90(self): + c0 = copy.deepcopy(pentominos.I().coos) + #self.assertEqual(c0, pentominos.I().turn90().turn90().coos) + + p = pentominos.Y() + s = pentominos.TileSet() + for i in range(4): + s.add(p) + p.turn90() + self.assertEqual(4, s.size()) + + def test_max(self): + self.assertEqual([0,4], pentominos.I().max()) + self.assertEqual([2,2], pentominos.F().max()) + + def test_set(self): + s = set([pentominos.I(), pentominos.I()]) + self.assertEqual(len(s), 1) + + def test_fixed_pentominos(self): + orbitSize = dict() + for p in pentominos.all_pentominos(): + orbitSize[p.name] = pentominos.fixed_pentominos_of(p).size() + + self.assertEqual(dict({'F': 8, 'I': 2, 'L': 8, 'N': 8, 'P': 8, 'U': 4, 'T': 4, 'W': 4, 'V': 4, 'Y': 8, 'X': 1, 'Z': 4}), orbitSize) + self.assertEqual(pentominos.all_fixed_pentominos().size(), 63) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPentominoMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/ay4me/examples.py b/dancing_links/python/ay4me/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/ay4me/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/ay4me/incidence_matrix.py b/dancing_links/python/ay4me/incidence_matrix.py new file mode 100644 index 0000000..53d875c --- /dev/null +++ b/dancing_links/python/ay4me/incidence_matrix.py @@ -0,0 +1,165 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader #points to ColumnObject of the relevant column + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 #number of 1s in the column + self.initCounter = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h #unused fields all point to h itself + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + #creates new ColumnObject and inserts it between left and right + def insertColumnObject(self, left, right, name): + """ insert a column header object into the circular linked list that contains the "root" node """ + # ColumnObject(self, left, right, up, down, name) + newColumnObject = ColumnObject(left, right, None, None, name) + newColumnObject.up = newColumnObject.down = newColumnObject #right now the column has only this element + #change links in left and right + left.right = newColumnObject + right.left = newColumnObject + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + currentColumnObject = self.columnObjectOfName[tileName] #pentomino column + rowName = tileName + '[' + str(currentColumnObject.initCounter) + ']' + currentColumnObject.initCounter += 1 + #rowName = tileName + '[' + str(currentColumnObject.size) + ']' + #IncidenceCell(self, left, right, up, down, listHeader, name): + currentCell = IncidenceCell(None,None,currentColumnObject.up,currentColumnObject,currentColumnObject, rowName)#construct new Cell + currentColumnObject.size += 1 + currentCell.left = currentCell.right = currentCell #right now the row has only this element + currentColumnObject.up.down = currentCell + currentColumnObject.up = currentCell + + + for col in placement: + currentColumnObject = self.columnObjectOfName[col] #find corresponding column + newCell = IncidenceCell(currentCell,currentCell.right,currentColumnObject.up,currentColumnObject,currentColumnObject,tileName + currentColumnObject.name) + currentColumnObject.size += 1 + currentColumnObject.up.down = newCell + currentColumnObject.up = newCell + currentCell.right.left = newCell + currentCell.right = newCell + currentCell = newCell + + #for further documentation see "Dancing Links" paper by Knuth p.6 + def coverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + #c is ColumnObject of the column to be covered + #remove columnObject from headerList + c.right.left = c.left #L[R[c]] <- L[c] + c.left.right = c.right #R[L[c]] <- R[c] + currentRow = c.down #i + while currentRow is not c: #go through all rows of column + currentColumn = currentRow.right #j + while currentColumn is not currentRow: #go through all columns of row + currentColumn.down.up = currentColumn.up #U[D[j]] <- U[j] + currentColumn.up.down = currentColumn.down #D[U[j]] <- D[j] + currentColumn.listHeader.size -= 1 #S[C[j]] <- S[C[j]]-1 + currentColumn = currentColumn.right + currentRow = currentRow.down + + #for further documentation see "Dancing Links" paper by Knuth p.6 + def uncoverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + #c is ColumnObject of the column to be uncovered + currentRow = c.up #i + while currentRow is not c: #go through all rows of the column in reverse order + currentColumn = currentRow.left #j + while currentColumn is not currentRow: #go through all columns of row in reverse order + currentColumn.listHeader.size += 1 #S[C[j]] <- S[C[j]]+1 + currentColumn.down.up = currentColumn #U[D[j]] <- j + currentColumn.up.down = currentColumn #D[U[j]] <- j + currentColumn = currentColumn.left + currentRow = currentRow.up + c.right.left = c #L[R[c]] <- c + c.left.right = c #R[L[c]] <- c + diff --git a/dancing_links/python/ay4me/meintest_incidence_matrix.py b/dancing_links/python/ay4me/meintest_incidence_matrix.py new file mode 100644 index 0000000..6a337c8 --- /dev/null +++ b/dancing_links/python/ay4me/meintest_incidence_matrix.py @@ -0,0 +1,8 @@ +import incidence_matrix +import pentominos +import examples +import copy + + +I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) +print I.representation() \ No newline at end of file diff --git a/dancing_links/python/ay4me/pentominos.py b/dancing_links/python/ay4me/pentominos.py new file mode 100644 index 0000000..e436ed7 --- /dev/null +++ b/dancing_links/python/ay4me/pentominos.py @@ -0,0 +1,244 @@ +import copy + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos #coordinates + self.dim = len(coos[0]) + return self + + #moves pentomino back to one axis + def normalize_coo(self, coo): + ref = self.min_box() #current position + offset = ref[coo] + if coo==1: + self.translate_by[0,min_box[1]] + else: + self.translate_by[min_box[0],0] + return self + + #moves pentomino back to origin + def normalize(self): + pos = self.min_box() + self.translate_by([-pos[0],-pos[1]]) + return self + + def flip(self, coo): + #1 : flip along x-axis (y-values change) + #0 : flip along y-axis (x-values change) + # flip along axis of the first coordinate + flip_point = self.coos[0] #get reference point + flip_value = flip_point[coo] #get reference coordinate value + offset = 0 #how far away from reference point + for c in self.coos: + offset = c[coo] - flip_value + c[coo] = c[coo] - 2*offset + return self.normalize() + + def translate_one(self, coo): + #0: move one on x-axis + #1: move one on y-axis + for c in self.coos: + c[coo] = c[coo]+1 + return self + + def translate_coo(self, coo, amount): + for c in self.coos: + c[coo] = c[coo]+ amount + return self + + def translate_by(self, by_vector): + x_shift = by_vector[0] + y_shift = by_vector[1] + for c in self.coos: + c[0] = c[0]+ x_shift + c[1] = c[1]+ y_shift + return self + + def turn90(self): + ref_point = self.min_box() + self.translate_by([-ref_point[0],-ref_point[1]]) #move pentomino to origin + # Now turn around origin + for c in self.coos: + x = c[0] + y = c[1] + c[0] = y + c[1] = -x + self.normalize() + self.translate_by(ref_point) #move back to former position + return self.normalize() + + #returns smallest field of bounding box + def min_box(self): + min_x = self.coos[0][0] + min_y = self.coos[0][1] + for c in self.coos: + if c[0]< min_x: + min_x = c[0] + if c[1]< min_y: + min_y = c[1] + # min_x,min_y smallest field of bounding box + return [min_x,min_y] + + def max(self): + max_value = 0 + max_coos = [0,0] + for c in self.coos: + x = c[0] + y = c[1] + if max_value < x+y: + max_value = x+y + max_coos = [x,y] + return max_coos + + def __hash__(self): + ref = self.min_box() + self.translate_by([-ref[0],-ref[1]]) #move pentomino to origin + bitstring = [] + for j in range(5): + for i in range(5): + if [4-i,4-j] in self.coos: + bitstring.append('1') + else: + bitstring.append('0') + self.translate_by(ref) #move back to former position + return int(''.join(bitstring), 2) + + + #two different pentominos are equal iff they have same name and orientation + def __eq__(self, other): + return self.__hash__() == other.__hash__() + #to use the hashfunction for equality checks is only ok, because it is perfect and no collisions can happen + + def representation(self): + return "[" + self.name + ":" + str(self.coos) + "]" + + + +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + +def fixed_pentominos_of(f): + pent = TileSet() + pent.add(f) + f.turn90() + pent.add(f) + f.turn90() + pent.add(f) + f.turn90() + pent.add(f) + f.turn90() + f.flip(0) + pent.add(f) + f.turn90() + pent.add(f) + f.turn90() + pent.add(f) + f.turn90() + pent.add(f) + return pent + +def all_fixed_pentominos(): + pent = TileSet() + pent.update(fixed_pentominos_of(F())) + pent.update(fixed_pentominos_of(I())) + pent.update(fixed_pentominos_of(L())) + pent.update(fixed_pentominos_of(P())) + pent.update(fixed_pentominos_of(N())) + pent.update(fixed_pentominos_of(T())) + pent.update(fixed_pentominos_of(U())) + pent.update(fixed_pentominos_of(V())) + pent.update(fixed_pentominos_of(W())) + pent.update(fixed_pentominos_of(X())) + pent.update(fixed_pentominos_of(Y())) + pent.update(fixed_pentominos_of(Z())) + return pent + + +def all_pentominos(): + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + +#The purpose of TileSet is to store one representative of each orientation of a pentomino, in normalized coordinates. +#That is to say, two translated copies should be merged into one, but a chiral pentomino and its reflected copy should be two different elements in the set. +class TileSet(object): + def __init__(self, plist=[]): + self.set = set() + for p in plist: + self.add(p) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + present = 0 + for q in self.set: + if p==q: + present = 1 + if present == 0: + self.set.add(copy.deepcopy(p)) + + def size(self): + return len(self.set) + + def update(self,other): + self.set |= other.set + return self + + def representation(self): + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.representation()) #str(p.coos) + rep += "]" + return rep + + diff --git a/dancing_links/python/ay4me/scott.py b/dancing_links/python/ay4me/scott.py new file mode 100644 index 0000000..83c4e93 --- /dev/null +++ b/dancing_links/python/ay4me/scott.py @@ -0,0 +1,116 @@ +import pentominos +import incidence_matrix +import sys + +class Problem(object): + """The problem gets a TileSet of pentominos to work with. The range of the field to cover. + A function legal() that tests whether a set of coordinates is legal and a number how often each single tile is allowed to be used. + This number is -1 if the tiles may be used arbitrary often.""" + def __init__(self,WorkingSet,FRange,legal,usgNr,pFlip): + self.WorkingSet = WorkingSet + self.FRange = FRange + self.usgNr = usgNr + self.legal = legal + self.pFlip = pFlip + self.IncMatrix = self.createMatrix() + self.solutionList = [] + self.searchNodes = 0 + + def createMatrix(self): + """creates the columns for the matrix""" + + names = [] + for p in self.WorkingSet: + names.append(p.name) + for i in range(self.FRange): + for j in range(self.FRange): + if self.legal([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + + def completeMatrix(self): + """creates all rows""" + for p in self.WorkingSet: + if self.pFlip and p.name == "P": + tiles = pentominos.TileSet() + tiles.add(p) + p.turn90() + tiles.add(p) + p.turn90() + tiles.add(p) + p.turn90() + tiles.add(p) + p.turn90() + else: + tiles = pentominos.fixed_pentominos_of(p) + for t in tiles: + for i in range(self.FRange): + for j in range(self.FRange): + t.translate_by([i,j]) + l = True + for x in t.coos: + if not self.legal(x): + l = False + break + if l: + self.IncMatrix.appendRow(t.name,self.placement(t)) + t.translate_by([-i,-j]) + + + def placement(self,tile): + coos = tile.coos + placement = [] + for c in coos: + placement.append(str(c[0])+str(c[1])) + return placement + + def solve(self): + O = {} + self.search(0,O) + if self.solutionList != []: + print "solutions found:" + str(self.solutionList) + print "number of searchNodes:" + str(self.searchNodes) + else: + print "no solution" + + def search(self,k,O): + self.searchNodes += 1 + if self.IncMatrix.h.right is self.IncMatrix.h: + solution = "" + for i in range(k): + currentRow = O[i] + solution += "(" + currentRow.listHeader.name + "," + currentColumn = currentRow.right + while currentColumn is not currentRow: + solution += "[" + currentColumn.listHeader.name + "]," + currentColumn = currentColumn.right + solution += ")" + self.solutionList.append(solution) + return solution + else: + c = self.IncMatrix.h + s = sys.maxint + j = self.IncMatrix.h.right + while j is not self.IncMatrix.h: + if j.size < s: + c = j + s = j.size + j = j.right + self.IncMatrix.coverColumn(c) + currentRow = c.down #r + while currentRow is not c: + O[k] = currentRow + currentColumn = currentRow.right + while currentColumn is not currentRow: + self.IncMatrix.coverColumn(currentColumn.listHeader) + currentColumn = currentColumn.right + self.search(k+1,O) + currentRow = O[k] + c = currentRow.listHeader + currentColumn = currentRow.left + while currentColumn is not currentRow: + self.IncMatrix.uncoverColumn(currentColumn.listHeader) + currentColumn = currentColumn.left + currentRow = currentRow.down + self.IncMatrix.uncoverColumn(c) + return {} \ No newline at end of file diff --git a/dancing_links/python/ay4me/test.py b/dancing_links/python/ay4me/test.py new file mode 100644 index 0000000..37c44a5 --- /dev/null +++ b/dancing_links/python/ay4me/test.py @@ -0,0 +1,40 @@ +import pentominos +import copy + +# p = pentominos.Y() +# print p.representation() +# print p.__hash__() +# p2 = copy.deepcopy(p) +# p2.flip(0) +# print p2.representation() +# print p2.__hash__() +# print p.__eq__(p2) +# p.flip(1) +# print p.representation() +# print p.__hash__() +# p.flip(0) +# print p.representation() +# print p.__hash__() + + +# X = pentominos.TileSet() +# p = pentominos.I() +# X.add(copy.deepcopy(p)) +# p.flip(0) +# #p.turn90() +# X.add(copy.deepcopy(p)) +# print X.representation() + +reps = pentominos.TileSet() +p = pentominos.Y() +print reps.representation() +reps.add(p) +print reps.representation() +p.flip(0) +print reps.representation() +reps.add(p) +print reps.representation() +p.flip(1) +reps.add(p) +p.flip(0) +reps.add(p) \ No newline at end of file diff --git a/dancing_links/python/ay4me/test_incidence_matrix.py b/dancing_links/python/ay4me/test_incidence_matrix.py new file mode 100644 index 0000000..673bcc0 --- /dev/null +++ b/dancing_links/python/ay4me/test_incidence_matrix.py @@ -0,0 +1,57 @@ +import unittest +import incidence_matrix +import pentominos +import examples +import copy + +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/ay4me/test_pentominos.py b/dancing_links/python/ay4me/test_pentominos.py new file mode 100644 index 0000000..d0aabe7 --- /dev/null +++ b/dancing_links/python/ay4me/test_pentominos.py @@ -0,0 +1,79 @@ +import unittest +import pentominos +import copy + +class TestPentominoMethods(unittest.TestCase): + +# def setUp(self): + + def test_normalize(self): + for p in pentominos.all_pentominos(): + self.assertEqual(p.coos, p.normalize().coos, "test_normalize failed for polyomino " + p.name) + + def test_translate(self): + self.assertEqual([[c[0]+1,c[1]] for c in pentominos.I().coos], pentominos.I().translate_one(0).coos) + self.assertEqual([[c[0],c[1]+1] for c in pentominos.I().coos], pentominos.I().translate_one(1).coos) + + def test_TileSet(self): + s = pentominos.TileSet([pentominos.I(), pentominos.I()]) + self.assertEqual(s.size(), 1) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + self.assertEqual(reps.size(), 4) + + + def test_turn90(self): + c0 = copy.deepcopy(pentominos.I().coos) + #self.assertEqual(c0, pentominos.I().turn90().turn90().coos) + cnew = pentominos.I().turn90().turn90().coos + for c in c0: + self.assertTrue(c in cnew) + for c in cnew: + self.assertTrue(c in c0) + + p = pentominos.Y() + s = pentominos.TileSet() + for i in range(4): + s.add(p) + p.turn90() + self.assertEqual(4, s.size()) + + def test_max(self): + self.assertEqual([0,4], pentominos.I().max()) + self.assertEqual([2,2], pentominos.F().max()) + + def test_set(self): + s = set([pentominos.I(), pentominos.I()]) + self.assertEqual(len(s), 1) + + def test_fixed_pentominos(self): + orbitSize = dict() + for p in pentominos.all_pentominos(): + orbitSize[p.name] = pentominos.fixed_pentominos_of(p).size() + + self.assertEqual(dict({'F': 8, 'I': 2, 'L': 8, 'N': 8, 'P': 8, 'U': 4, 'T': 4, 'W': 4, 'V': 4, 'Y': 8, 'X': 1, 'Z': 4}), orbitSize) + self.assertEqual(pentominos.all_fixed_pentominos().size(), 63) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPentominoMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/ay4me/test_scott.py b/dancing_links/python/ay4me/test_scott.py new file mode 100644 index 0000000..6be272c --- /dev/null +++ b/dancing_links/python/ay4me/test_scott.py @@ -0,0 +1,95 @@ +import scott +import unittest +import incidence_matrix +import pentominos +import copy + +class TestScottProblem(unittest.TestCase): + +#["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + + def testSetup(self): + TSet = pentominos.TileSet([pentominos.F(),pentominos.I(),pentominos.L(),pentominos.P(),pentominos.N(),pentominos.T(),pentominos.U(),pentominos.V(),pentominos.W(),pentominos.X(),pentominos.Y(),pentominos.Z()]) + names = [p.name for p in TSet] + for n in ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"]: + self.assertTrue(n in names) + for n in names: + self.assertTrue(n in ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"]) + prob = scott.Problem(TSet,8,self.legal,1,0) + # IM = copy.deepcopy(prob.IncMatrix) + # IM.appendRow("I", ["00", "01", "02", "03", "04"]) + # IM.appendRow("I", ["01", "02", "03", "04", "05"]) + # rep = [IM.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + # self.assertEqual([[[['h(2)', 'I', 'root', 'F', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], + # [[['h(1)', '00', 'V', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], + # ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], + # [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], + # ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + # #print IM.representation() + + def testMatrix(self): + TSet = pentominos.TileSet([pentominos.F(),pentominos.I(),pentominos.L(),pentominos.P(),pentominos.N(),pentominos.T(),pentominos.U(),pentominos.V(),pentominos.W(),pentominos.Y(),pentominos.Z()]) + names = [p.name for p in TSet] + probX12 = scott.Problem(TSet,8,self.legal1,1,0) + probX13 = scott.Problem(TSet,8,self.legal2,1,0) + probX22 = scott.Problem(TSet,8,self.legal3,1,1) + str1 = probX12.IncMatrix.representation() + probX12.completeMatrix() + str2 = probX12.IncMatrix.representation() + self.assertFalse(str1 == str2) + + str1 = probX13.IncMatrix.representation() + probX13.completeMatrix() + str2 = probX13.IncMatrix.representation() + self.assertFalse(str1 == str2) + + str1 = probX22.IncMatrix.representation() + probX22.completeMatrix() + str2 = probX22.IncMatrix.representation() + self.assertFalse(str1 == str2) + + probX12.solve() + sol12 = probX12.solutionList + self.assertEqual(len(sol12),19) + #print sol12 + # if sol12 != {}: + # sol12 += "(X,[02,11,12,13,22])" #12 + + probX13.solve() + sol13 = probX13.solutionList + self.assertEqual(len(sol13),20) + #print sol13 + # if sol13 != {}: + # sol13 += "(X,[03,12,13,14,23])" #13 + + probX22.solve() + sol22 = probX22.solutionList + self.assertEqual(len(sol22),26) + # if sol22 != {}: + # sol22 += "(X,[12,21,22,23,32])" #22 + + def legal(self,coos): + if coos in [[3,3],[3,4],[4,3],[4,4]] or coos[0]<0 or coos[0]>7 or coos[1]<0 or coos[1]>7: + return False + return True + + def legal1(self,coos): + if coos in [[3,3],[3,4],[4,3],[4,4],[0,2],[1,1],[1,2],[1,3],[2,2]] or coos[0]<0 or coos[0]>7 or coos[1]<0 or coos[1]>7: + return False + return True + + def legal2(self,coos): + if coos in [[3,3],[3,4],[4,3],[4,4],[0,3],[1,2],[1,3],[1,4],[2,3]] or coos[0]<0 or coos[0]>7 or coos[1]<0 or coos[1]>7: + return False + return True + + def legal3(self,coos): + if coos in [[3,3],[3,4],[4,3],[4,4],[1,2],[2,1],[2,2],[2,3],[3,2]] or coos[0]<0 or coos[0]>7 or coos[1]<0 or coos[1]>7: + return False + return True + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestScottProblem) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/dancing_links/python/examples.py b/dancing_links/python/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/franziska_constantin/covering.py b/dancing_links/python/franziska_constantin/covering.py new file mode 100644 index 0000000..cd6322c --- /dev/null +++ b/dancing_links/python/franziska_constantin/covering.py @@ -0,0 +1,105 @@ +import incidence_matrix +import pentominos +import copy + +class Board(object): + def __init__(self, size, capacities = None): + self.size = size + self.dim = len(size) + fields = [[]] + for i in range(len(size)): + oldFields = copy.deepcopy(fields) + newFields = [] + for j in range(size[i]): + newFields.extend([f + [j] for f in oldFields]) + fields = newFields + self.capacities = dict.fromkeys([str(f) for f in fields],1) + if capacities != None: + for cap in capacities: + self.capacities[cap] = capacities[cap] + + def valid_tile_placement(self, coos): + for c in coos: + if str(c) not in self.capacities: + return False + else: + if self.capacities[str(c)] == 0: + return False + return True + + def representation(self): + return str(self.size), ', ' , str(self.capacities) + + +class Covering(object): + def __init__(self, board, tileSet, fixedTiles=dict()): + self.board = board + self.tileSet = tileSet + self.fixedTiles = fixedTiles + + def get_size(self, c): + return c.size + + def n_solutions(self): + #initialize the appropriate incidence matrix + fields = [str(c[1])+str(c[4]) for c in self.board.capacities if self.board.capacities[c] > 0] + I = incidence_matrix.IncidenceMatrix([t.name for t in self.tileSet.set] + fields + ['constraint']) #name collisions for tiles which are more than once available + tmpPent = None + for p in self.tileSet.set: + if p.name in self.fixedTiles: + for c in [coos for coos in self.fixedTiles[p.name] if self.board.valid_tile_placement(coos)]: + I.appendRow(p.name,[str(coo[0])+str(coo[1]) for coo in c]) + if c == [[1,2],[2,2],[2,1],[2,3],[3,2]]: + constraintCell = incidence_matrix.IncidenceCell(I.columnObjectOfName['X'].up.left,I.columnObjectOfName['X'].up,I.columnObjectOfName['constraint'].up,I.columnObjectOfName['constraint'], I.columnObjectOfName['constraint'],I.columnObjectOfName['X'].up.name + "_constraint") + constraintCell.left.right = constraintCell.right.left = constraintCell.up.down = constraintCell.down.up = constraintCell + else: + for q in pentominos.fixed_pentominos_of(p): + #m = q.max() + for i in range(8):#self.board.size[0]-m[0]-1): + for j in range(8):#self.board.size[1]-m[1]-1): + if self.board.valid_tile_placement(q.coos): + I.appendRow(p.name,[str(c[0])+str(c[1]) for c in q.coos]) + if 'constraint' in I.columnObjectOfName: + tmpPent = copy.deepcopy(q).normalize() + if tmpPent in [pentominos.P().flip(0), pentominos.P().flip(0).turn90(), pentominos.P().flip(0).turn90().turn90(), pentominos.P().flip(0).turn90().turn90().turn90()]: + constraintCell = incidence_matrix.IncidenceCell(I.columnObjectOfName['P'].up.left,I.columnObjectOfName['P'].up,I.columnObjectOfName['constraint'].up,I.columnObjectOfName['constraint'], I.columnObjectOfName['constraint'],I.columnObjectOfName['P'].up.name + "_constraint") + constraintCell.left.right = constraintCell.right.left = constraintCell.up.down = constraintCell.down.up = constraintCell + q.translate_one(1) + q.normalize_coo(1) + q.translate_one(0) + I.h.size = float("inf") + I.columnObjectOfName['constraint'].size = float("inf") + return self.solve(I, 0) + + def solve(self, incidences, counter): + """ recursively add a tile to a partial solution until the whole board is covered """ + #breaking point + if incidences.h.right == incidences.h or incidences.h.right == incidences.columnObjectOfName['constraint']: + return counter + 1 + #determine the column object according to the selection rule + s = float("inf") + c = incidences.h.right + j = incidences.h.right + while j != incidences.h: + if j.size < s: + c = j + s = j.size + j = j.right + #c = min(incidences.columnObjectOfName.values(),key=self.get_size) + + #recursive calls + incidences.coverColumn(c) + r = c.down + while r != c: + j = r.right + while j != r: + incidences.coverColumn(j.listHeader) + j = j.right + counter = self.solve(incidences, counter) + j = r.left + while j != r: + incidences.uncoverColumn(j.listHeader) + j = j.left + r = r.down + incidences.uncoverColumn(c) + return counter diff --git a/dancing_links/python/franziska_constantin/examples.py b/dancing_links/python/franziska_constantin/examples.py new file mode 100644 index 0000000..823c068 --- /dev/null +++ b/dancing_links/python/franziska_constantin/examples.py @@ -0,0 +1,26 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/franziska_constantin/incidence_matrix.py b/dancing_links/python/franziska_constantin/incidence_matrix.py new file mode 100644 index 0000000..a0b3c1f --- /dev/null +++ b/dancing_links/python/franziska_constantin/incidence_matrix.py @@ -0,0 +1,151 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + """ insert a column header object into the circular linked list that contains the "root" node """ + co = ColumnObject(left,right,None,None,name) + co.up = co.down = left.right = right.left = co + + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + tileCell = IncidenceCell(None,None, self.columnObjectOfName[tileName].up, self.columnObjectOfName[tileName], self.columnObjectOfName[tileName], tileName + "["+ str(self.indexOfPiecePlacement[tileName]) + "]") + self.indexOfPiecePlacement[tileName] += 1 + self.columnObjectOfName[tileName].size += 1 + tileCell.left = tileCell.right = tileCell.down.up = tileCell.up.down = tileCell + for coo in sorted(placement): + cooCell = IncidenceCell(tileCell.left, tileCell, self.columnObjectOfName[str(coo)].up, self.columnObjectOfName[str(coo)], self.columnObjectOfName[str(coo)], tileName + str(coo)) + cooCell.down.up = cooCell.up.down = cooCell.left.right = cooCell.right.left = cooCell + self.columnObjectOfName[str(coo)].size += 1 + self.rows += 1 + + + def coverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + + #adjust links of the column objects + c.left.right = c.right + c.right.left = c.left + + #adjust all links in IncidenceCells which are in a row of c + currRowCell = c.down + while currRowCell != c: + currColCell = currRowCell.right + while currColCell != currRowCell: + currColCell.down.up = currColCell.up + currColCell.up.down = currColCell.down + currColCell.listHeader.size -= 1 + currColCell = currColCell.right + currRowCell = currRowCell.down + + def uncoverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + + #adjust all links in IncidenceCells which are in a row of c + currRowCell = c.up + while currRowCell != c: + currColCell = currRowCell.left + while currColCell != currRowCell: + currColCell.down.up = currColCell + currColCell.up.down = currColCell + currColCell.listHeader.size += 1 + currColCell = currColCell.left + currRowCell = currRowCell.up + + #adjust links of the column objects + c.left.right = c + c.right.left = c diff --git a/dancing_links/python/franziska_constantin/pentominos.py b/dancing_links/python/franziska_constantin/pentominos.py new file mode 100644 index 0000000..c344dd6 --- /dev/null +++ b/dancing_links/python/franziska_constantin/pentominos.py @@ -0,0 +1,169 @@ +import copy + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + + def normalize_coo(self, coo): + if coo == 0: + self.translate_by([-min([c[0] for c in self.coos]),0]) + else: + self.translate_by([0,-min([c[1] for c in self.coos])]) + + + def normalize(self): + self.translate_by([-min([c[0] for c in self.coos]),-min([c[1] for c in self.coos])]) + return self + + def flip(self, coo): + if coo == 0: + self.coos = [[c[0],-c[1]] for c in self.coos] + else: + self.coos = [[-c[0],c[1]] for c in self.coos] + self.normalize() + return self + + def translate_one(self, coo): + if coo == 0: + self.coos = [[c[0]+1,c[1]] for c in self.coos] + else: + self.coos = [[c[0],c[1]+1] for c in self.coos] + return self + + def translate_coo(self, coo, amount): + if coo == 0: + self.coos = [[c[0]+amount,c[1]] for c in self.coos] + else: + self.coos = [[c[0],c[1]+amount] for c in self.coos] + return self + + def translate_by(self, by_vector): + self.coos = [[c[0]+by_vector[0],c[1]+by_vector[1]] for c in self.coos] + return self + + def turn90(self): + self.coos = [[-c[1],c[0]] for c in self.coos] + self.normalize() + return self + + def max(self): + return [max([c[0] for c in self.coos]), max([c[1] for c in self.coos])] + + + def __hash__(self): + self.coos = sorted(self.coos) + return hash(str(self.coos)) + + def __eq__(self, other): + self.normalize() + other.normalize() + return self.__hash__() == other.__hash__() + + def representation(self): + return "[" + self.name + ":" + str(self.coos) + "]" + + +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + + +def all_pentominos(): + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + +def fixed_pentominos_of(p): + fp = TileSet() + for i in range(4): + p.turn90() + fp.add(p) + p.flip(0) + fp.add(p) + p.flip(0) + return fp + +def all_fixed_pentominos(): + plist = [] + for p in all_pentominos(): + plist += fixed_pentominos_of(p) + return TileSet(plist) + +class TileSet(object): + def __init__(self, plist=[], stock=None): + self.set = set() + for p in plist: + self.add(p) + if stock == None: + self.stock = dict.fromkeys([p.name for p in plist],1) + else: + self.stock = stock + self.stock.update(dict.fromkeys([p.name for p in plist if p.name not in self.stock],0)) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + self.set.add(copy.deepcopy(p)) #not desirable + return self + + def size(self): + return len(self.set) + + def representation(self): + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep + + diff --git a/dancing_links/python/franziska_constantin/test_covering.py b/dancing_links/python/franziska_constantin/test_covering.py new file mode 100644 index 0000000..0791617 --- /dev/null +++ b/dancing_links/python/franziska_constantin/test_covering.py @@ -0,0 +1,36 @@ +import unittest +import pentominos +import covering +import examples +import copy + +class TestCoveringMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_Board_init(self): + B = covering.Board([3,2,2], {'[0, 1, 1]': 0, '[2, 1, 0]':5, '[1, 1, 1]': 2}) + #self.assertEqual([3,5,str([[0,0],[0,1],[0,2],[0,3],[0,4],[1,0],[1,3],[1,4],[2,0],[2,1],[2,3],[2,4]])], [T.rows, T.cols, T.representation()]) + + def test_Board_valid_tile_placement(self): + B = covering.Board([8,8],{'[3, 3]': 0,'[3, 4]': 0,'[4, 3]': 0,'[4, 4]': 0}) + self.assertEqual(False, B.valid_tile_placement([[3,2],[3,3],[3,4],[3,5],[3,6]])) + + #def test_covering_init(self): + #B = covering.Board(8,8,[[3,3],[3,4],[4,3],[4,4]]) + #C = covering.Covering(B,covering.TileSet(pentominos.all_pentominos()),[]) + + def test_covering_n_solutions(self): + B = covering.Board([8,8],{'[3, 3]': 0,'[3, 4]': 0,'[4, 3]': 0,'[4, 4]': 0}) + C = covering.Covering(B,pentominos.TileSet(pentominos.all_pentominos()),{'X': [[[0,2],[1,2],[1,1],[1,3],[2,2]]]}) + self.assertEqual(19, C.n_solutions()) + C = covering.Covering(B,pentominos.TileSet(pentominos.all_pentominos()),{'X': [[[0,3],[1,3],[1,2],[1,4],[2,3]]]}) + self.assertEqual(20, C.n_solutions()) + C = covering.Covering(B,pentominos.TileSet(pentominos.all_pentominos()),{'X': [[[1,2],[2,2],[2,1],[2,3],[3,2]]]}) + self.assertEqual(26, C.n_solutions()) + + + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/franziska_constantin/test_incidence_matrix.py b/dancing_links/python/franziska_constantin/test_incidence_matrix.py new file mode 100644 index 0000000..673bcc0 --- /dev/null +++ b/dancing_links/python/franziska_constantin/test_incidence_matrix.py @@ -0,0 +1,57 @@ +import unittest +import incidence_matrix +import pentominos +import examples +import copy + +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/franziska_constantin/test_pentominos.py b/dancing_links/python/franziska_constantin/test_pentominos.py new file mode 100644 index 0000000..f029cfa --- /dev/null +++ b/dancing_links/python/franziska_constantin/test_pentominos.py @@ -0,0 +1,77 @@ +import unittest +import pentominos +import copy + +class TestPentominoMethods(unittest.TestCase): + + # def setUp(self): + + def test_normalize(self): + for p in pentominos.all_pentominos(): + self.assertEqual(p.coos, p.normalize().coos, "test_normalize failed for polyomino " + p.name) + + def test_translate(self): + self.assertEqual([[c[0]+1,c[1]] for c in pentominos.I().coos], pentominos.I().translate_one(0).coos) + self.assertEqual([[c[0],c[1]+1] for c in pentominos.I().coos], pentominos.I().translate_one(1).coos) + + def test_TileSet(self): + s = pentominos.TileSet([pentominos.I(), pentominos.I()]) + self.assertEqual(s.size(), 1) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet() + p = pentominos.Y() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + p.turn90() + reps.add(p) + self.assertEqual(reps.size(), 4) + + reps = pentominos.TileSet([pentominos.I(),pentominos.X()],{'I': 3}) + self.assertEqual({'I': 3, 'X': 0},reps.stock) + + + def test_turn90(self): + c0 = copy.deepcopy(pentominos.I().coos) + self.assertEqual(c0, sorted(pentominos.I().turn90().turn90().coos)) + + p = pentominos.Y() + s = pentominos.TileSet() + for i in range(4): + s.add(p) + p.turn90() + self.assertEqual(4, s.size()) + + def test_max(self): + self.assertEqual([0,4], pentominos.I().max()) + self.assertEqual([2,2], pentominos.F().max()) + + def test_set(self): + s = set([pentominos.I(), pentominos.I()]) + self.assertEqual(len(s), 1) + + def test_fixed_pentominos(self): + orbitSize = dict() + for p in pentominos.all_pentominos(): + orbitSize[p.name] = pentominos.fixed_pentominos_of(p).size() + + self.assertEqual(dict({'F': 8, 'I': 2, 'L': 8, 'N': 8, 'P': 8, 'U': 4, 'T': 4, 'W': 4, 'V': 4, 'Y': 8, 'X': 1, 'Z': 4}), orbitSize) + self.assertEqual(pentominos.all_fixed_pentominos().size(), 63) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestPentominoMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/incidence_matrix.py b/dancing_links/python/incidence_matrix.py new file mode 100644 index 0000000..9b0f9ed --- /dev/null +++ b/dancing_links/python/incidence_matrix.py @@ -0,0 +1,112 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + """ insert a column header object into the circular linked list that contains the "root" node """ + pass + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + pass + + def coverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + pass + + def uncoverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + pass \ No newline at end of file diff --git a/dancing_links/python/neosonea/examples.py b/dancing_links/python/neosonea/examples.py new file mode 100644 index 0000000..3625806 --- /dev/null +++ b/dancing_links/python/neosonea/examples.py @@ -0,0 +1,40 @@ +import incidence_matrix + +def running_example(): + I = incidence_matrix.IncidenceMatrix(["A", "B", "C", "D", "E", "F", "G"]) + I.appendRow("C", ["E", "F"]) + I.appendRow("A", ["D", "G"]) + I.appendRow("B", ["C", "F"]) + I.appendRow("A", ["D"]) + I.appendRow("B", ["G"]) + I.appendRow("D", ["E", "G"]) + return I + +def AllowOutsideHole(c): + if c not in [[3,3],[3,4],[4,3],[4,4]]: + return True + else: + return False + +def scott_example(): + names = ["F", "I", "L", "P", "N", "T", "U", "V", "W", "X", "Y", "Z"] + for i in range(8): + for j in range(8): + if AllowOutsideHole([i,j]): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + +def little_example(): + names = ["L","U","V","Y"] + for i in range(5): + for j in range(4): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + +def little_quadratic_example(): + names = ["I","L","U","V","Y"] + for i in range(5): + for j in range(5): + names.append(str(i)+str(j)) + return incidence_matrix.IncidenceMatrix(names) + diff --git a/dancing_links/python/neosonea/incidence_matrix.py b/dancing_links/python/neosonea/incidence_matrix.py new file mode 100644 index 0000000..7fccb9d --- /dev/null +++ b/dancing_links/python/neosonea/incidence_matrix.py @@ -0,0 +1,183 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + def rowRep(self): + rep = "row " + self.name + "," + curr = self.right + while curr != self: + rep += curr.name + "," + curr = curr.right + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = "" + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep += str(row) + "\n" + #rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + """ insert a column header object into the circular linked list that contains the "root" node """ + def insertColumnObject(self, left, right, name): + newCO = ColumnObject(left, right, None, None, name) + newCO.up = newCO.down = newCO + left.right = newCO + right.left = newCO + return newCO + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + pentoHeader = self.columnObjectOfName[tileName] + # create pentoCell + pentoCell = IncidenceCell(None, None, pentoHeader.up, pentoHeader, pentoHeader, + tileName+"["+str(self.indexOfPiecePlacement[tileName])+"]") + pentoHeader.up.down = pentoCell + pentoHeader.up = pentoCell + pentoHeader.size = pentoHeader.size + 1 + self.indexOfPiecePlacement[tileName] += 1 + + # create placementCells + left = pentoCell + for placeName in placement: + placeHeader = self.columnObjectOfName[placeName] + placementCell = IncidenceCell(left, None, placeHeader.up, + placeHeader, placeHeader, tileName+placeName) + placeHeader.up.down = placementCell + placeHeader.up = placementCell + placeHeader.size = placeHeader.size + 1 + left.right = placementCell + left = placementCell + + left.right = pentoCell + pentoCell.left = left + + self.rows = self.rows + 1 + #return self + + def coverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + # cover head c vertically + c.left.right = c.right + c.right.left = c.left + + # go through all rows in which c had a cell + rowhead = c.down + while rowhead is not c: + cell = rowhead.right + while cell is not rowhead: + # cover the cells horizontally in these rows + cell.up.down = cell.down + cell.down.up = cell.up + cell.listHeader.size -= 1 + cell = cell.right + self.rows -= 1 + rowhead = rowhead.down + #return self + + def uncoverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + # uncover head c vertically + c.left.right = c + c.right.left = c + + # go through all rows in which c had a cell + rowhead = c.up + while rowhead is not c: + cell = rowhead.right + while cell is not rowhead: + # uncover the cells horizontally in these rows + cell.up.down = cell + cell.down.up = cell + cell.listHeader.size += 1 + cell = cell.right + self.rows += 1 + rowhead = rowhead.up + #return self + diff --git a/dancing_links/python/neosonea/pentominos.py b/dancing_links/python/neosonea/pentominos.py new file mode 100644 index 0000000..9b1a55c --- /dev/null +++ b/dancing_links/python/neosonea/pentominos.py @@ -0,0 +1,195 @@ +import copy + +class Pentomino(object): + def __init__(self, name, coos): + self.name = name + self.coos = coos + self.dim = len(coos[0]) + + def normalize_coo(self, coo): + coo_min = self.coos[0][coo] + for i in range(1,len(self.coos)): + if coo_min > self.coos[i][coo]: + coo_min = self.coos[i][coo] + self.translate_coo(coo, -coo_min) + return self + + def normalize(self): + for coo in range(self.dim): + self.normalize_coo(coo) + self.coos.sort() + return self + + def flip(self, coo): + for i in range(len(self.coos)): + self.coos[i][(coo+1)%2] = - self.coos[i][(coo+1)%2]; + self.normalize() + return self + + def translate_one(self, coo): + for i in range(len(self.coos)): + self.coos[i][coo] = self.coos[i][coo] + 1; + return self + + def translate_coo(self, coo, amount): + for i in range(len(self.coos)): + self.coos[i][coo] = self.coos[i][coo] + amount; + return self + + def translate_by(self, by_vector): + for i in range(len(self.coos)): + for coo in range(self.dim): + self.coos[i][coo] = self.coos[i][coo] + by_vector[coo]; + return self + + def turn90(self): + x = 0 + for i in range(len(self.coos)): + x = self.coos[i][0] + self.coos[i][0] = - self.coos[i][1] + self.coos[i][1] = x + self.normalize() + return self + + def max(self): + compmax = self.coos[len(self.coos) - 1] + for coo in range(self.dim): + for i in range(len(self.coos) - 1): + if compmax[coo] < self.coos[i][coo]: + compmax[coo] = self.coos[i][coo] + return compmax + + def __hash__(self): + self.coos.sort() + hashstr = "" + #TODO padding for coos bigger than 9 + for i in range(len(self.coos)): + for coo in range(self.dim): + hashstr += str(self.coos[i][coo]) + return int(hashstr) + + def __eq__(self, other): + if self.dim != other.dim or self.name != other.name or len(self.coos) != len(other.coos): + return False + #return hash(self) == hash(other) + for i in range(len(self.coos)): + j = 0 + i_eq_j = False + while (not i_eq_j) and j < len(self.coos): + i_eq_j = True + for coo in range(self.dim): + if self.coos[i][coo] != other.coos[j][coo]: + i_eq_j = False + break + j = j + 1 + + if i_eq_j == False: + return False + return True + + def representation(self): + return "[" + self.name + ":" + str(self.coos) + "]" + + +class F(Pentomino): + def __init__(self): + Pentomino.__init__(self, "F", [[0,1],[1,0],[1,1],[1,2],[2,2]]) + +class I(Pentomino): + def __init__(self): + Pentomino.__init__(self, "I", [[0,0],[0,1],[0,2],[0,3],[0,4]]) + +class L(Pentomino): + def __init__(self): + Pentomino.__init__(self, "L", [[0,0],[0,1],[0,2],[0,3],[1,0]]) + +class N(Pentomino): + def __init__(self): + Pentomino.__init__(self, "N", [[0,0],[0,1],[1,1],[1,2],[1,3]]) + +class P(Pentomino): + def __init__(self): + Pentomino.__init__(self, "P", [[0,0],[0,1],[0,2],[1,1],[1,2]]) + +class T(Pentomino): + def __init__(self): + Pentomino.__init__(self, "T", [[0,2],[1,0],[1,1],[1,2],[2,2]]) + +class U(Pentomino): + def __init__(self): + Pentomino.__init__(self, "U", [[0,0],[0,1],[1,0],[2,0],[2,1]]) + +class V(Pentomino): + def __init__(self): + Pentomino.__init__(self, "V", [[0,0],[1,0],[2,0],[2,1],[2,2]]) + +class W(Pentomino): + def __init__(self): + Pentomino.__init__(self, "W", [[0,0],[1,0],[1,1],[2,1],[2,2]]) + +class X(Pentomino): + def __init__(self): + Pentomino.__init__(self, "X", [[0,1],[1,0],[1,1],[1,2],[2,1]]) + +class Y(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Y", [[0,0],[1,0],[2,0],[2,1],[3,0]]) + +class Z(Pentomino): + def __init__(self): + Pentomino.__init__(self, "Z", [[0,2],[1,0],[1,1],[1,2],[2,0]]) + + +def all_pentominos(): + return [F(), I(), L(), P(), N(), T(), U(), V(), W(), X(), Y(), Z()] + +def fixed_pentominos_of(p): + reps = TileSet() + for i in range(4): + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + reps.add(p) + p.flip(0) + reps.add(p) + p.flip(1) + + p.turn90() + return reps + +def all_fixed_pentominos(): + reps = TileSet() + for p in all_pentominos(): + for fixp in fixed_pentominos_of(p): + reps.add(fixp) + return reps + +class TileSet(object): + def __init__(self, plist=[]): + self.set = set() + for p in plist: + self.add(p) + + def __iter__(self): + return iter(self.set) + + def add(self, p): + self.set.add( copy.deepcopy(p) ) + + def size(self): + return len(self.set) + + def representation(self): + rep = "[" + i = 0 + for p in self.set: + if i>0: + rep += "," + else: + i = 1 + rep += str(p.coos) + rep += "]" + return rep + + diff --git a/dancing_links/python/neosonea/scott_matrix.py b/dancing_links/python/neosonea/scott_matrix.py new file mode 100644 index 0000000..19c0bcb --- /dev/null +++ b/dancing_links/python/neosonea/scott_matrix.py @@ -0,0 +1,90 @@ +import pentominos +import incidence_matrix +import examples +import copy + +class Scott_matrix(object): + def __init__(self, width, height): + self.width = 8; + self.height = 8; + self.solution = dict() + + self.noSolutions = 0 + + + def create_scott_matrix(self, legal): + self.IM = examples.scott_example() + + for p in pentominos.all_fixed_pentominos(): +# if p.name in ["I","L","U","V","Y"]:#TODO remove + self.create_all_rows_for(p, legal) + self.solve_scott_matrix() + return self.IM + + def solve_scott_matrix(self): + self.search(0) + print("#sol="+str(self.noSolutions)) + + def search(self, i): + if self.IM.h.right == self.IM.h: + #TODO solution found + #print("\none solution is") + #for j in range(i): + # print(str(self.solution[j].rowRep())) + self.noSolutions += 1 + return + #search column with min possibilities + minPossibilities = curr = self.IM.h.right + while curr != self.IM.h: + if curr.size < minPossibilities.size: + minPossibilities = curr + curr = curr.right + + #cover c + self.IM.coverColumn(minPossibilities) + #start deeper search (play all scenarios, where c could be placed. one after another) + currPlace = minPossibilities.down + while currPlace != minPossibilities: + + self.solution[i] = currPlace + #cover places, which are blocked now + curr = currPlace.right + while curr != currPlace: + self.IM.coverColumn(curr.listHeader) + curr = curr.right + + self.search(i+1) + + #uncover curr + curr = currPlace.left + while curr != currPlace: + self.IM.uncoverColumn(curr.listHeader) + curr = curr.left + currPlace = currPlace.down + + #uncover c + self.IM.uncoverColumn(minPossibilities) + + def create_all_rows_for(self, p, legal): + #p.normalize(); + for i in range(self.width): + for j in range(self.height): + if legal(copy.deepcopy(p)): + #placement = [] + #for pos in p.coos: + # placement.append(str(pos[0])+str(pos[1])) + #print(" p"+p.name+" ij="+str(i)+str(j)+" "+str([str(pos[0])+str(pos[1]) for pos in p.coos])) + #self.IM.appendRow(p.name, placement) #([[c[0]+1,c[1]] for c in pentominos.I().coos] + self.IM.appendRow(p.name, [str(pos[0])+str(pos[1]) for pos in p.coos]) + p.translate_one(1); + p.normalize_coo(1); + p.translate_one(0); + + def scott_legal(self, p): + for hole in [ [3,3],[3,4],[4,3],[4,4] ]: + if hole in p.coos: + return False + if p.max()[0] > self.width-1 or p.max()[1] > self.height-1: + return False; + return True + diff --git a/dancing_links/python/neosonea/test_create_matrix.py b/dancing_links/python/neosonea/test_create_matrix.py new file mode 100644 index 0000000..420579c --- /dev/null +++ b/dancing_links/python/neosonea/test_create_matrix.py @@ -0,0 +1,42 @@ +import unittest +import incidence_matrix +import pentominos +import examples +import copy +import scott_matrix + +class TestScottMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_creating_scott_matrix(self): + IM = scott_matrix.Scott_matrix(8,8) + IM.create_scott_matrix(IM.scott_legal) + #IM = scott_matrix.create_matrix() + #I.appendRow("I", ["00", "01", "02", "03", "04"]) + #I.appendRow("I", ["01", "02", "03", "04", "05"]) + #rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + #self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + origRep = I.representation() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + for n in ["G", "D", "A"]: + I.uncoverColumn(I.columnObjectOfName[n]) + + self.assertEqual(origRep, I.representation()) + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestScottMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/neosonea/test_incidence_matrix.py b/dancing_links/python/neosonea/test_incidence_matrix.py new file mode 100644 index 0000000..673bcc0 --- /dev/null +++ b/dancing_links/python/neosonea/test_incidence_matrix.py @@ -0,0 +1,57 @@ +import unittest +import incidence_matrix +import pentominos +import examples +import copy + +class TestIncidenceMatrixMethods(unittest.TestCase): + + def setUp(self): + pass + + def test_init(self): + I = incidence_matrix.IncidenceMatrix(["0", "1", "2"]) + self.assertEqual([[['h(0)', 'root', '2', '0', 'root', 'root']], [['h(0)', '0', 'root', '1', '0', '0']], [['h(0)', '1', '0', '2', '1', '1']], [['h(0)', '2', '1', 'root', '2', '2']]], I.representation()) + + def test_append_one_row(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(1)', 'I', 'F', 'L', 'I[0]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(1)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', '01']]], [[['h(1)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', '02']]], [[['h(1)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', '03']]], [[['h(1)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', '04']]]], rep) + + + def test_append_two_rows(self): + I = examples.scott_example() + I.appendRow("I", ["00", "01", "02", "03", "04"]) + I.appendRow("I", ["01", "02", "03", "04", "05"]) + rep = [I.columnObjectOfName[i].representation() for i in ["I", "00", "01", "02", "03", "04"]] + self.assertEqual([[[['h(2)', 'I', 'F', 'L', 'I[1]', 'I[0]'], ['c', 'I[0]', 'I04', 'I00', 'I', 'I[1]'], ['c', 'I[1]', 'I05', 'I01', 'I[0]', 'I']]], [[['h(1)', '00', 'Z', '01', 'I00', 'I00'], ['c', 'I00', 'I[0]', 'I01', '00', '00']]], [[['h(2)', '01', '00', '02', 'I01', 'I01'], ['c', 'I01', 'I00', 'I02', '01', 'I01'], ['c', 'I01', 'I[1]', 'I02', 'I01', '01']]], [[['h(2)', '02', '01', '03', 'I02', 'I02'], ['c', 'I02', 'I01', 'I03', '02', 'I02'], ['c', 'I02', 'I01', 'I03', 'I02', '02']]], [[['h(2)', '03', '02', '04', 'I03', 'I03'], ['c', 'I03', 'I02', 'I04', '03', 'I03'], ['c', 'I03', 'I02', 'I04', 'I03', '03']]], [[['h(2)', '04', '03', '05', 'I04', 'I04'], ['c', 'I04', 'I03', 'I[0]', '04', 'I04'], ['c', 'I04', 'I03', 'I05', 'I04', '04']]]], rep) + + def test_construct_running_example(self): + I = examples.running_example() + origRep = [[['h(0)', 'root', 'G', 'A', 'root', 'root']], [['h(2)', 'A', 'root', 'B', 'A[1]', 'A[0]'], ['c', 'A[0]', 'AG', 'AD', 'A', 'A[1]'], ['c', 'A[1]', 'AD', 'AD', 'A[0]', 'A']], [['h(2)', 'B', 'A', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(3)', 'D', 'C', 'E', 'D[0]', 'AD'], ['c', 'AD', 'A[0]', 'AG', 'D', 'AD'], ['c', 'AD', 'A[1]', 'A[1]', 'AD', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'AD', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(3)', 'G', 'F', 'root', 'DG', 'AG'], ['c', 'AG', 'AD', 'A[0]', 'G', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'AG', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]] + self.assertEqual(origRep, I.representation()) + + def test_cover_running_example(self): + I = examples.running_example() + origRep = I.representation() + I.coverColumn(I.columnObjectOfName["A"]) + self.assertEqual([[['h(0)', 'root', 'G', 'B', 'root', 'root']], [['h(2)', 'B', 'root', 'C', 'B[1]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B[1]'], ['c', 'B[1]', 'BG', 'BG', 'B[0]', 'B']], [['h(2)', 'C', 'B', 'D', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'D', 'C', 'E', 'D[0]', 'D[0]'], ['c', 'D[0]', 'DG', 'DE', 'D', 'D']], [['h(2)', 'E', 'D', 'F', 'DE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'DE'], ['c', 'DE', 'D[0]', 'DG', 'CE', 'E']], [['h(2)', 'F', 'E', 'G', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']], [['h(2)', 'G', 'F', 'root', 'DG', 'BG'], ['c', 'BG', 'B[1]', 'B[1]', 'G', 'DG'], ['c', 'DG', 'DE', 'D[0]', 'BG', 'G']]], I.representation()) + + I.uncoverColumn(I.columnObjectOfName["A"]) + self.assertEqual(origRep, I.representation()) + + def test_cover_3_running_example(self): + I = examples.running_example() + for n in ["A", "D", "G"]: + I.coverColumn(I.columnObjectOfName[n]) + + self.assertEqual([[['h(0)', 'root', 'F', 'B', 'root', 'root']], [['h(1)', 'B', 'root', 'C', 'B[0]', 'B[0]'], ['c', 'B[0]', 'BF', 'BC', 'B', 'B']], [['h(2)', 'C', 'B', 'E', 'BC', 'C[0]'], ['c', 'C[0]', 'CF', 'CE', 'C', 'BC'], ['c', 'BC', 'B[0]', 'BF', 'C[0]', 'C']], [['h(1)', 'E', 'C', 'F', 'CE', 'CE'], ['c', 'CE', 'C[0]', 'CF', 'E', 'E']], [['h(2)', 'F', 'E', 'root', 'BF', 'CF'], ['c', 'CF', 'CE', 'C[0]', 'F', 'BF'], ['c', 'BF', 'BC', 'B[0]', 'CF', 'F']]], I.representation()) + + + + +suite = unittest.TestLoader().loadTestsFromTestCase(TestIncidenceMatrixMethods) + +if __name__ == '__main__': + unittest.main() diff --git a/dancing_links/python/neosonea/test_pentominos.py b/dancing_links/python/neosonea/test_pentominos.py new file mode 120000 index 0000000..75a9ab7 --- /dev/null +++ b/dancing_links/python/neosonea/test_pentominos.py @@ -0,0 +1 @@ +../test_pentominos.py \ No newline at end of file diff --git a/dancing_links/python/pentominos.py b/dancing_links/python/pentominos.py index 99c91bf..9fc344f 100644 --- a/dancing_links/python/pentominos.py +++ b/dancing_links/python/pentominos.py @@ -8,7 +8,7 @@ def __init__(self, name, coos): def normalize_coo(self, coo): pass - +#hallowelt def normalize(self): pass diff --git a/dancing_links/python/test_incidence_matrix.py b/dancing_links/python/test_incidence_matrix.py new file mode 100644 index 0000000..64834d4 --- /dev/null +++ b/dancing_links/python/test_incidence_matrix.py @@ -0,0 +1,116 @@ +def is_number(string): + try: + float(string) + return True + except ValueError: + pass + return False + + +class IncidenceCell(object): + def __init__(self, left, right, up, down, listHeader, name): + self.left = left + self.right = right + self.up = up + self.down = down + self.listHeader = listHeader + self.name = name + + def representation(self): + rep = ["c", self.name] + for c in [self.left, self.right, self.up, self.down]: + rep.append(c.name) + return rep + + +class ColumnObject(IncidenceCell): + def __init__(self, left, right, up, down, name): + IncidenceCell.__init__(self, left, right, up, down, self, name) + self.size = 0 + + def representation(self): + hrep = ["h(" + str(self.size) + ")", self.name] + for c in [self.left, self.right, self.up, self.down]: + hrep.append(c.name) + rep = [[hrep]] + + currentCell = self.down + while currentCell is not self: + rep[0].append(currentCell.representation()) + currentCell = currentCell.down + + return rep + + +class IncidenceMatrix(object): + def __init__(self, names): + self.h = ColumnObject(None, None, None, None, "root") + self.h.left = self.h.right = self.h.up = self.h.down = self.h + + currentColumnObject = self.h + self.columnObjectOfName = dict() + self.columnObjectOfName["root"] = self.h + + self.indexOfPiecePlacement = dict() + for n in names: + self.indexOfPiecePlacement[n] = 0 + self.insertColumnObject(currentColumnObject, self.h, n) + currentColumnObject = currentColumnObject.right + self.columnObjectOfName[n] = currentColumnObject + + self.rows = 0 + + def representation(self): + currentColumnObject = self.h + + rep = currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + while currentColumnObject.name is not "root": + rep += currentColumnObject.representation() + currentColumnObject = currentColumnObject.right + + return rep + + def rowRepresentation(self): + rowRep = [] + currentColumnObject = self.h.right + while currentColumnObject.name is not "root" and not is_number(currentColumnObject.name): + head_elt = currentColumnObject.down + while head_elt is not currentColumnObject: + row = [ head_elt.name ] + current_elt = head_elt.right + while current_elt is not head_elt: + row.append(current_elt.listHeader.name) + current_elt = current_elt.right + rowRep.append(row) + head_elt = head_elt.down + currentColumnObject = currentColumnObject.right + return rowRep + + def insertColumnObject(self, left, right, name): + """ insert a column header object into the circular linked list that contains the "root" node """ + pass + + def appendRow(self, tileName, placement): + """ + a placement is a list of coordinates that indicates which squares the piece named `tileName` covers. + This function appends a row to the incidence matrix. A row consists of + - one IncidenceCell in the column corresponding to tileName + - one IncidenceCell in each column corresponding to a coordinate in `placement`. + These must be assembled into a circularly linked list, and each cell must be inserted into the + circular linked list of its corresponding column. + """ + pass + + def coverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + pass + + def uncoverColumn(self, c): + """ implement and document the algorithm in Knuth's paper. """ + pass + +if __name__ == '__main__': + unittest.main() + diff --git a/gpg_keys/Anne-Sophie Himmel anne-sophie@mailbox.tu-berlin.de (0x9BDC2E0E) pub.asc b/gpg_keys/Anne-Sophie Himmel anne-sophie@mailbox.tu-berlin.de (0x9BDC2E0E) pub.asc new file mode 100644 index 0000000..660b49c --- /dev/null +++ b/gpg_keys/Anne-Sophie Himmel anne-sophie@mailbox.tu-berlin.de (0x9BDC2E0E) pub.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +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 +=ac9/ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/gpg_keys/Constantin Fischer fischer@math.tu-berlin.de (0x58050E41) pub.asc b/gpg_keys/Constantin Fischer fischer@math.tu-berlin.de (0x58050E41) pub.asc new file mode 100644 index 0000000..583583c --- /dev/null +++ b/gpg_keys/Constantin Fischer fischer@math.tu-berlin.de (0x58050E41) pub.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +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 +PnYJwQA0hJWtrJBnTP7kAz5Q+824rHm3sQ== +=a6TV +-----END PGP PUBLIC KEY BLOCK----- diff --git a/gpg_keys/Julian Pfeifle (UPC) julian.pfeifle@upc.edu (0xE5CA3BE5) pub.asc b/gpg_keys/Julian Pfeifle (UPC) julian.pfeifle@upc.edu (0xE5CA3BE5) pub.asc new file mode 100644 index 0000000..95cedb7 --- /dev/null +++ b/gpg_keys/Julian Pfeifle (UPC) julian.pfeifle@upc.edu (0xE5CA3BE5) pub.asc @@ -0,0 +1,241 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.22 (GNU/Linux) + +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 +Z0B+UHhXlGGR +=k7kX +-----END PGP PUBLIC KEY BLOCK----- diff --git a/gpg_keys/Public_key_Raoul_Schikora.asc b/gpg_keys/Public_key_Raoul_Schikora.asc new file mode 100644 index 0000000..135acbd --- /dev/null +++ b/gpg_keys/Public_key_Raoul_Schikora.asc @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +mQENBFVTfZ4BCACsOvlfgW+AehEdUBxvAoo6E1zC0cUbvrf22ROzUToiroU/8GNU +zenPQlQqj/KkIqX/tUhmr9f30I1cZPyjdjJ3FTv7Dz6M9CgxsGwFlpAWUmTdPmHH +YHu6xIRhEZmsDaqu2Bx99ijoJhknU8D0p/NAB/vKs9rF47C+80SGU/Jehi2FNptk +chEdBZap5ECIg0W9dkkssCIlTn752mtrFld6EF/TDhsPr1RYovmAo+HotIBr5UTs +8RvMdLqQN2ezT6qMaDwNviWZbGE+seAMbGr8k/yc8nCgUhfYaiavjAA4YhXmI/t8 +BNODRsY0UnF8G1jVos7bF6zLrzA5vQtdlHMZABEBAAG0KFJhb3VsIFNjaGlrb3Jh +IDxyYW91bHNjaGlrb3JhQGdtYWlsLmNvbT6JATkEEwEIACMFAlVTfZ4CGw8HCwkI +BwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRDCWGoi3a/5HmbbB/wMAfVGIbPYaAbq +xqamh+d4GFjpm1J80KYSeN3iDy6gGkh2Q16SLhTrIPEwjZ+D2QKKTKqT6AU0xDk2 +1FOHqOY5MS2OwcR8q9tzwdhUENdh40pCYFcJT3aug02G3B/LtYT7uEVBbokgmksR +5eB/Fwq7GkwzixOTW5EI1iqOZ6pmBPfrhibs6REal4urtTDUncQeLbovNIT7HmxU +fghs30Fw/ecaSVUweuzGO4K2ktNTY1uPGz92wmhjjb8EqODwBNgWJW5jdCh328B6 +0+nzmng+EKfkjRe9kvO5eq5tbIEbZ82fby4Ka01YCKkPX6vRq82V46i0HIMJlPl1 +7Sq1CyFd +=vrK5 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/gpg_keys/Public_key_Robert_Loewe b/gpg_keys/Public_key_Robert_Loewe new file mode 100644 index 0000000..fa460fe --- /dev/null +++ b/gpg_keys/Public_key_Robert_Loewe @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: GPGTools - https://gpgtools.org + +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 +BKQxr7CkDOSX2tVIylORr7rW +=DOH+ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/gpg_keys/Sabine Weingarten sweingarten@gmx.net (0x3712C0A6) pub.asc b/gpg_keys/Sabine Weingarten sweingarten@gmx.net (0x3712C0A6) pub.asc new file mode 100644 index 0000000..935c428 --- /dev/null +++ b/gpg_keys/Sabine Weingarten sweingarten@gmx.net (0x3712C0A6) pub.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +mQINBFVcU04BEAC87aEtQ3Gw/QCRUdIM2p5SLqm4atwaG8cig68379RtsjMp/dnR +5qW4Q4B2r9NcaHXFnQGo8VxcYXgDiKYRivay/D37/GQM5DweSV/lARgy9m4+vpw/ +lYrUNzSz+fVZwBT6sb0D4JxW9h7JJOq68nQPJj6v5P9q9/W8x7kquRVh9TACYCs2 +ymXgQIooeQDfJ3fMfWZn/UdTIvtGjlSv54PDxgJcDRBPFWVaQ4l7FB/tXYforZoo +2tzwrpOepWGT7AcVpOsOzlYBiELFgY0T82gOx+Lvju12blFY8y9udivgkE7gikPa +pARq13TlxVsL+gTXkAoNE4LUa36SgNHyFOOlW74/5KGqohbtI5lq4CiRnHMGsjj6 +CRzELGQyyx84tdP0gNrfba/fgPr5Tnnzkz0dqZ/iE0vYv3gHnbXCNG+lAmpOG+8J +HXMy9uSzArcXbVEfn/lcDEI/+IW9/kVeex7d0VWGQuL363btcX3vNNS7UTKSZn7e +vAHCagh7ED1jFFBKKMLRKaJ/Lp8kHNi++66andnlhoZoewWdozKjqz8k1FQZ9n8O +9GQZFHN+oZZtL6F2TB2ZeBjFs0pp8n6+uZN1gLzpbdTWTTPPKT/LLT7YyQmeJBqg +ILVJCO+6eIVhcwqamGyBx++rQjemPryBBrX4UIsTMgoUA1mwopCxj+/B9wARAQAB +tCdTYWJpbmUgV2VpbmdhcnRlbiA8c3dlaW5nYXJ0ZW5AZ214Lm5ldD6JAj8EEwEI +ACkFAlVcU04CGyMFCQlmAYAHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRBV +bE27NxLApgtZD/9+CxaCCP0d+EJjzLPtaTFVW3/ik8m25QxLJ3H6kEZs+XEMPnf5 +FXV28Q0e3UbIpoDvooj+ZfOojkyoSl97oaWwJ7kvkGtzgJ2qGTtlSxO4Ec7PwU2p +RHBaZVjdwTd8nhW348N0iyeLzFP/Kw8vVyyVUqt0S5WNX5RFZwlNl49oh0L1vIWx ++/N3veqAtd91mA1hlVdXL0YMjur+GDw/EfyWdGGKAZa3SA5xu57xh8SVnEh/Moui +tRrOOHy2osrZQupTCsQaQumoNKxxLFuqqmF1VsbP6ZBs4I3w9kbfPDL3M28rFDkS +gNonmHkkoeIv1Cq3e21jvqy3oBK8SULzL2DFSGfh/sUp1d3z/+8ZE/gTzTTKdG52 +AykCgU9Kk7x+pjEonNZ3ZFsmjQwD+far+YdrraXunFkzvzb9GEeyLhRJu77t0qxa +JVbPLJli7ApF1OR/ld6p/t/HiKxUCa0lsay1DaLgaEpTUURQ/YDLKuf1OhVlmQLJ +UQQCZNIBdsTtzzNVY47CFkZNiEyIagtWnXKC4wcF2Z5b4nceOOBLKfsNnRqBlu/N +mpkdOQGfbIR7RlqtuXcu92nWbUuMVQE3BNQcwlJl08zRC8n3MsBzOcT+FE2g2F16 +tjGca7WUJiry2b1iuYjW3HIGPZc1Athdlh3F4nwFsIbmxYp26CUoUCoh97kCDQRV +XFNOARAAmXMfoLyHLyqOkAP5aZfjPDUqBse7q29G16ngrbQZKWWbUfrG3iaQ3VBR +LldutEBv3Zwj5cv4rZRAghW9IrkeUda9fGKFcuxBBYKA/40i0OkVe6BHzElydw/M +2HV/MVOSmMYG98cktHTppbTNPZ06LRB3Rssn/d78DYB5Lnu9uvpi22y4o3aFdAX1 +4VxafBXXx81rSfREIdNPUQBcrYpprBIXImAK2oNKXeP+LAfEeOr0GiZe1TqKBhck +yacb+cP7ytkwYuPVCVO8a7uEMUdZxry+Wty3EX7fT1u/IheVrDEGAK8D0vAOHsbu +8+iC1GieoEX8p16iiS8BVNqOymq/J9be+z1k70Z280GqRkF4aFDlyV+xAQlTyZIK +rvUhlL9t43ltkO2s1X0knYAzylMiArtmejiQRp3+4dqSitMlK/FogDkJGieLkbIG +fyvOdhn9yW5frYLcLoYH47WfZpsTyT/40EPhQXX2ZpPUQy0i3XXcg/tZoae9PdAR +oKT1zJjSdT8J/HZwgtHWq9FG7SlcGK4dj2Oz9D7YsD7bjmE0c2UgGRRpNVeVHxVh +q6aTuhvRJYxfnqsZvtV9bknPp1GcgU8zSluO1FNg5LWxRDFn4qD6VUMBIidwvd4L +H8z7H2HvmI8g6z1gxNAbpYADZaNHkdLj3fd5Ynd+cMjuxvIB568AEQEAAYkCJQQY +AQgADwUCVVxTTgIbDAUJCWYBgAAKCRBVbE27NxLApgU3EACRy1Ce2BljifwTnpYf +Ff0GU217i07dE7w+deeOnN/ByK8nTVlRW0ZPhJKhmwiWR96u6NstHN8wAM8HwrxI +Z0IU1XHyMQ/FlNf873gPZMTet44FSfZjWNn1G02W8G0Ts6cS7G8nRtYRtp9Hg857 +EiRmgkl/Mf10JV5vwdSJnq+mQm/0kZBG5QEEqKz0FU2y3ux3JOwmaFE5Bc6f5D0W +kvJ7Dya4jvkkkj+rmU4jYHIigCiWJNOY35L1NK7eGaaYawNrZ6MBwMoVioTPGRQ2 +2ClbHBicmW6dxpLxl3KK3LrgQ+gMvvcxdqkML2ScFRVJc1w7ZzxXmIes10LWRq3D +0JAuJkudMgasdV/4NTnFr1wmPizFXgMSLaE6EltnSSWdxyrYzpblH+9/ZkzWnqff +GFOZ/w64+ndu5gPHLvbQ7WyhnVI5Io33DYqVTwqH/c+vVDPHZ1u5kJgT3aAoGLIo +W8AIHaExWP+aH1d3QjgcuCD5RJa0QioKcp0xZ/JfJjiCHtbsJyyt9Kvne4TvD+Ie +1waPnJUi7ODDoJh5u8VVbGTjsb/E5pZTa/iOrU3CxLVBdtEgZU3zkeJgqAu40/Er +htfEAL82mxIhvTEPbYFM1dDdOqK0vQJi/6YoHg/mRjx0pmj1ZzcdQAqtO+cJF/pT +Ma1iAOsysssutiPWvnYZdAakCg== +=gvRa +-----END PGP PUBLIC KEY BLOCK----- diff --git a/participants/Biografie_Raoul_Schikora.pdf.gpg b/participants/Biografie_Raoul_Schikora.pdf.gpg new file mode 100644 index 0000000..a55eec7 Binary files /dev/null and b/participants/Biografie_Raoul_Schikora.pdf.gpg differ diff --git a/participants/Biografie_Robert_Loewe b/participants/Biografie_Robert_Loewe new file mode 100644 index 0000000..ae6c4f8 --- /dev/null +++ b/participants/Biografie_Robert_Loewe @@ -0,0 +1,51 @@ +-----BEGIN PGP MESSAGE----- +Comment: GPGTools - https://gpgtools.org + +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 +cxA= +=0+zu +-----END PGP MESSAGE----- diff --git a/participants/Biographie_Anne_Himmel.txt.asc b/participants/Biographie_Anne_Himmel.txt.asc new file mode 100644 index 0000000..4bf4752 --- /dev/null +++ b/participants/Biographie_Anne_Himmel.txt.asc @@ -0,0 +1,24 @@ +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1 + +hQIMAxx3/Bnc6zQ8AQ//f+0m0mFAtHyjRakEDKDERTszyXgqUmv1rZT6MN4bARsl +Qu5LUqnAVzlLQgo98WiowYjRCv3UV2CPvM3n8gI2FV1zlDrSPwrPO2xfbTuT0jmH +O/qaxoFpSuQyc07gdhADFtytqkDFRvSWZzM1GAZJWeZ27O3zGvCFvJrsCek8EIUr +1NL9M59rydgS+CTslRDhV9ObkEtZHu+PYS5W1vHPG1qcaoRW5EgqP4WK4yAYjqVI +hbfmyel/JoVwZs9VeIXJvaP0H6+XsZ20bBBf9n9RSgU/cLaaSs9IcEwTrsEWXFNO +tqViVwErIxiRHW59RBArOKqjz3O/9Hh3xZLJA7Z+OAwCNjPYk+QpmAPIgfXzAm5F +I6snR2fbzERD/h29WszUHPefWp/HFkp8IEcQIB2hrX4AUzIf2knqiGVT4W2dZ7no +u6H42oHI/bC6kfaKh/ClSFt7UBGUV9PnvNcoZDHhAICVFxOZdR7M9Zrqe2kyhaBc +v7511VXIQ4Dw0lkF3EXP6Bu/09jH4DTeEcyZKYgIRoC1rulWGHUyBPdDQuUqwhCa +NpfzNf77Q2UcMG1ca196uqhBKqUDVL6zalloZtgH5XxZ6sUthID5fa3XJRKHi5AG +QVKapxPlrwcLE3DNajp77Sq+iBykpZ46TSVJ4SM08KqQhwkqv23X89TB9IDV1afS +wJwB/wMHQJDO9Fw5N9AsTcrAykAPecP4y2xvlfFCZYCeNg3LM+NFesONhl1JOnXl +Cs42eeVcxhNh4JBr3xlsMxGbeK6qoFByha2krEeFoGJu43bLgHoZIZW11g0NKDiT +8kQyL7pgX+CKPTUdHUPj9eMShaRHK7+FRi6olYZK9at4J2jnbkoN5UClJ5rvtx4h +h5dkWCq/A5fisqxPpD+oo5MFCxcHJO2caDTOyheLIx5DPCCDYL4Jf4WiAUD09j5p +7p8tf6PtVkgNL9XCk8B7gDDuG0EO3lJYANULn36hUm11z7oRXUV43+zXguyQMrS6 +GFzTlXiphpyPvfhYAz5ATkiPmZq/0hJhWhPamxNWe8KcjK6s1mf3E/+3UyImZubX +y2aT2yUX57y5UwwL6FKBqdubgU5YolE4a/b2CESlWr3sXISyTfc8Nge/M4H4IZJD +/VwvD3RDm8st3pPsiBc= +=JLeB +-----END PGP MESSAGE----- diff --git a/participants/README b/participants/README new file mode 100644 index 0000000..ba3c862 --- /dev/null +++ b/participants/README @@ -0,0 +1 @@ +Please put a short biography with your current mathematical interests into this directory. diff --git a/participants/biographie_constantin_fischer.asc b/participants/biographie_constantin_fischer.asc new file mode 100644 index 0000000..210f003 --- /dev/null +++ b/participants/biographie_constantin_fischer.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1 + +hQIMAxx3/Bnc6zQ8AQ/+NEmWwvYfFxYh6pgQTBwslINeEZgNHG7d7tcs45FVdgXM +BM5WfCyPjficg6qPHlnPJXaY9WAtRzGk2cDmGNxpIqDH2ZqEKiv1B7xlThR81fgX +KElAJ1hy3jlXncZps84Lby7mlRUK6AwRbl6wVr/p0LSnShCx4Ph9XFLBMAkngxOB +LRF3cKK9sLBJJ2nGWwhscSW7lRBUWqZLFKVDYLiZkhp4wvjhEypsGkpictNxRkIL ++Z4VlJ/Rc94xajjf4RV0TjIcy8oO9wQx2smgSPo77zVlCglNLNYHIoSt2BzlrFMI +7VW0K/Za/uO0xQNGO2IAXOGKbk1AvP6eUR8F1uf9MwFAu2Teczhr/YYBpYMIo6bQ +cfp2chyn67pXhWoeJCfCLEnbnLh9uRz1U8GJadgaYq78G2M5hILLxHvYhKlXlMPr +abVXFShw31rmiL6+ANR/B4D+t92KtrazJjBCmTNpeiieBKDPfSDHN3dz6RitC5OI +Zf0msQ8t9r4FFGGft2V2XOVzMQ9CEtrGbIb3dbkvOHKamME0rXx3MRQsF206VnDr +xMzHcAS7VbZ04eBD36EzH7stkIdvdSoOiqw2EH13ICtrcZmE5OVk5R8Dk/Y/lZxW +IuevTQyWK7sF8wfXdfav+RU1UzVvN/9DtinVFG15YwA7+bnskLRuOpV2AijAhSbS +6QEgm5gZSBflsO3K6Hxiyj9y2eFhMrA1hBo/Xw8i5TZ3oQ2lIz80r5SoNUfI4jPW +GZmke1riyEChxDyLZ0PZWnqpdeNRHGYj17+ebBUCj9xlyNSPaaU6wfR7y4DhfYQS +0R8uLybM1XDg0TqvU7Iyvlm9AYWR6QZxDJ4L9uVOhRszDjAMHZbax1NXbC/Zij66 +iwv5J5yRNvAgahvwQfuliDP7aV4pMqf8gsSWmd6+arhcbS8xepKrSyys7Wh+HiAT +KduhpNvaUhGCHjLsBGF/Wifsga6cCsvbw+NoxqTW1N1+NrTovG0OX5LZ315dZcv7 +H82ck7WRNgcSX/xagUaGgNtiW0P1yJR0tmmRT81gsFoAT/Kd1aROIDYHh8J64UaL +H3Aosdb2zo9p0Npps+f0IX5xWLpMOnxGptgc8XHugGiuF+sDBHpN1TrxT61rR9MO +ST/bv99wrE1LUIfv0rA9ESFLJURgM759b0JHMqEZk+2KgPfO+v9/bFCUr8BtgvJj +rXCmY1UlXnpWeBR1/8HGvIH61XYCJaduI3ZjgAcovsIwjE1vAARTIuVODUEC3tEo +Tz7k57OlNzDuLgqoFRSpdAT7eddDHoMmL26RMcIB51rKLXH1ui0gw4JM591/qtNL ++WpjAmOZha0x4U95H2PoeBRNqJQGXbMxy3wnEsh9OLkjep2Wl+ihOU78eQ2FK2Ft +qzB3LhIIeQ7oZQzH3KQFJGbZp8ZQvm3II0Lwpy7Mp7hDKEKqdnKO2s15A2a1ibsc +c4z7WF16+upTP+7Oy0zcPZQJdmQedsMCZJpJqu4dHZ6XFkmHo0sBg37fUEhoxDdl +dQ+WaXz66DI0NxIi +=tM5D +-----END PGP MESSAGE----- diff --git a/participants/kurzBio.txt.gpg b/participants/kurzBio.txt.gpg new file mode 100644 index 0000000..127486a Binary files /dev/null and b/participants/kurzBio.txt.gpg differ