Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
language: python
python:
# - "2.7"
- "3.4"
# - "3.4"
- "3.5"
- "3.6"
- "nightly"
# - "pypy"
- "pypy3"
install:
- pip install -e .
Expand Down
4 changes: 2 additions & 2 deletions permuta/meshpatt.py
Original file line number Diff line number Diff line change
Expand Up @@ -853,8 +853,8 @@ def random(length):
#

def __repr__(self): # pragma: no cover
return "MeshPatt({self.pattern}, {shading})".format(
self=self, shading=sorted(self.shading))
return "MeshPatt({}, {})".format(
repr(self.pattern), sorted(self.shading))

def __str__(self): # pragma: no cover
result = []
Expand Down
60 changes: 23 additions & 37 deletions permuta/perm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import bisect
import collections
import fractions
import itertools
import math
import numbers
Expand All @@ -27,23 +26,11 @@ class Perm(tuple,

_TYPE_ERROR = "'{}' object is not a perm"

#
# Methods to modify Perm class settings
#

@staticmethod
def toggle_check():
# TODO: Docstring and discuss, can settings be done better?
if Perm._init_helper is Perm._init_checked:
Perm._init_helper = Perm._init_unchecked
else:
Perm._init_helper = Perm._init_checked

#
# Methods returning a single Perm instance
#

def __new__(cls, iterable=()):
def __new__(cls, iterable=(), check=False):
"""Return a Perm instance.

Args:
Expand All @@ -66,8 +53,7 @@ def __new__(cls, iterable=()):
Perm((5, 4, 3, 2, 1, 0))
>>> Perm(6012354)
Perm((6, 0, 1, 2, 3, 5, 4))
>>> Perm.toggle_check()
>>> Perm("abc") # Not good
>>> Perm("abc", check=True) # Not good
Traceback (most recent call last):
...
TypeError: ''a'' object is not an integer
Expand All @@ -92,15 +78,14 @@ def __new__(cls, iterable=()):
else:
raise

def __init__(self, iterable=()):
def __init__(self, iterable=(), check=False):
# Cache for data used when finding occurrences of self in a perm
self._cached_pattern_details = None
self._init_helper()

def _init_unchecked(self):
pass
if check:
self._init_checked()

def _init_checked(self):
"""Checks if a suitable iterable given when initialised."""
used = [False]*len(self)
for value in self:
if not isinstance(value, numbers.Integral):
Expand All @@ -112,7 +97,7 @@ def _init_checked(self):
raise ValueError("Duplicate element: {}".format(value))
used[value] = True

_init_helper = _init_unchecked
_to_standard_cache = {}

@classmethod
def to_standard(cls, iterable):
Expand All @@ -132,18 +117,16 @@ def to_standard(cls, iterable):
Perm((4, 0, 1, 3, 2))
"""
# TODO: Do performance testing
try:
len_iterable = len(iterable)
except TypeError:
iterable = list(iterable)
len_iterable = len(iterable)
result = [None]*len_iterable
value = 0
for (index, _) in sorted(enumerate(iterable),
key=operator.itemgetter(1)):
result[index] = value
value += 1
return cls(result)
iterable = tuple(iterable)
if iterable not in Perm._to_standard_cache:
result = [None]*len(iterable)
value = 0
for (index, _) in sorted(enumerate(iterable),
key=operator.itemgetter(1)):
result[index] = value
value += 1
Perm._to_standard_cache[iterable] = cls(result)
return Perm._to_standard_cache[iterable]

standardize = to_standard # permpy backwards compatibility
from_iterable = to_standard
Expand Down Expand Up @@ -1084,7 +1067,7 @@ def order(self):
"""
acc = 1
for l in map(len, self.cycle_decomp()):
acc = (acc * l) // fractions.gcd(acc, l)
acc = (acc * l) // math.gcd(acc, l)
return acc

# TODO: reimplement the following four functions to return generators
Expand Down Expand Up @@ -1965,8 +1948,8 @@ def occurrences(i, k):
i += 1
elements_remaining -= 1

for occurence in occurrences(0, 0):
yield occurence
for occurrence in occurrences(0, 0):
yield occurrence

def occurrences_of(self, patt):
"""Find all indices of occurrences of patt in self.
Expand Down Expand Up @@ -2181,6 +2164,9 @@ def __mul__(self, other):
def __repr__(self):
return "Perm({})".format(super(Perm, self).__repr__())

def __str__(self):
return "".join(str(i) for i in self)

def __lt__(self, other):
return (len(self), tuple(self)) < (len(other), tuple(other))

Expand Down
50 changes: 23 additions & 27 deletions tests/test_meshpatt.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,39 +23,35 @@
mesh3 = MeshPatt(patt3, shad3)

def test_init():
Perm.toggle_check()
try:
with pytest.raises(ValueError): MeshPatt(Perm([0, 1, 1]), ())
with pytest.raises(ValueError): MeshPatt(Perm([1, 0, 1]), ())
with pytest.raises(ValueError): MeshPatt(Perm([0, 0]), ())
with pytest.raises(ValueError): MeshPatt(Perm([1]), ())
with pytest.raises(ValueError): MeshPatt(Perm((1)), ())
with pytest.raises(ValueError): MeshPatt(Perm(101), ())
with pytest.raises(ValueError): MeshPatt(Perm(-234), ())
with pytest.raises(TypeError): MeshPatt(Perm(None), ())
with pytest.raises(TypeError): MeshPatt(Perm([0.1, 0.2, 0.3]), ())
with pytest.raises(TypeError): MeshPatt(Perm(()), (0, 1))
with pytest.raises(TypeError): MeshPatt(Perm((0, 1, 2)), [(1, 'a')])
with pytest.raises(TypeError): MeshPatt(Perm((0, 1, 2)), [('a', 1)])
with pytest.raises(ValueError): MeshPatt(Perm([0, 1, 1], check=True), ())
with pytest.raises(ValueError): MeshPatt(Perm([1, 0, 1], check=True), ())
with pytest.raises(ValueError): MeshPatt(Perm([0, 0], check=True), ())
with pytest.raises(ValueError): MeshPatt(Perm([1], check=True), ())
with pytest.raises(ValueError): MeshPatt(Perm((1), check=True), ())
with pytest.raises(ValueError): MeshPatt(Perm(101, check=True), ())
with pytest.raises(ValueError): MeshPatt(Perm(-234, check=True), ())
with pytest.raises(TypeError): MeshPatt(Perm(None, check=True), ())
with pytest.raises(TypeError): MeshPatt(Perm([0.1, 0.2, 0.3], check=True), ())
with pytest.raises(TypeError): MeshPatt(Perm((), check=True), (0, 1))
with pytest.raises(TypeError): MeshPatt(Perm((0, 1, 2), check=True), [(1, 'a')])
with pytest.raises(TypeError): MeshPatt(Perm((0, 1, 2), check=True), [('a', 1)])
with pytest.raises(ValueError): MeshPatt(Perm.random(5), [(0,), (1, 1)])
with pytest.raises(ValueError): MeshPatt(Perm.random(5), [(0, 0, 0), (1, 1, 1)])
with pytest.raises(ValueError): MeshPatt(Perm(()), [(0, 1), (1, 0)])
with pytest.raises(ValueError): MeshPatt(Perm((), check=True), [(0, 1), (1, 0)])
with pytest.raises(ValueError): MeshPatt(Perm.random(3), [(0, -1), (0, 0)])
with pytest.raises(ValueError): MeshPatt(Perm.random(10), [(0, 0), (12, 7)])
MeshPatt(Perm(), ())
MeshPatt(Perm([]), ())
MeshPatt(Perm(0), ())
MeshPatt(Perm([0]), ())
MeshPatt(Perm([3, 0, 2, 1]), ())
MeshPatt(Perm([3, 0, 2, 1]), [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4),
(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2),
(2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0),
(4, 1), (4, 2), (4, 3), (4, 4)])
MeshPatt(Perm([3, 0, 2, 1]), [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)])
MeshPatt(Perm(check=True), ())
MeshPatt(Perm([], check=True), ())
MeshPatt(Perm(0, check=True), ())
MeshPatt(Perm([0], check=True), ())
MeshPatt(Perm([3, 0, 2, 1], check=True), ())
MeshPatt(Perm([3, 0, 2, 1], check=True), [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4),
(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2),
(2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0),
(4, 1), (4, 2), (4, 3), (4, 4)])
MeshPatt(Perm([3, 0, 2, 1], check=True), [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)])
MeshPatt([3, 0, 2, 1], [(0, 2), (0, 3), (0, 4)])
MeshPatt(set([3, 0, 2, 1]), [(0, 2), (0, 3), (0, 4)])
finally:
Perm.toggle_check()

def test_complement():
assert MeshPatt(Perm(), []).complement() == MeshPatt(Perm(), [])
Expand Down
54 changes: 23 additions & 31 deletions tests/test_perm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,23 @@
from permuta import Perm, PermSet

def test_init():
Perm.toggle_check()
try:
with pytest.raises(ValueError): Perm([0, 1, 1])
with pytest.raises(ValueError): Perm([1, 0, 1])
with pytest.raises(ValueError): Perm([0, 0])
with pytest.raises(ValueError): Perm([1])
with pytest.raises(ValueError): Perm((1))
with pytest.raises(ValueError): Perm(101)
with pytest.raises(ValueError): Perm(-234)
with pytest.raises(TypeError): Perm(None)
with pytest.raises(TypeError): Perm([0.1, 0.2, 0.3])
Perm()
Perm([])
Perm(0)
Perm([0])
Perm([3, 0, 2, 1])
Perm(set([0, 1, 2]))
p = Perm(502134)
assert p == Perm((5, 0, 2, 1, 3, 4))
finally:
Perm.toggle_check()
with pytest.raises(ValueError): Perm([0, 1, 1], check=True)
with pytest.raises(ValueError): Perm([1, 0, 1], check=True)
with pytest.raises(ValueError): Perm([0, 0], check=True)
with pytest.raises(ValueError): Perm([1], check=True)
with pytest.raises(ValueError): Perm((1), check=True)
with pytest.raises(ValueError): Perm(101, check=True)
with pytest.raises(ValueError): Perm(-234, check=True)
with pytest.raises(TypeError): Perm(None, check=True)
with pytest.raises(TypeError): Perm([0.1, 0.2, 0.3], check=True)
Perm(check=True)
Perm([], check=True)
Perm(0, check=True)
Perm([0], check=True)
Perm([3, 0, 2, 1], check=True)
Perm(set([0, 1, 2]), check=True)
p = Perm(502134, check=True)
assert p == Perm((5, 0, 2, 1, 3, 4), check=True)

def test_to_standard():
def gen(perm):
Expand Down Expand Up @@ -66,15 +62,11 @@ def test_identity():
assert Perm.identity(length) == Perm(range(length))

def test_random():
Perm.toggle_check()
try:
for length in range(11):
for _ in range(10):
perm = Perm.random(length)
assert len(perm) == length
Perm(perm)
finally:
Perm.toggle_check()
for length in range(11):
for _ in range(10):
perm = Perm.random(length)
assert len(perm) == length
Perm(perm)

def test_monotone_increasing():
for length in range(11):
Expand Down Expand Up @@ -464,7 +456,7 @@ def test_all_syms():

@pytest.mark.xfail
def test_is_representative():
# TODO: write porper tests when the function is working
# TODO: write proper tests when the function is working
assert Perm(()).is_representative()
assert Perm((0)).is_representative()

Expand Down