def test_trivial_searches(self): from sage.all import Subsets for begin in [ ('level=10&weight=1-20&dim=1', ['Results (displaying all 21 matches)', '171901114', 'No', '10.723', 'A-L signs'] ), ('level=10%2C13%2C17&weight=1-8&dim=1', ['Results (displaying all 12 matches)', '1373', 'No', '0.136'] )]: for s in Subsets(['has_self_twist=no', 'is_self_dual=yes', 'nf_label=1.1.1.1','char_order=1','inner_twist_count=1']): s = '&'.join(['/ModularForm/GL2/Q/holomorphic/?search_type=List', begin[0]] + list(s)) page = self.tc.get(s, follow_redirects=True) for elt in begin[1]: assert elt in page.data, s for begin in [ ('level=1-330&weight=1&projective_image=D2', ['Results (displaying all 49 matches)', '328.1.c.a', r"\sqrt{-82}", r"\sqrt{-323}", r"\sqrt{109}"] ), ('level=900-1000&weight=1-&projective_image=D2', ['Results (displaying all 26 matches)', r"\sqrt{-1}", r"\sqrt{-995}", r"\sqrt{137}"] )]: for s in Subsets(['has_self_twist=yes', 'has_self_twist=cm', 'has_self_twist=rm', 'projective_image_type=Dn','dim=1-4']): s = '&'.join(['/ModularForm/GL2/Q/holomorphic/?search_type=List', begin[0]] + list(s)) page = self.tc.get(s, follow_redirects=True) for elt in begin[1]: assert elt in page.data, s
def padically_evaluate_regular(self, datum): T = datum.toric_datum if not T.is_regular(): raise ValueError('Can only processed regular toric data') M = Set(range(T.length())) q = SR.var('q') alpha = {} for I in Subsets(M): F = [T.initials[i] for i in I] V = SubvarietyOfTorus(F, torus_dim=T.ambient_dim) alpha[I] = V.count() def cat(u, v): return vector(list(u) + list(v)) for I in Subsets(M): cnt = sum((-1)**len(J) * alpha[I + J] for J in Subsets(M - I)) if not cnt: continue P = DirectProductOfPolyhedra(T.polyhedron, StrictlyPositiveOrthant(len(I))) it = iter(identity_matrix(ZZ, len(I)).rows()) ieqs = [] for i in M: ieqs.append( cat( vector(ZZ, (0, )), cat( vector(ZZ, T.initials[i].exponents()[0]) - vector(ZZ, T.lhs[i].exponents()[0]), next(it) if i in I else zero_vector(ZZ, len(I))))) if not ieqs: ieqs = [vector(ZZ, (T.ambient_dim + len(I) + 1) * [0])] Q = Polyhedron(ieqs=ieqs, base_ring=QQ, ambient_dim=T.ambient_dim + len(I)) foo, ring = symbolic_to_ratfun( cnt * (q - 1)**len(I) / q**(T.ambient_dim), [var('t'), var('q')]) corr_cnt = CyclotomicRationalFunction.from_laurent_polynomial( foo, ring) Phi = matrix([ cat(T.integrand[0], zero_vector(ZZ, len(I))), cat(T.integrand[1], vector(ZZ, len(I) * [-1])) ]).transpose() sm = RationalSet([P.intersection(Q)]).generating_function() for z in sm.monomial_substitution(QQ['t', 'q'], Phi): yield corr_cnt * z
def topologically_evaluate_regular(self, datum): if not datum.is_regular(): raise ValueError('need a regular datum') euler_cap = {} torus_factor_dim = {} N = Set(range(len(datum.polynomials))) _, d, _ = split_off_torus([datum.initials[i].num for i in N]) min_dim = datum.ambient_dim - d # NOTE: triangulation/"topologisation" of RationalSet instances only # considers cones of maximal dimension. if datum.RS.dim() <= min_dim - 2: return yield if datum.RS.dim() >= min_dim: raise RuntimeError('this should be impossible') for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) U,W = V.split_off_torus() torus_factor_dim[I] = W.torus_dim assert torus_factor_dim[I] >= min_dim if W.torus_dim > min_dim: continue euler_cap[I] = U.khovanskii_characteristic() if U.is_nondegenerate() else U.euler_characteristic() for I in Subsets(N): chi = sum((-1)**len(J) * euler_cap[I + J] for J in Subsets(N - I) if torus_factor_dim[I + J] == min_dim) if not chi: continue I = list(I) id = identity_matrix(ZZ, len(I)) def vectorise(first, k, vec): w = id[I.index(k)] if k in I else vector(ZZ,len(I)) return vector(ZZ, [first] + list(vec) + list(w)) polytopes = [] for (i, j) in self.pairs: vertices = [vectorise(0, k, datum.ideals[i].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[i])] +\ [vectorise(1, k, datum.ideals[j].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[j])] polytopes.append(Polyhedron(vertices=vertices, ambient_dim=1+datum.ambient_dim + len(I))) extended_RS = (RationalSet(StrictlyPositiveOrthant(1)) * datum.RS * RationalSet(StrictlyPositiveOrthant(len(I)))) for surf in topologically_evaluate_monomial_integral(extended_RS, polytopes, self.integrand, dims=[min_dim+len(I)]): yield SURF(scalar=chi*surf.scalar, rays=surf.rays)
def topologically_evaluate_regular(self, datum): if not datum.is_regular(): raise ValueError('need a regular datum') euler_cap = {} torus_factor_dim = {} N = Set(range(len(datum.polynomials))) _, d, _ = split_off_torus([datum.initials[i].num for i in N]) min_dim = datum.ambient_dim - d if datum.RS.dim() < min_dim: logger.debug('Totally irrelevant datum') return yield for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) U,W = V.split_off_torus() torus_factor_dim[I] = W.torus_dim euler_cap[I] = U.khovanskii_characteristic() if U.is_nondegenerate() else U.euler_characteristic() assert torus_factor_dim[I] >= min_dim for I in Subsets(N): chi = sum((-1)**len(J) * euler_cap[I+J] for J in Subsets(N-I) if torus_factor_dim[I+J] == min_dim) if not chi: logger.debug('Vanishing Euler characteristic: I = %s' % I) continue I = list(I) polytopes = [] id = identity_matrix(ZZ, len(I)) def vectorise(k, vec): w = id[I.index(k)] if k in I else vector(ZZ,len(I)) return vector(ZZ, list(vec) + list(w)) assert len(datum._ideal2poly[0]) == len(datum.ideals[0].gens) polytopes = [Polyhedron(vertices=[vectorise(k, datum.ideals[0].initials[m].exponents()[0]) for m,k in enumerate(datum._ideal2poly[0])], ambient_dim=datum.ambient_dim+len(I))] extended_RS = datum.RS * RationalSet(StrictlyPositiveOrthant(len(I))) assert all(extended_RS.ambient_dim == P.ambient_dim() for P in polytopes) for surf in topologically_evaluate_monomial_integral(extended_RS, polytopes, [ (1,), (0,) ], dims=[min_dim + len(I)], ): yield SURF(scalar=chi*surf.scalar, rays=surf.rays)
def padically_evaluate_regular(self, datum, extra_RS=None): if not datum.is_regular(): raise ValueError('need a regular datum') # The extra variable's valuation is in extra_RS. if extra_RS is None: extra_RS = RationalSet(StrictlyPositiveOrthant(1)) q = var('q') count_cap = {} N = Set(range(len(datum.polynomials))) for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) count_cap[I] = V.count() # BEGIN SANITY CHECK # q = var('q') # u, w = V.split_off_torus() # assert ((count_cap[I]/(q-1)**w.torus_dim).simplify_full())(q=1) == u.euler_characteristic() # END SANITY CHECK for I in Subsets(N): cnt = sum((-1)**len(J) * count_cap[I + J] for J in Subsets(N - I)) if not cnt: continue I = list(I) id = identity_matrix(ZZ, len(I)) def vectorise(first, k, vec): w = id[I.index(k)] if k in I else vector(ZZ, len(I)) return vector(ZZ, [first] + list(vec) + list(w)) polytopes = [] for (i, j) in self.pairs: vertices = [vectorise(0, k, datum.ideals[i].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[i])] +\ [vectorise(1, k, datum.ideals[j].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[j])] polytopes.append(Polyhedron(vertices=vertices, ambient_dim=1 + datum.ambient_dim + len(I))) extended_RS = extra_RS * datum.RS * RationalSet(StrictlyPositiveOrthant(len(I))) foo, ring = symbolic_to_ratfun(cnt * (q - 1)**(1 + len(I)) / q**(1 + datum.ambient_dim), [var('t'), var('q')]) corr_cnt = CyclotomicRationalFunction.from_laurent_polynomial(foo, ring) for z in padically_evaluate_monomial_integral(extended_RS, polytopes, self.integrand): yield corr_cnt * z
def zero_forcing_set_bruteforce(graph, bound=None): """ Return a zero forcing set of minimum order that also has order less than the given bound. :param graph: the graph on which to find the zero-forcing set :param bound: the maximum acceptable order for a zero-forcing set :type bound: integer :return: a zero-forcing set of minimum order that also has order less than the bound if one exists; False if no such zero-forcing set can be found EXAMPLES:: sage: from sage.graphs.minrank import zero_forcing_set_bruteforce sage: zero_forcing_set_bruteforce(graphs.CompleteGraph(5)) {0, 1, 2, 3} sage: zero_forcing_set_bruteforce(graphs.CompleteGraph(5),2) False """ from sage.all import Subsets order = graph.order() if bound is None: bound = order if bound < 0: bound = 1 vertices = graph.vertices() mindegree = min(graph.degree()) for i in range(mindegree, bound + 1): for subset in Subsets(vertices, i): outcome = zerosgame(graph, subset) if len(outcome) == order: return subset return False
def principal_minors(A, size): m = A.nrows() n = A.ncols() r = min(m, n) li = [] for idx in Subsets(range(r), size): idx = list(idx) li.append(A.base_ring()(A.matrix_from_rows_and_columns( idx, idx).determinant())) return li
def get_way_count(surface_count): n = (surface_count + 3) // 2 factors = [x for x, _ in factor(n)] def f(x): first_k = (x * (-x % 3) - 2) // 3 last_k = (n - 2) // 3 last_k = last_k - (last_k - first_k) % x return (last_k - first_k) // x + 1 return ((n - 2) // 3 + 1 + sum( (+1 if len(subset) % 2 == 0 else -1) * f(prod(subset)) for subset in Subsets(factors) if subset))
def padically_evaluate_regular(self, datum): if not datum.is_regular(): raise ValueError('need a regular datum') q = var('q') count_cap = {} N = Set(range(len(datum.polynomials))) for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) count_cap[I] = V.count() for I in Subsets(N): cnt = sum((-1)**len(J) * count_cap[I+J] for J in Subsets(N-I)) if not cnt: continue I = list(I) polytopes = [] id = identity_matrix(ZZ, len(I)) def vectorise(k, vec): w = id[I.index(k)] if k in I else vector(ZZ,len(I)) return vector(ZZ, list(vec) + list(w)) assert len(datum._ideal2poly[0]) == len(datum.ideals[0].gens) polytopes = [Polyhedron(vertices=[ vectorise(k, datum.ideals[0].initials[m].exponents()[0]) for m,k in enumerate(datum._ideal2poly[0]) ], ambient_dim=datum.ambient_dim+len(I))] extended_RS = datum.RS * RationalSet(StrictlyPositiveOrthant(len(I))) foo, ring = symbolic_to_ratfun(cnt * (q - 1)**len(I) / q**datum.ambient_dim, [var('t'), var('q')]) corr_cnt = CyclotomicRationalFunction.from_laurent_polynomial(foo, ring) assert all(extended_RS.ambient_dim == P.ambient_dim() for P in polytopes) for z in padically_evaluate_monomial_integral(extended_RS, polytopes, [ (1,), (0,) ]): yield corr_cnt * z
def _res_arr(n): from sage.all import Subsets, HyperplaneArrangements, QQ, Matrix Subs = Subsets(range(1, n + 1)) def S_vec(S): v = [QQ(0)] * (n + 1) for s in S: v[s] = QQ(1) return v M = [S_vec(S) for S in Subs if len(S) > 0] HH = HyperplaneArrangements(QQ, tuple(['x' + str(k) for k in range(n)])) H = HH(Matrix(QQ, M)) return H
def zero_forcing_set_bruteforce(graph, bound=None, all_sets=False): """ Return a zero forcing set of minimum order that also has order less than the given bound. :param graph: the graph on which to find the zero-forcing set :param int bound: the maximum acceptable order for a zero-forcing set :param bool all_sets: whether to return all zero forcing sets or just the first one :return: a zero-forcing set (or list of all zero-forcing sets if all_sets is True) of minimum order that also has order less than the bound if one exists; False if no such zero-forcing set can be found. EXAMPLES:: sage: from sage.graphs.minrank import zero_forcing_set_bruteforce sage: zero_forcing_set_bruteforce(graphs.CompleteGraph(5)) {0, 1, 2, 3} sage: zero_forcing_set_bruteforce(graphs.CompleteGraph(5),2) False sage: zero-forcing_set_bruteforce(graphs.CompleteGraph(5), all_sets=True) [{0, 1, 2, 3}, {0, 1, 2, 4}, {0, 1, 3, 4}, {0, 2, 3, 4}, {1, 2, 3, 4}] """ from sage.all import Subsets order = graph.order() if bound is None: bound = order if bound < 0: bound = 1 found_zfs = False zfs_sets = [] vertices = graph.vertices() mindegree = min(graph.degree()) for i in range(mindegree, bound + 1): if found_zfs: break for subset in Subsets(vertices, i): outcome = zerosgame(graph, subset) if len(outcome) == order: if all_sets: found_zfs = True zfs_sets.append(subset) else: return subset if found_zfs: return zfs_sets else: return False
def _mixed_volume_naive(gen): """ Naive computation of the normalised mixed volume using Cox et al., 'Using Algebraic Geometry', Thm 7.4.12. """ P = list(gen) n = len(P) if any(q.ambient_dim() != n for q in P): raise TypeError( 'Number of polytopes and ambient dimension do not match') res = 0 for I in Subsets(range(n)): if not I: continue res += (-1)**len(I) * (sum(P[i] for i in I)).volume() return (-1)**n / Integer(factorial(n)) * res
def is_nondegenerate(F, all_subsets=True, all_initial_forms=True, collision_handler=None): # NOTE: Setting all_subsets=False gives exactly Khovanskii's original # non-degeneracy condition. logger.debug('Original polynomials: %s' % F) if not F: return True if 0 in F: raise NotImplementedError() for G, _ in relative_initial_forms(F) if all_initial_forms else [(F, None)]: # NOTE: we could do the torus factor splitting for each subset separately. G, _, _ = split_off_torus(G) logger.debug('Restricted polynomials: %s' % G) R = G[0].parent() jac = jacobian(G, R.gens()) idx = [i for i in range(len(G)) if not G[i].is_monomial()] if not all_subsets and len(idx) < len(G): continue # empty variety! logger.debug('Active indices: %s' % idx) S = Subsets(idx) if all_subsets else [idx] for J in S: if not J: continue I = R.ideal([G[j] for j in J] + matrix(R, [jac[j] for j in J]).minors(len(J))) if not belongs_to_radical(prod(R.gens()), I): logger.debug('Collision: %s' % J) if collision_handler is not None: collision_handler(J) return False return True
def height_function(self, vertex_edge_collisions, extra_layers=0, edge_edge_collisions=[]): r""" Return a height function of edges if possible for given vertex-edge collisions. WARNING: Costly, since it runs through all edge-colorings. """ def e2s(e): return Set(e) for v in vertex_edge_collisions: vertex_edge_collisions[v] = Set([e2s(e) for e in vertex_edge_collisions[v]]) collision_graph = Graph([[e2s(e) for e in self._graph.edges(labels=False)],[]],format='vertices_and_edges') for u in self._graph.vertices(): collision_graph.add_edges([[e2s([u,v]),e2s([u,w]),''] for v,w in Subsets(self._graph.neighbors(u),2)]) for e in collision_graph.vertices(): for v in vertex_edge_collisions: if v in e: for f in vertex_edge_collisions[v]: collision_graph.add_edge([e2s(f), e2s(e), 'col']) for e, f in edge_edge_collisions: collision_graph.add_edge([e2s(f), e2s(e), 'e-e_col']) from sage.graphs.graph_coloring import all_graph_colorings optimal = False chrom_number = collision_graph.chromatic_number() for j in range(0, extra_layers + 1): i = 1 res = [] num_layers = chrom_number + j min_s = len(self._graph.vertices())*num_layers for col in all_graph_colorings(collision_graph,num_layers): if len(Set(col.keys()))<num_layers: continue layers = {} for h in col: layers[h] = [u for e in col[h] for u in e] col_free = True A = [] for v in vertex_edge_collisions: A_min_v = min([h for h in layers if v in layers[h]]) A_max_v = max([h for h in layers if v in layers[h]]) A.append([A_min_v, A_max_v]) for h in range(A_min_v+1,A_max_v): if v not in layers[h]: if len(Set(col[h]).intersection(vertex_edge_collisions[v]))>0: col_free = False break if not col_free: break if col_free: s = 0 for v in self._graph.vertices(): A_min_v = min([h for h in layers if v in layers[h]]) A_max_v = max([h for h in layers if v in layers[h]]) s += A_max_v - A_min_v if s<min_s: min_s = s res.append((col, s, A)) i += 1 if s==2*len(self._graph.edges())-len(self._graph.vertices()): optimal = True break if optimal: break if not res: return None vertex_coloring = min(res, key = lambda t: t[1])[0] h = {} for layer in vertex_coloring: for e in vertex_coloring[layer]: h[e] = layer return h
def __init__(self, graph, four_cycles=[], separator='', edges_ordered=[]): if not (isinstance(graph, FlexRiGraph) or 'FlexRiGraph' in str(type(graph))): raise exceptions.TypeError('The graph must be of the type FlexRiGraph.') self._graph = graph if four_cycles == []: self._four_cycles = self._graph.four_cycles(only_with_NAC=True) else: self._four_cycles = four_cycles if not self._graph.are_NAC_colorings_named(): self._graph.set_NAC_colorings_names() # -----Polynomial Ring for leading coefficients----- ws = [] zs = [] lambdas = [] ws_latex = [] zs_latex = [] lambdas_latex = [] if edges_ordered==[]: edges_ordered = self._graph.edges(labels=False) else: if (Set([self._edge2str(e) for e in edges_ordered]) != Set([self._edge2str(e) for e in self._graph.edges(labels=False)])): raise ValueError('The provided ordered edges do not match the edges of the graph.') for e in edges_ordered: ws.append('w' + self._edge2str(e)) zs.append('z' + self._edge2str(e)) lambdas.append('lambda' + self._edge2str(e)) ws_latex.append('w_{' + self._edge2str(e).replace('_', separator) + '}') zs_latex.append('z_{' + self._edge2str(e).replace('_', separator) + '}') lambdas_latex.append('\\lambda_{' + self._edge2str(e).replace('_', separator) + '}') self._ringLC = PolynomialRing(QQ, names=lambdas+ws+zs) #, order='lex') self._ringLC._latex_names = lambdas_latex + ws_latex + zs_latex self._ringLC_gens = self._ringLC.gens_dict() self._ring_lambdas = PolynomialRing(QQ, names=lambdas + ['u']) self._ring_lambdas._latex_names = lambdas_latex + ['u'] self._ring_lambdas_gens = self._ring_lambdas.gens_dict() self.aux_var = self._ring_lambdas_gens['u'] xs = [] ys = [] xs_latex = [] ys_latex = [] for v in self._graph.vertices(): xs.append('x' + str(v)) ys.append('y' + str(v)) xs_latex.append('x_{' + str(v) + '}') ys_latex.append('y_{' + str(v) + '}') self._ring_coordinates = PolynomialRing(QQ, names=lambdas+xs+ys) self._ring_coordinates._latex_names = lambdas_latex + xs_latex + ys_latex self._ring_coordinates_gens = self._ring_coordinates.gens_dict() # ----Ramification----- # if len(self._graph.NAC_colorings()) > 1: self._ring_ramification = PolynomialRing(QQ, [col.name() for col in self._graph.NAC_colorings()], len(self._graph.NAC_colorings())) # else: # self._ring_ramification = PolynomialRing(QQ, self._graph.NAC_colorings()[0].name()) self._ring_ramification_gens = self._ring_ramification.gens_dict() self._restriction_NAC_types = self.NAC_coloring_restrictions() # -----Graph of 4-cycles----- self._four_cycle_graph = Graph([self._four_cycles,[]], format='vertices_and_edges') for c1, c2 in Subsets(self._four_cycle_graph.vertices(), 2): intersection = self.cycle_edges(c1, sets=True).intersection(self.cycle_edges(c2, sets=True)) if len(intersection)>=2 and len(intersection[0].intersection(intersection[1]))==1: common_vert = intersection[0].intersection(intersection[1])[0] self._four_cycle_graph.add_edge(c1, c2, common_vert) # -----Cycle with orthogonal diagonals due to NAC----- self._orthogonal_diagonals = { delta.name(): [cycle for cycle in self._four_cycle_graph if delta.cycle_has_orthogonal_diagonals(cycle)] for delta in self._graph.NAC_colorings()}
from sage.all import vector, Combinations, Subsets, Set, SimplicialComplex, ZZ, ChainComplex, save from CatMat import FiniteCategory, CatMat, dgModule, TerminalCategory from Prune import prune_dg_module_on_poset n = 3 verbose = True # Set up our graphs vertices = range(1, n + 1) edges = [(i, j) for i, j in Combinations(vertices, 2)] graphs = list(Subsets(edges)) # Define the poset G(n) as a category def G_one(x): return '*' def G_hom(x, y): if x.issubset(y): return ['*'] return [] def G_comp(x, f, y, g, z): return '*' G = FiniteCategory(graphs, G_one, G_hom, G_comp) Gop = G.op()
def topologically_evaluate_regular(self, datum): T = datum.toric_datum if not T.is_regular(): raise ValueError('Can only processed regular toric data') # All our polyhedra all really half-open cones (with a - 1 >=0 # being an imitation of a >= 0). C = conify_polyhedron(T.polyhedron) M = Set(range(T.length())) logger.debug('Dimension of polyhedron: %d' % T.polyhedron.dim()) # STEP 1: # Compute the Euler characteristcs of the subvarieties of # Torus^sth defined by some subsets of T.initials. # Afterwards, we'll combine those into Denef-style Euler characteristics # via inclusion-exclusion. logger.debug('STEP 1') alpha = {} tdim = {} for I in Subsets(M): logger.debug('Processing I = %s' % I) F = [T.initials[i] for i in I] V = SubvarietyOfTorus(F, torus_dim=T.ambient_dim) U, W = V.split_off_torus() # Keep track of the dimension of the torus factor for F == 0. tdim[I] = W.torus_dim if tdim[I] > C.dim(): # In this case, we will never need alpha[I]. logger.debug('Totally irrelevant intersection.') # alpha[I] = ZZ(0) else: # To ensure that the computation of Euler characteristics succeeds in case # of global non-degeneracy, we test this first. # The 'euler_characteristic' method may change generating sets, # possibly introducing degeneracies. alpha[I] = U.khovanskii_characteristic() if U.is_nondegenerate( ) else U.euler_characteristic() logger.debug( 'Essential Euler characteristic alpha[%s] = %d; dimension of torus factor = %d' % (I, alpha[I], tdim[I])) logger.debug( 'Done computing essential Euler characteristics of intersections: %s' % alpha) # STEP 2: # Compute the topological zeta functions of the extended cones. # That is, add extra variables, add variable constraints (here: just >= 0), # and add newly monomialised conditions. def cat(u, v): return vector(list(u) + list(v)) logger.debug('STEP 2') for I in Subsets(M): logger.debug('Current set: I = %s' % I) # P = C_0 x R_(>0)^I in the paper P = DirectProductOfPolyhedra(T.polyhedron, StrictlyPositiveOrthant(len(I))) it = iter(identity_matrix(ZZ, len(I)).rows()) ieqs = [] for i in M: # Turn lhs[i] | monomial of initials[i] * y[i] if in I, # lhs[i] | monomial of initials[i] otherwise # into honest cone conditions. ieqs.append( cat( vector(ZZ, (0, )), cat( vector(ZZ, T.initials[i].exponents()[0]) - vector(ZZ, T.lhs[i].exponents()[0]), next(it) if i in I else zero_vector(ZZ, len(I))))) if not ieqs: # For some reason, not providing any constraints yields the empty # polyhedron in Sage; it should be all of RR^whatever, IMO. ieqs = [vector(ZZ, (T.ambient_dim + len(I) + 1) * [0])] Q = Polyhedron(ieqs=ieqs, base_ring=QQ, ambient_dim=T.ambient_dim + len(I)) sigma = conify_polyhedron(P.intersection(Q)) logger.debug('Dimension of Hensel cone: %d' % sigma.dim()) # Obtain the desired Euler characteristic via inclusion-exclusion, # restricted to those terms contributing to the constant term mod q-1. chi = sum((-1)**len(J) * alpha[I + J] for J in Subsets(M - I) if tdim[I + J] + len(I) == sigma.dim()) if not chi: continue # NOTE: dim(P) = dim(sigma): choose any point omega in P # then a large point lambda in Pos^I will give (omega,lambda) in sigma. # Moreover, small perturbations of (omega,lambda) don't change that # so (omega,lambda) is an interior point of sigma inside P. surfs = (topologise_cone( sigma, matrix([ cat(T.integrand[0], zero_vector(ZZ, len(I))), cat(T.integrand[1], vector(ZZ, len(I) * [-1])) ]).transpose())) for S in surfs: yield SURF(scalar=chi * S.scalar, rays=S.rays)
def check_orthogonal_diagonals(self, motion_types, active_NACs, extra_cycles_orthog_diag=[]): r""" Check the necessary conditions for orthogonal diagonals. TODO: return orthogonality_graph """ perp_by_NAC = [cycle for delta in active_NACs for cycle in self._orthogonal_diagonals[delta]] deltoids = [cycle for cycle, t in motion_types.items() if t in ['e','o']] orthogonalLines = [] for perpCycle in perp_by_NAC + deltoids + extra_cycles_orthog_diag: orthogonalLines.append(Set([Set([perpCycle[0],perpCycle[2]]), Set([perpCycle[1],perpCycle[3]])])) orthogonalityGraph = Graph(orthogonalLines, format='list_of_edges', multiedges=False) n_edges = -1 while n_edges != orthogonalityGraph.num_edges(): n_edges = orthogonalityGraph.num_edges() for perp_subgraph in orthogonalityGraph.connected_components_subgraphs(): isBipartite, partition = perp_subgraph.is_bipartite(certificate=True) if isBipartite: graph_0 = Graph([v.list() for v in partition if partition[v]==0]) graph_1 = Graph([v.list() for v in partition if partition[v]==1]) for comp_0 in graph_0.connected_components(): for comp_1 in graph_1.connected_components(): for e0 in Subsets(comp_0,2): for e1 in Subsets(comp_1,2): orthogonalityGraph.add_edge([Set(e0), Set(e1)]) else: raise exceptions.RuntimeError('A component of the orthogonality graph is not bipartite!') self._orthogonality_graph = orthogonalityGraph check_again = False H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)} self._set_same_lengths(H, motion_types) for c in motion_types: if not orthogonalityGraph.has_edge(Set([c[0],c[2]]),Set([c[1],c[3]])): continue if motion_types[c]=='a': # inconsistent since antiparallel motion cannot have orthogonal diagonals return False elif motion_types[c]=='p': # this cycle must be rhombus self._set_two_edge_same_lengths(H, c[0], c[1], c[2], c[3], 0) self._set_two_edge_same_lengths(H, c[0], c[1], c[1], c[2], 0) self._set_two_edge_same_lengths(H, c[0], c[1], c[0], c[3], 0) check_again = True for c in motion_types: if motion_types[c]=='g': labels = [H[self._edge_ordered(c[i-1],c[i])] for i in range(0,4)] if (not None in labels and ((len(Set(labels))==2 and labels.count(labels[0])==2) or len(Set(labels))==1)): return False if (orthogonalityGraph.has_edge(Set([c[0],c[2]]),Set([c[1],c[3]])) and True in [(H[self._edge_ordered(c[i-1], c[i])]==H[self._edge_ordered(c[i-2], c[i-1])] and H[self._edge_ordered(c[i-1],c[i])]!= None) for i in range(0,4)]): return False if check_again: for K23_edges in [Graph(self._graph).subgraph(k23_ver).edges(labels=False) for k23_ver in self._graph.induced_K23s()]: if MotionClassifier._same_edge_lengths(H, K23_edges): return False return True