Skip to content

Commit

Permalink
Merge pull request #14 from nskeip/feature-11-exc-powers
Browse files Browse the repository at this point in the history
Constraints for 2F4, 2B2, 2G2
  • Loading branch information
nskeip authored Jan 31, 2022
2 parents af0da63 + bc8e509 commit c1cd084
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
13 changes: 12 additions & 1 deletion src/spectrum/calculations/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ class ExceptionalGroup(Group):
"F4": 'F_4', "2F4": '{}^2F_4', "G2": 'G_2', "2G2": '{}^2G_2',
"2B2": '{}^2B_2', "3D4": '{}^3D_4'}

# constraints for field order
_field_constraints = {
'2F4': Constraints(min=2, primality=numeric.ODD_POWER_OF_2),
'2B2': Constraints(min=2, primality=numeric.ODD_POWER_OF_2),
'2G2': Constraints(min=2, primality=numeric.ODD_POWER_OF_3),
}

def __init__(self, name, *field):
super(ExceptionalGroup, self).__init__()
self._name = name
Expand Down Expand Up @@ -316,4 +323,8 @@ def order(self):
func = orders.exceptional_orders.get(self._name,
lambda *arg: Integer())
self._order = func(self._field)
return self._order
return self._order

@classmethod
def field_constraints(cls, name):
return cls._field_constraints.get(name, Constraints(min=2, primality=numeric.PRIME_POWER))
57 changes: 56 additions & 1 deletion src/spectrum/calculations/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
limitations under the License.
"""
import functools
import math
import operator
from collections import Counter
Expand Down Expand Up @@ -230,6 +231,49 @@ def closest_power_of_two(n):
return k * 2


def _nearest_odd_or_even(a, greater=True, is_even=True):
op = operator.add if greater else operator.sub
b = (a % 2) if is_even else (a + 1) % 2
return op(a, b)


def _math_round_in_0_1(x):
""""Python round works incorrectly when rounding 0.5"""
return 0 if x < 0.5 else 1


def _closest_power_of(is_even, base, n):
"""Returns the closest power of base two to n
Args:
is_even: bool
base: int
n: Integer
Returns:
Closest power of base two to n
"""
p = math.log(n, base)
prev_p = _nearest_odd_or_even(math.floor(p), False, is_even)
next_p = _nearest_odd_or_even(math.ceil(p), True, is_even)

if prev_p == p == next_p:
return n

is_p_closer_to_prev_p = 0 == _math_round_in_0_1((n - base ** prev_p) / (base ** next_p - base ** prev_p))

closest_exponent = max(
0 if is_even else 1,
prev_p if is_p_closer_to_prev_p else next_p
)

return base ** max(1, closest_exponent)


closest_odd_power_of_two = functools.partial(_closest_power_of, False, 2)
closest_odd_power_of_three = functools.partial(_closest_power_of, False, 3)


def is_power_of_two(n):
"""Returns whether n is a power of 2
"""
Expand Down Expand Up @@ -497,6 +541,9 @@ def factors(self):

PRIME = 1
PRIME_POWER = 2
ODD_POWER_OF_2 = 3
ODD_POWER_OF_3 = 4


class Constraints:
"""Class representing numeric constraints, e.g. for dimension and
Expand Down Expand Up @@ -529,6 +576,10 @@ def closest_valid(self, value):
value = closest_odd_prime_power(value)
else:
value = closest_prime_power(value)
elif self._primality == ODD_POWER_OF_2:
value = closest_odd_power_of_two(value)
elif self._primality == ODD_POWER_OF_3:
value = closest_odd_power_of_three(value)
else:
if self._parity == 1:
value -= value % 2
Expand All @@ -550,4 +601,8 @@ def is_valid(self, value):
return False
if self._primality == PRIME_POWER and not is_prime_power(value):
return False
return True
if self._primality == ODD_POWER_OF_2 and math.log(value, 2) % 2 != 1:
return False
if self._primality == ODD_POWER_OF_3 and math.log(value, 3) % 2 != 1:
return False
return True
6 changes: 6 additions & 0 deletions src/spectrum/gui/group_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,13 @@ def _init_components(self):
Label(self._ex_params, text="Type").grid(row=0, sticky='w')
self._ex_type = OptionList(self._ex_params, values=ExceptionalGroup.types())
self._ex_type.setvar(value=ExceptionalGroup.types()[0])
self._ex_type.variable.trace("w", lambda n, i, m: self._exceptional_group_type_selection())
self._ex_type.grid(row=0, column=1, sticky='we')

Label(self._ex_params, text="Field order").grid(row=1, sticky='w')
self._ex_field = NumberBox(self._ex_params, constraints=Constraints(primality=numeric.PRIME_POWER))
self._ex_field.grid(row=1, column=1, sticky='we')
self._exceptional_group_type_selection()

# sporadic
self._spor_params = Frame(group_params_frame)
Expand Down Expand Up @@ -144,3 +146,7 @@ def _classical_group_type_selection(self):
name = self._clas_type.variable.get()
self._clas_dim.set_constraints(ClassicalGroup.dim_constraints(name))
self._clas_field.set_constraints(ClassicalGroup.field_constraints(name))

def _exceptional_group_type_selection(self):
name = self._ex_type.variable.get()
self._ex_field.set_constraints(ExceptionalGroup.field_constraints(name))
20 changes: 20 additions & 0 deletions src/tests/spectrum_tests/calculations/numeric_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,26 @@ def test_is_power_of_two(self):
for key, value in values.items():
self.assertEqual(value, is_power_of_two(key))

def test_closest_odd_power_of_two(self):
self.assertEqual(2, closest_odd_power_of_two(1))
self.assertEqual(2, closest_odd_power_of_two(2))
self.assertEqual(2, closest_odd_power_of_two(3))
self.assertEqual(2, closest_odd_power_of_two(4))
self.assertEqual(8, closest_odd_power_of_two(5))
self.assertEqual(8, closest_odd_power_of_two(6))
self.assertEqual(8, closest_odd_power_of_two(7))
self.assertEqual(8, closest_odd_power_of_two(8))
self.assertEqual(8, closest_odd_power_of_two(9))

self.assertEqual(8, closest_odd_power_of_two(16))

def test_closest_odd_power_of_three(self):
for n in range(1, 15):
self.assertEqual(3, closest_odd_power_of_three(n), f'trouble with n={n}')
self.assertEqual(27, closest_odd_power_of_three(15))
self.assertEqual(27, closest_odd_power_of_three(26))
self.assertEqual(27, closest_odd_power_of_three(27))

def test_constraints(self):
c = Constraints(min=5, primality=PRIME)
self.assertTrue(c.is_valid(5))
Expand Down

0 comments on commit c1cd084

Please sign in to comment.