Initialisation du repository de Beta
This commit is contained in:
commit
14985f6dbb
9469 changed files with 1903273 additions and 0 deletions
|
|
@ -0,0 +1,160 @@
|
|||
"""
|
||||
The Schur number S(k) is the largest integer n for which the interval [1,n]
|
||||
can be partitioned into k sum-free sets.(https://mathworld.wolfram.com/SchurNumber.html)
|
||||
"""
|
||||
import math
|
||||
from sympy.core import S
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.function import Function
|
||||
from sympy.core.numbers import Integer
|
||||
|
||||
|
||||
class SchurNumber(Function):
|
||||
r"""
|
||||
This function creates a SchurNumber object
|
||||
which is evaluated for `k \le 5` otherwise only
|
||||
the lower bound information can be retrieved.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.combinatorics.schur_number import SchurNumber
|
||||
|
||||
Since S(3) = 13, hence the output is a number
|
||||
>>> SchurNumber(3)
|
||||
13
|
||||
|
||||
We do not know the Schur number for values greater than 5, hence
|
||||
only the object is returned
|
||||
>>> SchurNumber(6)
|
||||
SchurNumber(6)
|
||||
|
||||
Now, the lower bound information can be retrieved using lower_bound()
|
||||
method
|
||||
>>> SchurNumber(6).lower_bound()
|
||||
536
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def eval(cls, k):
|
||||
if k.is_Number:
|
||||
if k is S.Infinity:
|
||||
return S.Infinity
|
||||
if k.is_zero:
|
||||
return S.Zero
|
||||
if not k.is_integer or k.is_negative:
|
||||
raise ValueError("k should be a positive integer")
|
||||
first_known_schur_numbers = {1: 1, 2: 4, 3: 13, 4: 44, 5: 160}
|
||||
if k <= 5:
|
||||
return Integer(first_known_schur_numbers[k])
|
||||
|
||||
def lower_bound(self):
|
||||
f_ = self.args[0]
|
||||
# Improved lower bounds known for S(6) and S(7)
|
||||
if f_ == 6:
|
||||
return Integer(536)
|
||||
if f_ == 7:
|
||||
return Integer(1680)
|
||||
# For other cases, use general expression
|
||||
if f_.is_Integer:
|
||||
return 3*self.func(f_ - 1).lower_bound() - 1
|
||||
return (3**f_ - 1)/2
|
||||
|
||||
|
||||
def _schur_subsets_number(n):
|
||||
|
||||
if n is S.Infinity:
|
||||
raise ValueError("Input must be finite")
|
||||
if n <= 0:
|
||||
raise ValueError("n must be a non-zero positive integer.")
|
||||
elif n <= 3:
|
||||
min_k = 1
|
||||
else:
|
||||
min_k = math.ceil(math.log(2*n + 1, 3))
|
||||
|
||||
return Integer(min_k)
|
||||
|
||||
|
||||
def schur_partition(n):
|
||||
"""
|
||||
|
||||
This function returns the partition in the minimum number of sum-free subsets
|
||||
according to the lower bound given by the Schur Number.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n: a number
|
||||
n is the upper limit of the range [1, n] for which we need to find and
|
||||
return the minimum number of free subsets according to the lower bound
|
||||
of schur number
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
List of lists
|
||||
List of the minimum number of sum-free subsets
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
It is possible for some n to make the partition into less
|
||||
subsets since the only known Schur numbers are:
|
||||
S(1) = 1, S(2) = 4, S(3) = 13, S(4) = 44.
|
||||
e.g for n = 44 the lower bound from the function above is 5 subsets but it has been proven
|
||||
that can be done with 4 subsets.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For n = 1, 2, 3 the answer is the set itself
|
||||
|
||||
>>> from sympy.combinatorics.schur_number import schur_partition
|
||||
>>> schur_partition(2)
|
||||
[[1, 2]]
|
||||
|
||||
For n > 3, the answer is the minimum number of sum-free subsets:
|
||||
|
||||
>>> schur_partition(5)
|
||||
[[3, 2], [5], [1, 4]]
|
||||
|
||||
>>> schur_partition(8)
|
||||
[[3, 2], [6, 5, 8], [1, 4, 7]]
|
||||
"""
|
||||
|
||||
if isinstance(n, Basic) and not n.is_Number:
|
||||
raise ValueError("Input value must be a number")
|
||||
|
||||
number_of_subsets = _schur_subsets_number(n)
|
||||
if n == 1:
|
||||
sum_free_subsets = [[1]]
|
||||
elif n == 2:
|
||||
sum_free_subsets = [[1, 2]]
|
||||
elif n == 3:
|
||||
sum_free_subsets = [[1, 2, 3]]
|
||||
else:
|
||||
sum_free_subsets = [[1, 4], [2, 3]]
|
||||
|
||||
while len(sum_free_subsets) < number_of_subsets:
|
||||
sum_free_subsets = _generate_next_list(sum_free_subsets, n)
|
||||
missed_elements = [3*k + 1 for k in range(len(sum_free_subsets), (n-1)//3 + 1)]
|
||||
sum_free_subsets[-1] += missed_elements
|
||||
|
||||
return sum_free_subsets
|
||||
|
||||
|
||||
def _generate_next_list(current_list, n):
|
||||
new_list = []
|
||||
|
||||
for item in current_list:
|
||||
temp_1 = [number*3 for number in item if number*3 <= n]
|
||||
temp_2 = [number*3 - 1 for number in item if number*3 - 1 <= n]
|
||||
new_item = temp_1 + temp_2
|
||||
new_list.append(new_item)
|
||||
|
||||
last_list = [3*k + 1 for k in range(len(current_list)+1) if 3*k + 1 <= n]
|
||||
new_list.append(last_list)
|
||||
current_list = new_list
|
||||
|
||||
return current_list
|
||||
Loading…
Add table
Add a link
Reference in a new issue