def __init__(self, s): """ TESTS:: sage: s = Subsets(Set([1])) sage: e = s.first() sage: isinstance(e, s.element_class) True In the following "_test_elements" is temporarily disabled until :class:`sage.sets.set.Set_object_enumerated` objects pass the category tests:: sage: S = Subsets([1,2,3]) sage: TestSuite(S).run(skip=["_test_elements"]) sage: S = sage.sets.set.Set_object_enumerated([1,2]) sage: TestSuite(S).run() # todo: not implemented """ Parent.__init__(self, category=EnumeratedSets().Finite()) if s not in EnumeratedSets(): from sage.misc.misc import uniq from sage.sets.finite_enumerated_set import FiniteEnumeratedSet s = list(s) us = uniq(s) if len(us) == len(s): s = FiniteEnumeratedSet(s) else: s = FiniteEnumeratedSet(us) self._s = s
def _check_polynomials_P3(quadratic1, quadratic2, variables): """ Check that the polynomial is weighted homogeneous in standard variables. INPUT: - ``quadratic1``, ``quadratic2`` -- two quadratic polynomials in 4 homogeneous or 3 inhomogeneous variables. - ``variables`` -- the variables or ``None`` (default). OUTPUT: This function returns ``variables``, potentially guessed from the polynomial ring. A ``ValueError`` is raised if the polynomial is not homogeneous. EXAMPLES: sage: from sage.schemes.toric.weierstrass_higher import _check_polynomials_P3 sage: R.<w,x,y,z> = QQ[] sage: quadratic = w^2+x^2+y^2+z^2 sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,z]) (w, x, y, z) sage: _check_polynomials_P3(w^2, quadratic, None) (w, x, y, z) sage: _check_polynomials_P3(z^2, quadratic.subs(w=0), None) (x, y, z, None) sage: R.<w,x,y,z,t> = QQ[] sage: quadratic = w^2+x^2+y^2+z^2 + t*(x*y+y*z+z*w+w*x) sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,z]) (w, x, y, z) sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,t]) Traceback (most recent call last): ... ValueError: The polynomial is not homogeneous with weights (1, 1, 1, 1) """ if quadratic1.parent() is not quadratic2.parent(): raise ValueError( 'The two quadratics must be in the same polynomial ring.') if variables is None: from sage.misc.misc import uniq variables = uniq(quadratic1.variables() + quadratic2.variables()) variables.reverse() if len(variables) == 4: w, x, y, z = variables _check_homogeneity(quadratic1, [w, x, y, z], (1, 1, 1, 1), 2) _check_homogeneity(quadratic2, [w, x, y, z], (1, 1, 1, 1), 2) elif len(variables) == 3: w, x, y = variables z = None else: raise ValueError('Need three or four variables, got ' + str(variables)) return (w, x, y, z)
def _check_polynomials_P3(quadratic1, quadratic2, variables): """ Check that the polynomial is weighted homogeneous in standard variables. INPUT: - ``quadratic1``, ``quadratic2`` -- two quadratic polynomials in 4 homogeneous or 3 inhomogeneous variables. - ``variables`` -- the variables or ``None`` (default). OUTPUT: This function returns ``variables``, potentially guessed from the polynomial ring. A ``ValueError`` is raised if the polynomial is not homogeneous. EXAMPLES: sage: from sage.schemes.toric.weierstrass_higher import _check_polynomials_P3 sage: R.<w,x,y,z> = QQ[] sage: quadratic = w^2+x^2+y^2+z^2 sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,z]) (w, x, y, z) sage: _check_polynomials_P3(w^2, quadratic, None) (w, x, y, z) sage: _check_polynomials_P3(z^2, quadratic.subs(w=0), None) (x, y, z, None) sage: R.<w,x,y,z,t> = QQ[] sage: quadratic = w^2+x^2+y^2+z^2 + t*(x*y+y*z+z*w+w*x) sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,z]) (w, x, y, z) sage: _check_polynomials_P3(w^2, quadratic, [w,x,y,t]) Traceback (most recent call last): ... ValueError: The polynomial is not homogeneous with weights (1, 1, 1, 1) """ if quadratic1.parent() is not quadratic2.parent(): raise ValueError('The two quadratics must be in the same polynomial ring.') if variables is None: from sage.misc.misc import uniq variables = uniq(quadratic1.variables() + quadratic2.variables()) variables.reverse() if len(variables) == 4: w, x, y, z = variables _check_homogeneity(quadratic1, [w, x, y, z], (1, 1, 1, 1), 2) _check_homogeneity(quadratic2, [w, x, y, z], (1, 1, 1, 1), 2) elif len(variables) == 3: w, x, y = variables z = None else: raise ValueError('Need three or four variables, got '+str(variables)) return (w, x, y, z)
def automorphism_group(self): """ EXAMPLES:: sage: p = PermutationGroupElement((2,3)) sage: S = species.SetSpecies() sage: F = S * S sage: a = F.structures([1,2,3,4]).random_element(); a {1}*{2, 3, 4} sage: a.automorphism_group() Permutation Group with generators [(2,3), (2,3,4)] :: sage: [a.transport(g) for g in a.automorphism_group()] [{1}*{2, 3, 4}, {1}*{2, 3, 4}, {1}*{2, 3, 4}, {1}*{2, 3, 4}, {1}*{2, 3, 4}, {1}*{2, 3, 4}] :: sage: a = F.structures([1,2,3,4]).random_element(); a {2, 3}*{1, 4} sage: [a.transport(g) for g in a.automorphism_group()] [{2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}] """ from sage.groups.all import PermutationGroupElement, PermutationGroup, SymmetricGroup from sage.misc.misc import uniq from sage.combinat.species.misc import change_support left, right = self._list n = len(self._labels) #Get the supports for each of the sides l_support = self._subset._list r_support = self._subset.complement()._list #Get the automorphism group for the left object and #make it have the correct support. Do the same to the #right side. l_aut = change_support(left.automorphism_group(), l_support) r_aut = change_support(right.automorphism_group(), r_support) identity = PermutationGroupElement([]) gens = l_aut.gens() + r_aut.gens() gens = [g for g in gens if g != identity] gens = uniq(gens) if len(gens) > 0 else [[]] return PermutationGroup(gens)
def __iter__(self): """ EXAMPLES:: sage: Combinations(['a','a','b'],2).list() # indirect doctest [['a', 'a'], ['a', 'b']] """ items = map(self.mset.index, self.mset) indices = uniq(sorted(items)) counts = [0] * len(indices) for i in items: counts[indices.index(i)] += 1 for iv in IntegerVectors(self.k, len(indices), outer=counts): yield sum([[self.mset[indices[i]]]*iv[i] for i in range(len(indices))],[])
def to_chain(self): """ Returns the chain of partitions corresponding to the (semi)standard skew tableau. EXAMPLES:: sage: SkewTableau([[None,1],[2],[3]]).to_chain() [[1], [2], [2, 1], [2, 1, 1]] sage: SkewTableau([[None,1],[1],[2]]).to_chain() [[1], [2, 1], [2, 1, 1]] """ weights = [0] + uniq(sorted(self.to_word())) return [self.restrict(x).shape()[0] for x in weights]
def to_chain(self): """ Returns the chain of partitions corresponding to the (semi)standard skew tableau. EXAMPLES:: sage: SkewTableau([[None,1],[2],[3]]).to_chain() [[1], [2], [2, 1], [2, 1, 1]] sage: SkewTableau([[None,1],[1],[2]]).to_chain() [[1], [2, 1], [2, 1, 1]] """ weights = [0] + uniq(sorted(self.to_word())) return [ self.restrict(x).shape()[0] for x in weights]
def __iter__(self): """ EXAMPLES:: sage: Combinations(['a','a','b'],2).list() # indirect doctest [['a', 'a'], ['a', 'b']] """ items = map(self.mset.index, self.mset) indices = uniq(sorted(items)) counts = [0] * len(indices) for i in items: counts[indices.index(i)] += 1 for iv in IntegerVectors(self.k, len(indices), outer=counts): yield sum([[self.mset[indices[i]]] * iv[i] for i in range(len(indices))], [])
def __contains__(self, x): """ EXAMPLES:: sage: c = Combinations(range(4)) sage: all( i in c for i in c ) True sage: [3,4] in c False sage: [0,0] in c False """ try: x = list(x) except TypeError: return False return all(i in self.mset for i in x) and len(uniq(x)) == len(x)
def order_filter(self, elements): """ Returns the order filter generated by a list of elements. `I` is an order filter if, for any `x` in `I` and `y` such that `y \ge x`, then `y` is in `I`. EXAMPLES:: sage: H = Posets.BooleanLattice(4)._hasse_diagram sage: H.order_filter([3,8]) [3, 7, 8, 9, 10, 11, 12, 13, 14, 15] """ of = [] for i in elements: for j in self.breadth_first_search(i): of.append(j) return uniq(of)
def order_filter(self,elements): """ Returns the order filter generated by a list of elements. `I` is an order filter if, for any `x` in `I` and `y` such that `y \ge x`, then `y` is in `I`. EXAMPLES:: sage: H = Posets.BooleanLattice(4)._hasse_diagram sage: H.order_filter([3,8]) [3, 7, 8, 9, 10, 11, 12, 13, 14, 15] """ of = [] for i in elements: for j in self.breadth_first_search(i): of.append(j) return uniq(of)
def order_ideal(self,elements): """ Returns the order ideal generated by a list of elements. `I` is an order ideal if, for any `x` in `I` and `y` such that `y \le x`, then `y` is in `I`. EXAMPLES:: sage: H = Posets.BooleanLattice(4)._hasse_diagram sage: H.order_ideal([7,10]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 10] """ H = copy(self).reverse() oi = [] for i in elements: for j in H.breadth_first_search(i): oi.append(j) return uniq(oi)
def __contains__(self, x): """ EXAMPLES:: sage: from sage.combinat.choose_nk import ChooseNK sage: c52 = ChooseNK(5,2) sage: [0,1] in c52 True sage: [1,1] in c52 False sage: [0,1,3] in c52 False """ try: x = list(x) except TypeError: return False r = range(len(x)) return all(i in r for i in x) and len(uniq(x)) == self._k
def __init__(self, alphabet): """ Builds an ordered alphabet from an iterable. The order is that given by the order the items appear in the iterable. There must be no duplicates. NOTE: The alphabet is expanded in memory and stored as a list. EXAMPLES:: sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite sage: A = OrderedAlphabet_Finite([0,1,2]) sage: A == loads(dumps(A)) True sage: A = OrderedAlphabet_Finite("abc") sage: A == loads(dumps(A)) True TESTS:: sage: from sage.combinat.words.alphabet import OrderedAlphabet_Finite sage: OrderedAlphabet_Finite('aba') Traceback (most recent call last): ... ValueError: duplicate elements in alphabet sage: OrderedAlphabet_Finite(33) Traceback (most recent call last): ... TypeError: cannot build an alphabet from 33 """ try: self._alphabet = list(alphabet) except TypeError: raise TypeError, "cannot build an alphabet from %s" % (alphabet) if len(uniq(self._alphabet)) != len(self._alphabet): raise ValueError, "duplicate elements in alphabet"
def set_value_from_cells(self, obj_class=None, cells={}): r"""We have an object value, but we want to change it according to cells Yet we want to keep the same class (or warn if that's impossible) INPUT: - ``obj_class`` -- an object class (by default: self.value.__class__) - ``cells`` -- a dictionary (i,j)->val """ if not obj_class and self.value: obj_class = self.value.__class__ if not obj_class: return if hasattr(self.adapter, 'from_cells'): try: obj = self.adapter.from_cells(cells) except: raise ValueError( "Could not make an object of class '%s' from given cells" % str(obj_class)) elif hasattr(obj_class, 'cells') or hasattr( obj_class, 'rows'): # e.g. a tableau / matrix / vector positions = sorted(list(cells.keys())) for cl in obj_class.__mro__: try: obj = cl([[cells[pos] for pos in positions if pos[0] == i] for i in uniq([t[0] for t in positions])]) except: print("These cells cannot be turned into a %s" % cl) else: raise TypeError( "Unable to cast the given cells into a grid-like object.") if not self.validate(obj, None, obj_class): raise ValueError( "Could not make a compatible ('%s') object from given cells" % str(obj_class)) self.set_value(obj, False)
def draw(self, cell_widget_classes=None, cell_widget_class_index=None, addable_widget_class=None, blank_widget_class=None): r""" Add children to the GridWidget: - Sage object/grid editor cells - Blank cells for empty cells in a row - Addable cells if any Used classes can be passed as arguments to enable changing shapes, colors .. """ self.initialization = True # Prevent any interactivity while drawing the widget self.reset_links() self.compute_height() positions = sorted(list(self.cells.keys())) rows = [[(pos, self.cells[pos]) for pos in positions if pos[0]==i] \ for i in range(self.height)] vbox_children = [] addable_positions = self.addable_cells() addable_rows = [] removable_positions = self.removable_cells() addable_rows = [(i,[pos for pos in addable_positions if pos[0]==i]) \ for i in uniq([t[0] for t in addable_positions])] if not cell_widget_classes: cell_widget_classes = self.cell_widget_classes if not cell_widget_class_index: cell_widget_class_index = self.cell_widget_class_index if not addable_widget_class: addable_widget_class = self.addable_widget_class if not blank_widget_class: blank_widget_class = self.blank_widget_class for i in range(self.height): r = rows[i] if not r: # Empty row if (i, 0) in addable_positions: vbox_children.append( HBox((addable_widget_class( (i, 0), layout=self.cell_layout), ))) else: vbox_children.append( HBox((blank_widget_class(layout=self.cell_layout, disabled=True), ))) continue j = 0 hbox_children = [] while j <= max([t[0][1] for t in rows[i]]): if (i, j) in positions: cell_content = self.cells[(i, j)] cell_widget_class = cell_widget_classes[ cell_widget_class_index((i, j))] cell_display = self.adapter.cell_to_display( cell_content, self.displaytype) cell = cell_widget_class(cell_display, (i, j), layout=self.cell_layout, placeholder=cell_display) if (i, j) in removable_positions: if issubclass(cell_widget_class, ToggleButton): cell.description = '-' cell.disabled = False else: cell.add_class('removablecell') hbox_children.append(cell) elif (i, j) in addable_positions: # Inside the grid-represented object limits hbox_children.append( addable_widget_class((i, j), layout=self.cell_layout)) else: hbox_children.append( blank_widget_class(layout=self.cell_layout)) j += 1 if j > max([t[0][1] for t in rows[i]]) and (i, j) in addable_positions: # Outside of the grid-represented object limits hbox_children.append( self.addable_widget_class((i, j), layout=self.cell_layout)) vbox_children.append(HBox(hbox_children)) for row in addable_rows: if row[0] > i: vbox_children.append( HBox([ self.addable_widget_class((i, j), layout=self.cell_layout) for c in row[1] ])) if self.display_convention == 'fr': vbox_children.reverse() self.children = vbox_children self.add_links() self.initialization = False
def __init__(self, matrices, C, D, check=True): """ Create a morphism from a dictionary of matrices. EXAMPLES:: from sage.matrix.constructor import zero_matrix sage: S = simplicial_complexes.Sphere(1) sage: S Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} sage: C = S.chain_complex() sage: C.differential() {0: [], 1: [ 1 1 0] [ 0 -1 -1] [-1 0 1], 2: []} sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)} sage: G = Hom(C,C) sage: x = G(f) sage: x Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] [0 0 0], 1: [0 0 0] [0 0 0] [0 0 0]} Check that the bug in :trac:`13220` has been fixed:: sage: X = simplicial_complexes.Simplex(1) sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) sage: g.associated_chain_complex_morphism() Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 1 nonzero terms over Integer Ring """ if not C.base_ring() == D.base_ring(): raise NotImplementedError('morphisms between chain complexes of different' ' base rings are not implemented') d = C.degree_of_differential() if d != D.degree_of_differential(): raise ValueError('degree of differential does not match') from sage.misc.misc import uniq degrees = uniq(C.differential().keys() + D.differential().keys()) initial_matrices = dict(matrices) matrices = dict() for i in degrees: if i - d not in degrees: if not (C.free_module_rank(i) == D.free_module_rank(i) == 0): raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i)) continue try: matrices[i] = initial_matrices.pop(i) except KeyError: matrices[i] = matrix.zero_matrix(C.base_ring(), D.differential(i).ncols(), C.differential(i).ncols(), sparse=True) if check: # all remaining matrices given must be 0x0 if not all(m.ncols() == m.nrows() == 0 for m in initial_matrices.values()): raise ValueError('the remaining matrices are not empty') # check commutativity for i in degrees: if i - d not in degrees: if not (C.free_module_rank(i) == D.free_module_rank(i) == 0): raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i)) continue if i + d not in degrees: if not (C.free_module_rank(i+d) == D.free_module_rank(i+d) == 0): raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i+d)) continue Dm = D.differential(i) * matrices[i] mC = matrices[i+d] * C.differential(i) if mC != Dm: raise ValueError('matrices must define a chain complex morphism') self._matrix_dictionary = matrices self._domain = C self._codomain = D
def __init__(self, matrices, C, D, check=True): """ Create a morphism from a dictionary of matrices. EXAMPLES:: sage: S = simplicial_complexes.Sphere(1) sage: S Minimal triangulation of the 1-sphere sage: C = S.chain_complex() sage: C.differential() {0: [], 1: [-1 -1 0] [ 1 0 -1] [ 0 1 1], 2: []} sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)} sage: G = Hom(C,C) sage: x = G(f) sage: x Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] [0 0 0], 1: [0 0 0] [0 0 0] [0 0 0]} Check that the bug in :trac:`13220` has been fixed:: sage: X = simplicial_complexes.Simplex(1) sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) sage: g.associated_chain_complex_morphism() Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring Check that an error is raised if the matrices are the wrong size:: sage: C = ChainComplex({0: zero_matrix(ZZ, 0, 1)}) sage: D = ChainComplex({0: zero_matrix(ZZ, 0, 2)}) sage: Hom(C,D)({0: matrix(1, 2, [1, 1])}) # 1x2 is the wrong size. Traceback (most recent call last): ... ValueError: matrix in degree 0 is not the right size sage: Hom(C,D)({0: matrix(2, 1, [1, 1])}) # 2x1 is right. Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring """ if not C.base_ring() == D.base_ring(): raise NotImplementedError('morphisms between chain complexes of different' ' base rings are not implemented') d = C.degree_of_differential() if d != D.degree_of_differential(): raise ValueError('degree of differential does not match') from sage.misc.misc import uniq degrees = uniq(list(C.differential()) + list(D.differential())) initial_matrices = dict(matrices) matrices = dict() for i in degrees: if i - d not in degrees: if not (C.free_module_rank(i) == D.free_module_rank(i) == 0): raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i)) continue try: matrices[i] = initial_matrices.pop(i) except KeyError: matrices[i] = zero_matrix(C.base_ring(), D.differential(i).ncols(), C.differential(i).ncols(), sparse=True) if check: # All remaining matrices given must be 0x0. if not all(m.ncols() == m.nrows() == 0 for m in initial_matrices.values()): raise ValueError('the remaining matrices are not empty') # Check sizes of matrices. for i in matrices: if (matrices[i].nrows() != D.free_module_rank(i) or matrices[i].ncols() != C.free_module_rank(i)): raise ValueError('matrix in degree {} is not the right size'.format(i)) # Check commutativity. for i in degrees: if i - d not in degrees: if not (C.free_module_rank(i) == D.free_module_rank(i) == 0): raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i)) continue if i + d not in degrees: if not (C.free_module_rank(i+d) == D.free_module_rank(i+d) == 0): raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i+d)) continue Dm = D.differential(i) * matrices[i] mC = matrices[i+d] * C.differential(i) if mC != Dm: raise ValueError('matrices must define a chain complex morphism') self._matrix_dictionary = {} for i in matrices: m = matrices[i] # Use immutable matrices because they're hashable. m.set_immutable() self._matrix_dictionary[i] = m Morphism.__init__(self, Hom(C,D, ChainComplexes(C.base_ring())))
def __init__(self, matrices, C, D, check=True): """ Create a morphism from a dictionary of matrices. EXAMPLES:: sage: S = simplicial_complexes.Sphere(1) sage: S Minimal triangulation of the 1-sphere sage: C = S.chain_complex() sage: C.differential() {0: [], 1: [ 1 1 0] [ 0 -1 -1] [-1 0 1], 2: []} sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)} sage: G = Hom(C,C) sage: x = G(f) sage: x Chain complex endomorphism of Chain complex with at most 2 nonzero terms over Integer Ring sage: x._matrix_dictionary {0: [0 0 0] [0 0 0] [0 0 0], 1: [0 0 0] [0 0 0] [0 0 0]} Check that the bug in :trac:`13220` has been fixed:: sage: X = simplicial_complexes.Simplex(1) sage: Y = simplicial_complexes.Simplex(0) sage: g = Hom(X,Y)({0:0, 1:0}) sage: g.associated_chain_complex_morphism() Chain complex morphism: From: Chain complex with at most 2 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring Check that an error is raised if the matrices are the wrong size:: sage: C = ChainComplex({0: zero_matrix(ZZ, 0, 1)}) sage: D = ChainComplex({0: zero_matrix(ZZ, 0, 2)}) sage: Hom(C,D)({0: matrix(1, 2, [1, 1])}) # 1x2 is the wrong size. Traceback (most recent call last): ... ValueError: matrix in degree 0 is not the right size sage: Hom(C,D)({0: matrix(2, 1, [1, 1])}) # 2x1 is right. Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Integer Ring To: Chain complex with at most 1 nonzero terms over Integer Ring """ if not C.base_ring() == D.base_ring(): raise NotImplementedError( 'morphisms between chain complexes of different' ' base rings are not implemented') d = C.degree_of_differential() if d != D.degree_of_differential(): raise ValueError('degree of differential does not match') from sage.misc.misc import uniq degrees = uniq(C.differential().keys() + D.differential().keys()) initial_matrices = dict(matrices) matrices = dict() for i in degrees: if i - d not in degrees: if not (C.free_module_rank(i) == D.free_module_rank(i) == 0): raise ValueError( '{} and {} are not rank 0 in degree {}'.format( C, D, i)) continue try: matrices[i] = initial_matrices.pop(i) except KeyError: matrices[i] = zero_matrix(C.base_ring(), D.differential(i).ncols(), C.differential(i).ncols(), sparse=True) if check: # All remaining matrices given must be 0x0. if not all(m.ncols() == m.nrows() == 0 for m in initial_matrices.values()): raise ValueError('the remaining matrices are not empty') # Check sizes of matrices. for i in matrices: if (matrices[i].nrows() != D.free_module_rank(i) or matrices[i].ncols() != C.free_module_rank(i)): raise ValueError( 'matrix in degree {} is not the right size'.format(i)) # Check commutativity. for i in degrees: if i - d not in degrees: if not (C.free_module_rank(i) == D.free_module_rank(i) == 0): raise ValueError( '{} and {} are not rank 0 in degree {}'.format( C, D, i)) continue if i + d not in degrees: if not (C.free_module_rank(i + d) == D.free_module_rank(i + d) == 0): raise ValueError( '{} and {} are not rank 0 in degree {}'.format( C, D, i + d)) continue Dm = D.differential(i) * matrices[i] mC = matrices[i + d] * C.differential(i) if mC != Dm: raise ValueError( 'matrices must define a chain complex morphism') self._matrix_dictionary = {} for i in matrices: m = matrices[i] # Use immutable matrices because they're hashable. m.set_immutable() self._matrix_dictionary[i] = m Morphism.__init__(self, Hom(C, D, ChainComplexes(C.base_ring())))
def __add__(self, Nelt): r""" Concatenate two ascii art object. By default, when two object are concatenated, the new one will be splittable between both. If the baseline is defined, the concatenation is computed such that the new baseline coincidate with the olders. For example, let `T` be a tree with it's baseline ascii art representation in the middle:: o \ o / \ o o and let `M` be a matrix with it's baseline ascii art representation at the middle two:: [1 2 3] [4 5 6] [7 8 9] then the concatenation of both will give:: o \ [1 2 3] o [4 5 6] / \ [7 8 9] o o If one of the objects has not baseline, the concatenation is realized from the top:: o [1 2 3] \ [4 5 6] o [7 8 9] / \ o o TESTS:: sage: from sage.typeset.ascii_art import AsciiArt sage: l5 = AsciiArt(lines=['|' for _ in range(5)], baseline=2); l5 | | | | | sage: l3 = AsciiArt(lines=['|' for _ in range(3)], baseline=1); l3 | | | sage: l3 + l5 | || || || | sage: l5 + l3 | || || || | sage: l5._baseline = 0 sage: l5 + l3 | | | || || | sage: l5._baseline = 4 sage: l5 + l3 | || || | | | sage: l3._baseline = 0 sage: l3 + l5 | | || | | | | """ new_matrix = [] new_h = self.__class__._compute_new_h(self, Nelt) new_baseline = self.__class__._compute_new_baseline(self, Nelt) if self._baseline is not None and Nelt._baseline is not None: # left treatement for line in self._matrix: new_matrix.append(line + " " * (self._l - len(line))) if new_h > self._h: # | new_h > self._h # | new_baseline > self._baseline # ||<-- baseline number of white lines at the bottom # | } :: Nelt._baseline - self._baseline # | } if new_baseline > self._baseline: for k in range(new_baseline - self._baseline): new_matrix.append(" " * self._l) # | } new_h > self._h # | } new_h - new_baseline > self._h - self._baseline # ||<-- baseline number of white lines at the top # || :: new_h - new_baseline - self._h + self._baseline # || # | # | if new_h - new_baseline > self._h - self._baseline: for _ in range((new_h - new_baseline) - (self._h - self._baseline)): new_matrix.insert(0, " " * self._l) # right treatement i = 0 if new_h > Nelt._h: # | } new_h > Nelt._h # | } new_h - new_baseline > Nelt._h - self._baseline # ||<-- baseline number of white lines at the top # || :: new_h - new_baseline - Nelt._h + Nelt._baseline # || # || # | i = max(new_h - new_baseline - Nelt._h + Nelt._baseline, 0) for j in range(Nelt._h): new_matrix[i + j] += Nelt._matrix[j] else: for line in self._matrix: new_matrix.append(line + " " * (self._l - len(line))) for i, line_i in enumerate(Nelt._matrix): if i == len(new_matrix): new_matrix.append(" " * self._l + line_i) else: new_matrix[i] += line_i # breakpoint new_breakpoints = list(self._breakpoints) new_breakpoints.append(self._l) for bp in Nelt._breakpoints: new_breakpoints.append(bp + self._l) from sage.misc.misc import uniq return self.__class__(lines=new_matrix, breakpoints=uniq(new_breakpoints), baseline=new_baseline)
def __add__(self, Nelt): r""" Concatenate two ascii art object. By default, when two object are concatenated, the new one will be splittable between both. If the baseline is defined, the concatenation is computed such that the new baseline coincidate with the olders. For example, let `T` be a tree with it's baseline ascii art representation in the middle:: o \ o / \ o o and let `M` be a matrix with it's baseline ascii art representation at the middle two:: [1 2 3] [4 5 6] [7 8 9] then the concatenation of both will give:: o \ [1 2 3] o [4 5 6] / \ [7 8 9] o o If one of the objects has not baseline, the concatenation is realized from the top:: o [1 2 3] \ [4 5 6] o [7 8 9] / \ o o TESTS:: sage: from sage.misc.ascii_art import AsciiArt sage: l5 = AsciiArt(lines=['|' for _ in range(5)], baseline=2); l5 | | | | | sage: l3 = AsciiArt(lines=['|' for _ in range(3)], baseline=1); l3 | | | sage: l3 + l5 | || || || | sage: l5 + l3 | || || || | sage: l5._baseline = 0 sage: l5 + l3 | | | || || | sage: l5._baseline = 4 sage: l5 + l3 | || || | | | sage: l3._baseline = 0 sage: l3 + l5 | | || | | | | """ new_matrix = [] new_h = AsciiArt._compute_new_h(self, Nelt) new_baseline = AsciiArt._compute_new_baseline(self, Nelt) if self._baseline != None and Nelt._baseline != None: # left traitement for line in self._matrix: new_matrix.append(line + " "**Integer(self._l - len(line))) if new_h > self._h: # | new_h > self._h # | new_baseline > self._baseline # ||<-- baseline number of white lines at the bottom # | } :: Nelt._baseline - self._baseline # | } if new_baseline > self._baseline: for k in range(new_baseline - self._baseline): new_matrix.append(" "**Integer(self._l)) # | } new_h > self._h # | } new_h - new_baseline > self._h - self._baseline # ||<-- baseline number of white lines at the top # || :: new_h - new_baseline - self._h + self._baseline # || # | # | if new_h - new_baseline > self._h - self._baseline: for _ in range((new_h - new_baseline) - (self._h - self._baseline)): new_matrix.insert(0, " "**Integer(self._l)) # right traitement i = 0 if new_h > Nelt._h: # | } new_h > Nelt._h # | } new_h - new_baseline > Nelt._h - self._baseline # ||<-- baseline number of white lines at the top # || :: new_h - new_baseline - Nelt._h + Nelt._baseline # || # || # | i = max(new_h - new_baseline - Nelt._h + Nelt._baseline, 0) for j in range(Nelt._h): new_matrix[i + j] += Nelt._matrix[j] else: for line in self._matrix: new_matrix.append(line + " "**Integer(self._l - len(line))) for i, line_i in enumerate(Nelt._matrix): if i == len(new_matrix): new_matrix.append(" "**Integer(self._l) + line_i) else: new_matrix[i] += line_i # breakpoint new_breakpoints = list(self._breakpoints) new_breakpoints.append(self._l) for bp in Nelt._breakpoints: new_breakpoints.append(bp + self._l) from sage.misc.misc import uniq return AsciiArt(lines=new_matrix, breakpoints=uniq(new_breakpoints), baseline=new_baseline, atomic=False)