def test_farthest_points_closest_points(): from random import randint from sympy.utilities.iterables import subsets for how in (min, max): if how is min: func = closest_points else: func = farthest_points raises(ValueError, lambda: func(Point2D(0, 0), Point2D(0, 0))) # 3rd pt dx is close and pt is closer to 1st pt p1 = [Point2D(0, 0), Point2D(3, 0), Point2D(1, 1)] # 3rd pt dx is close and pt is closer to 2nd pt p2 = [Point2D(0, 0), Point2D(3, 0), Point2D(2, 1)] # 3rd pt dx is close and but pt is not closer p3 = [Point2D(0, 0), Point2D(3, 0), Point2D(1, 10)] # 3rd pt dx is not closer and it's closer to 2nd pt p4 = [Point2D(0, 0), Point2D(3, 0), Point2D(4, 0)] # 3rd pt dx is not closer and it's closer to 1st pt p5 = [Point2D(0, 0), Point2D(3, 0), Point2D(-1, 0)] # duplicate point doesn't affect outcome dup = [Point2D(0, 0), Point2D(3, 0), Point2D(3, 0), Point2D(-1, 0)] # symbolic x = Symbol('x', positive=True) s = [Point2D(a) for a in ((x, 1), (x + 3, 2), (x + 2, 2))] for points in (p1, p2, p3, p4, p5, s, dup): d = how(i.distance(j) for i, j in subsets(points, 2)) ans = a, b = list(func(*points))[0] a.distance(b) == d assert ans == _ordered_points(ans) # if the following ever fails, the above tests were not sufficient # and the logical error in the routine should be fixed points = set() while len(points) != 7: points.add(Point2D(randint(1, 100), randint(1, 100))) points = list(points) d = how(i.distance(j) for i, j in subsets(points, 2)) ans = a, b = list(func(*points))[0] a.distance(b) == d assert ans == _ordered_points(ans) # equidistant points a, b, c = (Point2D(0, 0), Point2D(1, 0), Point2D(S(1) / 2, sqrt(3) / 2)) ans = set([_ordered_points((i, j)) for i, j in subsets((a, b, c), 2)]) assert closest_points(b, c, a) == ans assert farthest_points(b, c, a) == ans # unique to farthest points = [(1, 1), (1, 2), (3, 1), (-5, 2), (15, 4)] assert farthest_points(*points) == set([(Point2D(-5, 2), Point2D(15, 4))]) points = [(1, -1), (1, -2), (3, -1), (-5, -2), (15, -4)] assert farthest_points(*points) == set([(Point2D(-5, -2), Point2D(15, -4))]) assert farthest_points((1, 1), (0, 0)) == set([(Point2D(0, 0), Point2D(1, 1))]) raises(ValueError, lambda: farthest_points((1, 1)))
def test_issue_11230(): # a specific test that always failed a, b, f, k, l, i = symbols('a b f k l i') p = [a*b*f*k*l, a*i*k**2*l, f*i*k**2*l] R, C = cse(p) assert not any(i.is_Mul for a in C for i in a.args) # random tests for the issue from random import choice from sympy.core.function import expand_mul s = symbols('a:m') # 35 Mul tests, none of which should ever fail ex = [Mul(*[choice(s) for i in range(5)]) for i in range(7)] for p in subsets(ex, 3): p = list(p) R, C = cse(p) assert not any(i.is_Mul for a in C for i in a.args) for ri in reversed(R): for i in range(len(C)): C[i] = C[i].subs(*ri) assert p == C # 35 Add tests, none of which should ever fail ex = [Add(*[choice(s[:7]) for i in range(5)]) for i in range(7)] for p in subsets(ex, 3): p = list(p) was = R, C = cse(p) assert not any(i.is_Add for a in C for i in a.args) for ri in reversed(R): for i in range(len(C)): C[i] = C[i].subs(*ri) # use expand_mul to handle cases like this: # p = [a + 2*b + 2*e, 2*b + c + 2*e, b + 2*c + 2*g] # x0 = 2*(b + e) is identified giving a rebuilt p that # is now `[a + 2*(b + e), c + 2*(b + e), b + 2*c + 2*g]` assert p == [expand_mul(i) for i in C]
def test_arguments(): """Functions accepting `Point` objects in `geometry` should also accept tuples, lists, and generators and automatically convert them to points.""" from sympy.utilities.iterables import subsets singles2d = ((1, 2), [1, 3], Point(1, 5)) doubles2d = subsets(singles2d, 2) l2d = Line(Point2D(1, 2), Point2D(2, 3)) singles3d = ((1, 2, 3), [1, 2, 4], Point(1, 2, 6)) doubles3d = subsets(singles3d, 2) l3d = Line(Point3D(1, 2, 3), Point3D(1, 1, 2)) singles4d = ((1, 2, 3, 4), [1, 2, 3, 5], Point(1, 2, 3, 7)) doubles4d = subsets(singles4d, 2) l4d = Line(Point(1, 2, 3, 4), Point(2, 2, 2, 2)) # test 2D test_single = ['contains', 'distance', 'equals', 'parallel_line', 'perpendicular_line', 'perpendicular_segment', 'projection', 'intersection'] for p in doubles2d: Line2D(*p) for func in test_single: for p in singles2d: getattr(l2d, func)(p) # test 3D for p in doubles3d: Line3D(*p) for func in test_single: for p in singles3d: getattr(l3d, func)(p) # test 4D for p in doubles4d: Line(*p) for func in test_single: for p in singles4d: getattr(l4d, func)(p)
def _choose_factor(factors, x, v, dom=QQ, prec=200, bound=5): """ Return a factor having root ``v`` It is assumed that one of the factors has root ``v``. """ from sympy.polys.polyutils import illegal if isinstance(factors[0], tuple): factors = [f[0] for f in factors] if len(factors) == 1: return factors[0] prec1 = 10 points = {} symbols = dom.symbols if hasattr(dom, 'symbols') else [] while prec1 <= prec: # when dealing with non-Rational numbers we usually evaluate # with `subs` argument but we only need a ballpark evaluation xv = {x: v if not v.is_number else v.n(prec1)} fe = [f.as_expr().xreplace(xv) for f in factors] # assign integers [0, n) to symbols (if any) for n in subsets(range(bound), k=len(symbols), repetition=True): for s, i in zip(symbols, n): points[s] = i # evaluate the expression at these points candidates = [(abs(f.subs(points).n(prec1)), i) for i, f in enumerate(fe)] # if we get invalid numbers (e.g. from division by zero) # we try again if any(i in illegal for i, _ in candidates): continue # find the smallest two -- if they differ significantly # then we assume we have found the factor that becomes # 0 when v is substituted into it can = sorted(candidates) (a, ix), (b, _) = can[:2] if b > a * 10**6: # XXX what to use? return factors[ix] prec1 *= 2 raise NotImplementedError( "multiple candidates for the minimal polynomial of %s" % v)
def test_issue2300(): args = [x, y, S(2), S.Half] def ok(a): """Return True if the input args for diff are ok""" if not a: return False if a[0].is_Symbol is False: return False s_at = [i for i in range(len(a)) if a[i].is_Symbol] n_at = [i for i in range(len(a)) if not a[i].is_Symbol] # every symbol is followed by symbol or int # every number is followed by a symbol return (all(a[i+1].is_Symbol or a[i+1].is_Integer for i in s_at if i+1<len(a)) and all(a[i+1].is_Symbol for i in n_at if i+1<len(a))) eq = x**10*y**8 for a in subsets(args): for v in variations(a, len(a)): if ok(v): noraise = eq.diff(*v) else: raises(ValueError, 'eq.diff(*v)')
def test_issue2300(): args = [x, y, S(2), S.Half] def ok(a): """Return True if the input args for diff are ok""" if not a: return False if a[0].is_Symbol is False: return False s_at = [i for i in range(len(a)) if a[i].is_Symbol] n_at = [i for i in range(len(a)) if not a[i].is_Symbol] # every symbol is followed by symbol or int # every number is followed by a symbol return (all([a[i+1].is_Symbol or a[i+1].is_Integer for i in s_at if i+1<len(a)]) and all([a[i+1].is_Symbol for i in n_at if i+1<len(a)])) eq = x**10*y**8 for a in subsets(args): for v in variations(a, len(a)): if ok(v): noraise = eq.diff(*v) else: raises(ValueError, 'eq.diff(*v)')
def pairwise_most_common(sets): """Return a list of `(s, L)` tuples where `s` is the largest subset of elements that appear in pairs of sets given by `sets` and `L` is a list of tuples giving the indices of the pairs of sets in which those elements appeared. All `s` will be of the same length. Examples ======== >>> from sympy.simplify.cse_main import pairwise_most_common >>> pairwise_most_common(( ... {1,2,3}, ... {1,3,5}, ... {1,2,3,4,5}, ... {1,2,3,6})) [({1, 3, 5}, [(1, 2)]), ({1, 2, 3}, [(0, 2), (0, 3), (2, 3)])] >>> """ from sympy.utilities.iterables import subsets from collections import defaultdict most = -1 for i, j in subsets(list(range(len(sets))), 2): com = sets[i] & sets[j] if com and len(com) > most: best = defaultdict(list) best_keys = [] most = len(com) if len(com) == most: if com not in best_keys: best_keys.append(com) best[best_keys.index(com)].append((i, j)) if most == -1: return [] for k in range(len(best)): best_keys[k] = (best_keys[k], best[k]) best_keys.sort(key=lambda x: len(x[1])) return best_keys
def pairwise_most_common(sets): """Return a list of `(s, L)` tuples where `s` is the largest subset of elements that appear in pairs of sets given by `sets` and `L` is a list of tuples giving the indices of the pairs of sets in which those elements appeared. All `s` will be of the same length. Examples ======== >>> from sympy.simplify.cse_main import pairwise_most_common >>> pairwise_most_common(( ... {1,2,3}, ... {1,3,5}, ... {1,2,3,4,5}, ... {1,2,3,6})) [({1, 3, 5}, [(1, 2)]), ({1, 2, 3}, [(0, 2), (0, 3), (2, 3)])] >>> """ from sympy.utilities.iterables import subsets from collections import defaultdict most = -1 for i, j in subsets(list(range(len(sets))), 2): com = sets[i] & sets[j] if com and len(com) > most: best = defaultdict(list) best_keys = [] most = len(com) if len(com) == most: if com not in best_keys: best_keys.append(com) best[best_keys.index(com)].append((i,j)) if most == -1: return [] for k in range(len(best)): best_keys[k] = (best_keys[k], best[k]) best_keys.sort(key=lambda x: len(x[1])) return best_keys
def test_subsets(): assert list(subsets([1, 2, 3], 1)) == [[1], [2], [3]] assert list(subsets([1, 2, 3], 2)) == [[1, 2], [1, 3], [2, 3]] assert list(subsets([1, 2, 3], 3)) == [[1, 2, 3]]
def _match_common_args(Func, funcs): if order != 'none': funcs = list(ordered(funcs)) else: funcs = sorted(funcs, key=lambda x: len(x.args)) if Func is Mul: F = Pow meth = 'as_powers_dict' from sympy.core.add import _addsort as inplace_sorter elif Func is Add: F = Mul meth = 'as_coefficients_dict' from sympy.core.mul import _mulsort as inplace_sorter else: assert None # expected Mul or Add # ----------------- helpers --------------------------- def ufunc(*args): # return a well formed unevaluated function from the args # SHARES Func, inplace_sorter args = list(args) inplace_sorter(args) return Func(*args, evaluate=False) def as_dict(e): # creates a dictionary of the expression using either # as_coefficients_dict or as_powers_dict, depending on Func # SHARES meth d = getattr(e, meth, lambda: {a: S.One for a in e.args})() for k in list(d.keys()): try: as_int(d[k]) except ValueError: d[F(k, d.pop(k))] = S.One return d def from_dict(d): # build expression from dict from # as_coefficients_dict or as_powers_dict # SHARES F return ufunc(*[F(k, v) for k, v in d.items()]) def update(k): # updates all of the info associated with k using # the com_dict: func_dicts, func_args, opt_subs # returns True if all values were updated, else None # SHARES com_dict, com_func, func_dicts, func_args, # opt_subs, funcs, verbose for di in com_dict: # don't allow a sign to change if com_dict[di] > func_dicts[k][di]: return # remove it if Func is Add: take = min(func_dicts[k][i] for i in com_dict) _sum = from_dict(com_dict) if take == 1: com_func_take = _sum else: com_func_take = Mul(take, _sum, evaluate=False) else: take = igcd(*[func_dicts[k][i] for i in com_dict]) base = from_dict(com_dict) if take == 1: com_func_take = base else: com_func_take = Pow(base, take, evaluate=False) for di in com_dict: func_dicts[k][di] -= take * com_dict[di] # compute the remaining expression rem = from_dict(func_dicts[k]) # reject hollow change, e.g extracting x + 1 from x + 3 if Func is Add and rem and rem.is_Integer and 1 in com_dict: return if verbose: print('\nfunc %s (%s) \ncontains %s \nas %s \nleaving %s' % (funcs[k], func_dicts[k], com_func, com_func_take, rem)) # recompute the dict since some keys may now # have corresponding values of 0; one could # keep track of which ones went to zero but # this seems cleaner func_dicts[k] = as_dict(rem) # update associated info func_dicts[k][com_func] = take func_args[k] = set(func_dicts[k]) # keep the constant separate from the remaining # part of the expression, e.g. 2*(a*b) rather than 2*a*b opt_subs[funcs[k]] = ufunc(rem, com_func_take) # everything was updated return True def get_copy(i): return [func_dicts[i].copy(), func_args[i].copy(), funcs[i], i] def restore(dafi): i = dafi.pop() func_dicts[i], func_args[i], funcs[i] = dafi # ----------------- end helpers ----------------------- func_dicts = [as_dict(f) for f in funcs] func_args = [set(d) for d in func_dicts] while True: hit = pairwise_most_common(func_args) if not hit or len(hit[0][0]) <= 1: break changed = False for com_args, ij in hit: take = len(com_args) ALL = list(ordered(com_args)) while take >= 2: for com_args in subsets(ALL, take): com_func = Func(*com_args) com_dict = as_dict(com_func) for i, j in ij: dafi = None if com_func != funcs[i]: dafi = get_copy(i) ch = update(i) if not ch: restore(dafi) continue if com_func != funcs[j]: dafj = get_copy(j) ch = update(j) if not ch: if dafi is not None: restore(dafi) restore(dafj) continue changed = True if changed: break else: take -= 1 continue break else: continue break if not changed: break
def test_subsets(): assert list(subsets([1, 2, 3], 1)) == [[1], [2], [3]] assert list(subsets([1, 2, 3], 2)) == [[1, 2], [1,3], [2, 3]] assert list(subsets([1, 2, 3], 3)) == [[1, 2, 3]]
def delta(p): if len(p) == 1: return oo return min(abs(i[0] - i[1]) for i in subsets(p, 2))
def test_farthest_points_closest_points(): from random import randint from sympy.utilities.iterables import subsets for how in (min, max): if how is min: func = closest_points else: func = farthest_points raises(ValueError, lambda: func(Point2D(0, 0), Point2D(0, 0))) # 3rd pt dx is close and pt is closer to 1st pt p1 = [Point2D(0, 0), Point2D(3, 0), Point2D(1, 1)] # 3rd pt dx is close and pt is closer to 2nd pt p2 = [Point2D(0, 0), Point2D(3, 0), Point2D(2, 1)] # 3rd pt dx is close and but pt is not closer p3 = [Point2D(0, 0), Point2D(3, 0), Point2D(1, 10)] # 3rd pt dx is not closer and it's closer to 2nd pt p4 = [Point2D(0, 0), Point2D(3, 0), Point2D(4, 0)] # 3rd pt dx is not closer and it's closer to 1st pt p5 = [Point2D(0, 0), Point2D(3, 0), Point2D(-1, 0)] # duplicate point doesn't affect outcome dup = [Point2D(0, 0), Point2D(3, 0), Point2D(3, 0), Point2D(-1, 0)] # symbolic x = Symbol('x', positive=True) s = [Point2D(a) for a in ((x, 1), (x + 3, 2), (x + 2, 2))] for points in (p1, p2, p3, p4, p5, s, dup): d = how(i.distance(j) for i, j in subsets(points, 2)) ans = a, b = list(func(*points))[0] a.distance(b) == d assert ans == _ordered_points(ans) # if the following ever fails, the above tests were not sufficient # and the logical error in the routine should be fixed points = set() while len(points) != 7: points.add(Point2D(randint(1, 100), randint(1, 100))) points = list(points) d = how(i.distance(j) for i, j in subsets(points, 2)) ans = a, b = list(func(*points))[0] a.distance(b) == d assert ans == _ordered_points(ans) # equidistant points a, b, c = ( Point2D(0, 0), Point2D(1, 0), Point2D(S(1)/2, sqrt(3)/2)) ans = set([_ordered_points((i, j)) for i, j in subsets((a, b, c), 2)]) assert closest_points(b, c, a) == ans assert farthest_points(b, c, a) == ans # unique to farthest points = [(1, 1), (1, 2), (3, 1), (-5, 2), (15, 4)] assert farthest_points(*points) == set( [(Point2D(-5, 2), Point2D(15, 4))]) points = [(1, -1), (1, -2), (3, -1), (-5, -2), (15, -4)] assert farthest_points(*points) == set( [(Point2D(-5, -2), Point2D(15, -4))]) assert farthest_points((1, 1), (0, 0)) == set( [(Point2D(0, 0), Point2D(1, 1))]) raises(ValueError, lambda: farthest_points((1, 1)))
def zzx_zassenhaus(f): """Factor square-free polynomials over Z[x]. """ n = zzx_degree(f) if n == 1: return [f] A = zzx_max_norm(f) b = zzx_LC(f) B = abs(int(sqrt(n + 1) * 2**n * A * b)) C = (n + 1)**(2 * n) * A**(2 * n - 1) gamma = int(ceil(2 * log(C, 2))) prime_max = int(2 * gamma * log(gamma)) for p in xrange(3, prime_max + 1): if not isprime(p) or b % p == 0: continue F = gf_from_int_poly(f, p) if gf_sqf_p(F, p): break l = int(ceil(log(2 * B + 1, p))) modular = [] for ff in gf_factor_sqf(F, p)[1]: modular.append(gf_to_int_poly(ff, p)) g = zzx_hensel_lift(p, f, modular, l) T = set(range(len(g))) factors, s = [], 1 while 2 * s <= len(T): for S in subsets(T, s): G, H = [b], [b] S = set(S) for i in S: G = zzx_mul(G, g[i]) for i in T - S: H = zzx_mul(H, g[i]) G = zzx_trunc(G, p**l) H = zzx_trunc(H, p**l) G_norm = zzx_l1_norm(G) H_norm = zzx_l1_norm(H) if G_norm * H_norm <= B: T = T - S G = zzx_primitive(G)[1] f = zzx_primitive(H)[1] factors.append(G) b = zzx_LC(f) break else: s += 1 return factors + [f]
def almost_align(self): def slice_to_mask(L): """ Enables to use slicing operator like array[x, y, :, z] with choosing the position of the symbol ':' (represented with a -1 instead). For example L can be equal to [0, 0, -1, 0] if we want to access self.board[0, 0, :, 0] """ mask = np.zeros([self.size] * self.n_dim, dtype=bool) dim = L.index(-1) for tile in range(self.size): L[dim] = tile mask[tuple(L)] = True return mask # vertical and horizontal axis all_axis = [] for d in range(self.size ** self.n_dim): all_axis.append([(d // self.size ** k) % self.size for k in range(self.n_dim)[::-1]]) # example in 3D case with size 3 : # all_axis = [ [i, j, k] for i = 0, 1, 2 for j = 0, 1, 2 for k = 0, 1, 2 ] for d in range(self.n_dim): d_axis = np.array(all_axis) d_axis[:, d] = -1 d_axis = np.unique(d_axis, axis=0) for axis in d_axis: space_mask = slice_to_mask(list(axis)) in_game_axis = self.board[space_mask] axis_value = in_game_axis.sum().item() if axis_value == self.size - 1 and -1 not in in_game_axis: for coords in np.argwhere(space_mask == True): if self.board[tuple(coords)] == 0: return tuple(coords) elif axis_value == -self.size + 1 and 1 not in in_game_axis: for coords in np.argwhere(space_mask == True): if self.board[tuple(coords)] == 0: return tuple(coords) # diagonal axis diag = np.array([range(self.size)]).T antidiag = np.array([range(self.size - 1, -1, -1)]).T poss_diag = np.array([diag, antidiag]) poss_index = list(range(self.size)) coords_to_check = set() for dof in range(self.n_dim - 2, -1, -1): dof_fc = self.n_dim - dof cpt = 0 for fc in subsets(poss_diag, dof_fc, repetition=True): if cpt == int(dof_fc / 2) + 1: break cpt += 1 frozen_comp = np.array(fc).reshape((dof_fc, self.size)).T if dof > 0: for free_comp in subsets(poss_index, dof, repetition=True): free_comp_array = np.repeat(np.array([free_comp]), self.size, axis=0) coords = np.hstack((free_comp_array, frozen_comp)) for perm in multiset_permutations(coords.T.tolist()): perm_coords = [list(i) for i in zip(*perm)] perm_coords.sort() coords_to_check.add(tuple(map(tuple, perm_coords))) else: coords = frozen_comp for perm in multiset_permutations(coords.T.tolist()): perm_coords = [list(i) for i in zip(*perm)] perm_coords.sort() coords_to_check.add(tuple(map(tuple, perm_coords))) for coords in coords_to_check: total_pos, total_neg = 0, 0 for tile in coords: if self.board[tile] == 1: total_pos += 1 elif self.board[tile] == -1: total_neg += 1 if total_pos == self.size - 1 and total_neg == 0: for tile in coords: if self.board[tile] == 0: return tile elif total_neg == self.size - 1 and total_pos == 0: for tile in coords: if self.board[tile] == 0: return tile return None
def test_subsets(): # combinations assert list(subsets([1, 2, 3], 0)) == [()] assert list(subsets([1, 2, 3], 1)) == [(1,), (2,), (3,)] assert list(subsets([1, 2, 3], 2)) == [(1, 2), (1, 3), (2, 3)] assert list(subsets([1, 2, 3], 3)) == [(1, 2, 3)] l = range(4) assert list(subsets(l, 0, repetition=True)) == [()] assert list(subsets(l, 1, repetition=True)) == [(0,), (1,), (2,), (3,)] assert list(subsets(l, 2, repetition=True)) == [(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] assert list(subsets(l, 3, repetition=True)) == [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 2), (0, 2, 3), (0, 3, 3), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (1, 3, 3), (2, 2, 2), (2, 2, 3), (2, 3, 3), (3, 3, 3)] assert len(list(subsets(l, 4, repetition=True))) == 35 assert list(subsets(l[:2], 3, repetition=False)) == [] assert list(subsets(l[:2], 3, repetition=True)) == [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)] assert list(subsets([1, 2], repetition=True)) == \ [(), (1,), (2,), (1, 1), (1, 2), (2, 2)] assert list(subsets([1, 2], repetition=False)) == \ [(), (1,), (2,), (1, 2)] assert list(subsets([1, 2, 3], 2)) == \ [(1, 2), (1, 3), (2, 3)] assert list(subsets([1, 2, 3], 2, repetition=True)) == \ [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
def _match_common_args(Func, funcs): if order != 'none': funcs = list(ordered(funcs)) else: funcs = sorted(funcs, key=lambda x: len(x.args)) if Func is Mul: F = Pow meth = 'as_powers_dict' from sympy.core.add import _addsort as inplace_sorter elif Func is Add: F = Mul meth = 'as_coefficients_dict' from sympy.core.mul import _mulsort as inplace_sorter else: assert None # expected Mul or Add # ----------------- helpers --------------------------- def ufunc(*args): # return a well formed unevaluated function from the args # SHARES Func, inplace_sorter args = list(args) inplace_sorter(args) return Func(*args, evaluate=False) def as_dict(e): # creates a dictionary of the expression using either # as_coefficients_dict or as_powers_dict, depending on Func # SHARES meth d = getattr(e, meth, lambda: {a: S.One for a in e.args})() for k in list(d.keys()): try: as_int(d[k]) except ValueError: d[F(k, d.pop(k))] = S.One return d def from_dict(d): # build expression from dict from # as_coefficients_dict or as_powers_dict # SHARES F return ufunc(*[F(k, v) for k, v in d.items()]) def update(k): # updates all of the info associated with k using # the com_dict: func_dicts, func_args, opt_subs # returns True if all values were updated, else None # SHARES com_dict, com_func, func_dicts, func_args, # opt_subs, funcs, verbose for di in com_dict: # don't allow a sign to change if com_dict[di] > func_dicts[k][di]: return # remove it if Func is Add: take = min(func_dicts[k][i] for i in com_dict) com_func_take = Mul(take, from_dict(com_dict), evaluate=False) else: take = igcd(*[func_dicts[k][i] for i in com_dict]) com_func_take = Pow(from_dict(com_dict), take, evaluate=False) for di in com_dict: func_dicts[k][di] -= take*com_dict[di] # compute the remaining expression rem = from_dict(func_dicts[k]) # reject hollow change, e.g extracting x + 1 from x + 3 if Func is Add and rem and rem.is_Integer and 1 in com_dict: return if verbose: print('\nfunc %s (%s) \ncontains %s \nas %s \nleaving %s' % (funcs[k], func_dicts[k], com_func, com_func_take, rem)) # recompute the dict since some keys may now # have corresponding values of 0; one could # keep track of which ones went to zero but # this seems cleaner func_dicts[k] = as_dict(rem) # update associated info func_dicts[k][com_func] = take func_args[k] = set(func_dicts[k]) # keep the constant separate from the remaining # part of the expression, e.g. 2*(a*b) rather than 2*a*b opt_subs[funcs[k]] = ufunc(rem, com_func_take) # everything was updated return True def get_copy(i): return [func_dicts[i].copy(), func_args[i].copy(), funcs[i], i] def restore(dafi): i = dafi.pop() func_dicts[i], func_args[i], funcs[i] = dafi # ----------------- end helpers ----------------------- func_dicts = [as_dict(f) for f in funcs] func_args = [set(d) for d in func_dicts] while True: hit = pairwise_most_common(func_args) if not hit or len(hit[0][0]) <= 1: break changed = False for com_args, ij in hit: take = len(com_args) ALL = list(ordered(com_args)) while take >= 2: for com_args in subsets(ALL, take): com_func = Func(*com_args) com_dict = as_dict(com_func) for i, j in ij: dafi = None if com_func != funcs[i]: dafi = get_copy(i) ch = update(i) if not ch: restore(dafi) continue if com_func != funcs[j]: dafj = get_copy(j) ch = update(j) if not ch: if dafi is not None: restore(dafi) restore(dafj) continue changed = True if changed: break else: take -= 1 continue break else: continue break if not changed: break
def test_arguments(): """Functions accepting `Point` objects in `geometry` should also accept tuples and lists and automatically convert them to points.""" singles2d = ((1,2), [1,2], Point(1,2)) singles2d2 = ((1,3), [1,3], Point(1,3)) doubles2d = cartes(singles2d, singles2d2) p2d = Point2D(1,2) singles3d = ((1,2,3), [1,2,3], Point(1,2,3)) doubles3d = subsets(singles3d, 2) p3d = Point3D(1,2,3) singles4d = ((1,2,3,4), [1,2,3,4], Point(1,2,3,4)) doubles4d = subsets(singles4d, 2) p4d = Point(1,2,3,4) # test 2D test_single = ['distance', 'is_scalar_multiple', 'taxicab_distance', 'midpoint', 'intersection', 'dot', 'equals', '__add__', '__sub__'] test_double = ['is_concyclic', 'is_collinear'] for p in singles2d: Point2D(p) for func in test_single: for p in singles2d: getattr(p2d, func)(p) for func in test_double: for p in doubles2d: getattr(p2d, func)(*p) # test 3D test_double = ['is_collinear'] for p in singles3d: Point3D(p) for func in test_single: for p in singles3d: getattr(p3d, func)(p) for func in test_double: for p in doubles2d: getattr(p3d, func)(*p) # test 4D test_double = ['is_collinear'] for p in singles4d: Point(p) for func in test_single: for p in singles4d: getattr(p4d, func)(p) for func in test_double: for p in doubles4d: getattr(p4d, func)(*p) # test evaluate=False for ops x = Symbol('x') a = Point(0, 1) assert a + (0.1, x) == Point(0.1, 1 + x) a = Point(0, 1) assert a/10.0 == Point(0.0, 0.1) a = Point(0, 1) assert a*10.0 == Point(0.0, 10.0) # test evaluate=False when changing dimensions u = Point(.1, .2, evaluate=False) u4 = Point(u, dim=4, on_morph='ignore') assert u4.args == (.1, .2, 0, 0) assert all(i.is_Float for i in u4.args[:2]) # and even when *not* changing dimensions assert all(i.is_Float for i in Point(u).args) # never raise error if creating an origin assert Point(dim=3, on_morph='error')
def test_subsets(): # combinations assert list(subsets([1, 2, 3], 0)) == [[]] assert list(subsets([1, 2, 3], 1)) == [[1], [2], [3]] assert list(subsets([1, 2, 3], 2)) == [[1, 2], [1,3], [2, 3]] assert list(subsets([1, 2, 3], 3)) == [[1, 2, 3]] l = range(4) assert list(subsets(l, 0, repetition=True)) == [[]] assert list(subsets(l, 1, repetition=True)) == [[0], [1], [2], [3]] assert list(subsets(l, 2, repetition=True)) == [[0, 0], [0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]] assert list(subsets(l, 3, repetition=True)) == [[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 0, 3], [0, 1, 1], [0, 1, 2], [0, 1, 3], [0, 2, 2], [0, 2, 3], [0, 3, 3], [1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 2, 3], [1, 3, 3], [2, 2, 2], [2, 2, 3], [2, 3, 3], [3, 3, 3]] assert len(list(subsets(l, 4, repetition=True))) == 35 assert list(subsets(l[:2], 3, repetition=False)) == [] assert list(subsets(l[:2], 3, repetition=True)) == [[0, 0, 0], [0, 0, 1], [0, 1, 1], [1, 1, 1]] assert list(subsets([1, 2], repetition=True)) == \ [[], [1], [2], [1, 1], [1, 2], [2, 2]] assert list(subsets([1, 2], repetition=False)) == \ [[], [1], [2], [1, 2]] assert list(subsets([1, 2, 3], 2)) == \ [[1, 2], [1, 3], [2, 3]] assert list(subsets([1, 2, 3], 2, repetition=True)) == \ [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]]
def test_arguments(): """Functions accepting `Point` objects in `geometry` should also accept tuples and lists and automatically convert them to points.""" singles2d = ((1, 2), [1, 2], Point(1, 2)) singles2d2 = ((1, 3), [1, 3], Point(1, 3)) doubles2d = cartes(singles2d, singles2d2) p2d = Point2D(1, 2) singles3d = ((1, 2, 3), [1, 2, 3], Point(1, 2, 3)) doubles3d = subsets(singles3d, 2) p3d = Point3D(1, 2, 3) singles4d = ((1, 2, 3, 4), [1, 2, 3, 4], Point(1, 2, 3, 4)) doubles4d = subsets(singles4d, 2) p4d = Point(1, 2, 3, 4) # test 2D test_single = [ 'distance', 'is_scalar_multiple', 'taxicab_distance', 'midpoint', 'intersection', 'dot', 'equals', '__add__', '__sub__' ] test_double = ['is_concyclic', 'is_collinear'] for p in singles2d: Point2D(p) for func in test_single: for p in singles2d: getattr(p2d, func)(p) for func in test_double: for p in doubles2d: getattr(p2d, func)(*p) # test 3D test_double = ['is_collinear'] for p in singles3d: Point3D(p) for func in test_single: for p in singles3d: getattr(p3d, func)(p) for func in test_double: for p in doubles3d: getattr(p3d, func)(*p) # test 4D test_double = ['is_collinear'] for p in singles4d: Point(p) for func in test_single: for p in singles4d: getattr(p4d, func)(p) for func in test_double: for p in doubles4d: getattr(p4d, func)(*p) # test evaluate=False for ops x = Symbol('x') a = Point(0, 1) assert a + (0.1, x) == Point(0.1, 1 + x, evaluate=False) a = Point(0, 1) assert a / 10.0 == Point(0, 0.1, evaluate=False) a = Point(0, 1) assert a * 10.0 == Point(0.0, 10.0, evaluate=False) # test evaluate=False when changing dimensions u = Point(.1, .2, evaluate=False) u4 = Point(u, dim=4, on_morph='ignore') assert u4.args == (.1, .2, 0, 0) assert all(i.is_Float for i in u4.args[:2]) # and even when *not* changing dimensions assert all(i.is_Float for i in Point(u).args) # never raise error if creating an origin assert Point(dim=3, on_morph='error')
def test_subsets(): # combinations assert list(subsets([1, 2, 3], 0)) == [[]] assert list(subsets([1, 2, 3], 1)) == [[1], [2], [3]] assert list(subsets([1, 2, 3], 2)) == [[1, 2], [1, 3], [2, 3]] assert list(subsets([1, 2, 3], 3)) == [[1, 2, 3]] l = range(4) assert list(subsets(l, 0, repetition=True)) == [[]] assert list(subsets(l, 1, repetition=True)) == [[0], [1], [2], [3]] assert list(subsets(l, 2, repetition=True)) == [[0, 0], [0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]] assert list(subsets(l, 3, repetition=True)) == [[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 0, 3], [0, 1, 1], [0, 1, 2], [0, 1, 3], [0, 2, 2], [0, 2, 3], [0, 3, 3], [1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 2, 3], [1, 3, 3], [2, 2, 2], [2, 2, 3], [2, 3, 3], [3, 3, 3]] assert len(list(subsets(l, 4, repetition=True))) == 35 assert list(subsets(l[:2], 3, repetition=False)) == [] assert list(subsets(l[:2], 3, repetition=True)) == [[0, 0, 0], [0, 0, 1], [0, 1, 1], [1, 1, 1]] assert list(subsets([1, 2], repetition=True)) == \ [[], [1], [2], [1, 1], [1, 2], [2, 2]] assert list(subsets([1, 2], repetition=False)) == \ [[], [1], [2], [1, 2]] assert list(subsets([1, 2, 3], 2)) == \ [[1, 2], [1, 3], [2, 3]] assert list(subsets([1, 2, 3], 2, repetition=True)) == \ [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]]
def test_subsets(): # combinations assert list(subsets([1, 2, 3], 0)) == [()] assert list(subsets([1, 2, 3], 1)) == [(1, ), (2, ), (3, )] assert list(subsets([1, 2, 3], 2)) == [(1, 2), (1, 3), (2, 3)] assert list(subsets([1, 2, 3], 3)) == [(1, 2, 3)] l = list(range(4)) assert list(subsets(l, 0, repetition=True)) == [()] assert list(subsets(l, 1, repetition=True)) == [(0, ), (1, ), (2, ), (3, )] assert list(subsets(l, 2, repetition=True)) == [(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] assert list(subsets(l, 3, repetition=True)) == [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 2), (0, 2, 3), (0, 3, 3), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (1, 3, 3), (2, 2, 2), (2, 2, 3), (2, 3, 3), (3, 3, 3)] assert len(list(subsets(l, 4, repetition=True))) == 35 assert list(subsets(l[:2], 3, repetition=False)) == [] assert list(subsets(l[:2], 3, repetition=True)) == [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)] assert list(subsets([1, 2], repetition=True)) == \ [(), (1,), (2,), (1, 1), (1, 2), (2, 2)] assert list(subsets([1, 2], repetition=False)) == \ [(), (1,), (2,), (1, 2)] assert list(subsets([1, 2, 3], 2)) == \ [(1, 2), (1, 3), (2, 3)] assert list(subsets([1, 2, 3], 2, repetition=True)) == \ [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
def zzx_zassenhaus(f): """Factor square-free polynomials over Z[x]. """ n = zzx_degree(f) if n == 1: return [f] A = zzx_max_norm(f) b = zzx_LC(f) B = abs(int(sqrt(n+1)*2**n*A*b)) C = (n+1)**(2*n)*A**(2*n-1) gamma = int(ceil(2*log(C, 2))) prime_max = int(2*gamma*log(gamma)) for p in xrange(3, prime_max+1): if not isprime(p) or b % p == 0: continue F = gf_from_int_poly(f, p) if gf_sqf_p(F, p): break l = int(ceil(log(2*B + 1, p))) modular = [] for ff in gf_factor_sqf(F, p)[1]: modular.append(gf_to_int_poly(ff, p)) g = zzx_hensel_lift(p, f, modular, l) T = set(range(len(g))) factors, s = [], 1 while 2*s <= len(T): for S in subsets(T, s): G, H = [b], [b] S = set(S) for i in S: G = zzx_mul(G, g[i]) for i in T-S: H = zzx_mul(H, g[i]) G = zzx_trunc(G, p**l) H = zzx_trunc(H, p**l) G_norm = zzx_l1_norm(G) H_norm = zzx_l1_norm(H) if G_norm*H_norm <= B: T = T - S G = zzx_primitive(G)[1] f = zzx_primitive(H)[1] factors.append(G) b = zzx_LC(f) break else: s += 1 return factors + [f]