示例#1
0
    def add_assumption(self, lincomb, bound):
        """Assumption of the form [(perm, coef), ..., (perm, coef)] \geq bound."""

        # switch on 'assumptions mode'
        if self.assumptions is False:
            self.assumptions = True

        assumption_densities = [-Rational(bound) for x in range(len(self.admissible_perms))]

        for densperm, coeff in lincomb:
            densperm = PermFlag(densperm)
            if self.N < densperm.N: # if too big to fit, then skip
                continue
            
            combs = Combinations(range(self.N), densperm.N)
            numcombs = combs.cardinality()
            
            # for each admissible permutation, compute the density of densperm in it
            for i in range(len(self.admissible_perms)):
                admissibleperm = self.admissible_perms[i]
                counter = 0 # number of copies of densperm in admissible perm
                for c in combs:
                    admissible_subperm = normalize([admissibleperm.perm[x] for x in c], densperm.N)
                    admissible_subflag = PermFlag(admissible_subperm)
                    if admissible_subflag == densperm:
                        counter += 1
                       
                assumption_densities[i] += coeff*Integer(counter)/numcombs
                #sys.stdout.write("assumption_densities[i] = %s\n" % str(assumption_densities[i]))

        self.assumption_densities.append(assumption_densities)
示例#2
0
    def _compute_densities(self):
        
        densities = [0 for x in range(len(self.admissible_perms))]

        for densperm, coeff in self.density_pattern:

            if self.N < densperm.N: # too big to fit, then skip
                continue
            
            combs = Combinations(range(self.N), densperm.N)
            numcombs = combs.cardinality()
            
            # for each admissible permutation, compute the density of densperm in it
            for i in range(len(self.admissible_perms)):
                admissibleperm = self.admissible_perms[i]
                counter = 0 # number of copies of densperm in admissibleperm
                for c in combs:
                    admissible_subperm = normalize([admissibleperm.perm[x] for x in c], densperm.N)
                    admissible_subflag = PermFlag(admissible_subperm)
                    if admissible_subflag == densperm:
                       counter += 1
                       
                densities[i] += coeff*Integer(counter)/numcombs

        return densities
示例#3
0
def ChooseNK(n, k):
    """
    All possible choices of k elements out of range(n) without repetitions.

    The elements of the output are tuples of Python int (and not Sage Integer).

    This was deprecated in :trac:`10534` for :func:`Combinations`
    (or ``itertools.combinations`` for doing iteration).

    EXAMPLES::

        sage: from sage.combinat.choose_nk import ChooseNK
        sage: c = ChooseNK(4,2)
        doctest:...: DeprecationWarning: ChooseNk is deprecated and will be
        removed. Use Combinations instead (or combinations from the itertools
        module for iteration)
        See http://trac.sagemath.org/10534 for details.
        sage: c.first()
        [0, 1]
        sage: c.list()
        [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]]
    """
    from sage.misc.superseded import deprecation
    deprecation(
        10534,
        "ChooseNk is deprecated and will be removed. Use Combinations instead (or combinations from the itertools module for iteration)"
    )
    from sage.combinat.combination import Combinations
    return Combinations(n, k)
示例#4
0
    def parallelotope(self, generators):
        r"""
        Return the parallelotope spanned by the generators.

        INPUT:

        - ``generators`` -- an iterable of anything convertible to vector
          (for example, a list of vectors) such that the vectors all
          have the same dimension.

        OUTPUT:

        The parallelotope. This is the multi-dimensional
        generalization of a parallelogram (2 generators) and a
        parallelepiped (3 generators).

        EXAMPLES::

            sage: polytopes.parallelotope([ (1,0), (0,1) ])
            A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices
            sage: polytopes.parallelotope([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]])
            A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 16 vertices
        """
        try:
            generators = [vector(QQ, v) for v in generators]
            base_ring = QQ
        except TypeError:
            generators = [vector(RDF, v) for v in generators]
            base_ring = RDF

        from sage.combinat.combination import Combinations
        par = [0 * generators[0]]
        par += [sum(c) for c in Combinations(generators) if c != []]
        return Polyhedron(vertices=par, base_ring=base_ring)
示例#5
0
def antisymmetrized_coordinate_sums(dim, n):
    """
    Return formal anti-symmetrized sum of multi-indices

    INPUT:

    - ``dim`` -- integer. The dimension (range of each index).

    - ``n`` -- integer. The total number of indices.

    OUTPUT:

    An anti-symmetrized formal sum of multi-indices (tuples of integers)

    EXAMPLES::

        sage: from sage.modules.tensor_operations import antisymmetrized_coordinate_sums
        sage: antisymmetrized_coordinate_sums(3, 2)
        ((0, 1) - (1, 0), (0, 2) - (2, 0), (1, 2) - (2, 1))
    """
    from sage.structure.formal_sum import FormalSum
    table = []
    from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    S_d = SymmetricGroup(n)
    from sage.combinat.combination import Combinations
    for i in Combinations(range(dim), n):
        i = tuple(i)
        x = []
        for g in S_d:
            x.append([g.sign(), g(i)])
        x = FormalSum(x)
        table.append(x)
    return tuple(table)
示例#6
0
    def is_covering(self):
        """
        Checks that all t-sets are in fact covered.

        INPUT:
            putative covering design

        OUTPUT:
            True if all t-sets are in at least one block


        NOTES:
            This is very slow and wasteful of memory.  A faster Cython
            version will be added soon.

        EXAMPLES:
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 5]],0, 'Projective Plane')
            sage: C.is_covering()
            True
            sage: C=CoveringDesign(7,3,2,7,range(7),[[0, 1, 2], [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6], [2, 4, 6]],0, 'not a covering')   # last block altered
            sage: C.is_covering()
            False
        """
        v = self.__v
        k = self.__k
        t = self.__t
        Svt = Combinations(range(v), t)
        Skt = Combinations(range(k), t)
        tset = {}  # tables of t-sets: False = uncovered, True = covered
        for i in Svt:
            tset[tuple(i)] = False

        # mark all t-sets covered by each block
        for a in self.__incidence_structure.blocks():
            for z in Skt:
                y = [a[x] for x in z]
                tset[tuple(y)] = True

        for i in Svt:
            if tset[tuple(i)] == False:  # uncovered
                return False

        return True  # everything was covered
示例#7
0
    def minimal_nonfaces(self):
        """
        Return the minimal non-faces of ``self``.

        EXAMPLES::

            sage: ClusterComplex(['A', 2]).minimal_nonfaces()
            [[0, 2], [0, 3], [1, 3], [1, 4], [2, 4]]
        """
        from sage.combinat.combination import Combinations
        return [X for X in Combinations(self.vertices(), self.k() + 1)
                if not any(set(X).issubset(F) for F in self.facets())]
示例#8
0
    def subperm_density(self, perm):
        """
        Return density of perm in self.

        INPUT:
        
        - perm:    permutation of type PermFlag

        EXAMPLE:

        sage: P = PermFlag("1234765")
        sage: P.subperm_density(PermFlag("123"))
        22/35
        """

        combs = Combinations(self.N, perm.N)
        counter = 0
        for c in combs:
            if self._induced_subpattern(c) == perm.perm:
                counter += 1
        return Integer(counter) / combs.cardinality()
def royle_x_graph():
    r"""
    Return a strongly regular graph, as described by Royle [Roy2008]_.

    INPUT:

    None.

    OUTPUT:

    An object of class ``Graph``, representing Royle's X graph [Roy2008]_.

    EXAMPLES:

    ::

        sage: from boolean_cayley_graphs.royle_x_graph import royle_x_graph
        sage: g = royle_x_graph()
        sage: g.is_strongly_regular()
        True
        sage: g.is_strongly_regular(parameters=True)
        (64, 35, 18, 20)

    REFERENCES:

    Royle [Roy2008]_.

    """
    n = 8
    order = 64

    vecs = [vector([1] * n)]
    for a in Combinations(xsrange(1, n), 4):
        vecs.append(vector([-1 if x in a else 1 for x in xsrange(n)]))
    for b in Combinations(xsrange(n), 2):
        vecs.append(vector([-1 if x in b else 1 for x in xsrange(n)]))

    return Graph([(i, j) for i in xsrange(order)
                  for j in xsrange(i + 1, order) if vecs[i] * vecs[j] == 0])
示例#10
0
    def _structures(self, structure_class, labels):
        """
        EXAMPLES::

            sage: S = species.SubsetSpecies()
            sage: S.structures([1,2]).list()
            [{}, {1}, {2}, {1, 2}]
            sage: S.structures(['a','b']).list()
            [{}, {'a'}, {'b'}, {'a', 'b'}]
        """
        from sage.combinat.combination import Combinations
        for c in Combinations(range(1, len(labels) + 1)):
            yield structure_class(self, labels, c)
示例#11
0
    def is_covering(self):
        """
        Check all `t`-sets are in fact covered by the blocks of ``self``.

        .. NOTE::

            This is very slow and wasteful of memory.

        EXAMPLES::

            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6],
            ....:     [2, 3, 6], [2, 4, 5]], 0, 'Projective Plane')
            sage: C.is_covering()
            True
            sage: C = CoveringDesign(7, 3, 2, 7, range(7), [[0, 1, 2],
            ....:     [0, 3, 4], [0, 5, 6], [1, 3, 5], [1, 4, 6], [2, 3, 6],
            ....:     [2, 4, 6]], 0, 'not a covering')   # last block altered
            sage: C.is_covering()
            False
        """
        v = self.__v
        k = self.__k
        t = self.__t
        Svt = Combinations(range(v), t)
        Skt = Combinations(range(k), t)
        tset = {}  # tables of t-sets: False = uncovered, True = covered
        for i in Svt:
            tset[tuple(i)] = False
        # mark all t-sets covered by each block
        for a in self.__incidence_structure.blocks():
            for z in Skt:
                y = (a[x] for x in z)
                tset[tuple(y)] = True
        for i in Svt:
            if not tset[tuple(i)]:  # uncovered
                return False
        return True  # everything was covered
示例#12
0
def c3_func(SUK, prec=106):
    r"""
    Return the constant `c_3` from Smart's 1995 TCDF paper, [Sma1995]_

    INPUT:

    - ``SUK`` -- a group of `S`-units
    - ``prec`` -- (default: 106) the precision of the real field

    OUTPUT:

    The constant ``c3``, as a real number

    EXAMPLES::

        sage: from sage.rings.number_field.S_unit_solver import c3_func
        sage: K.<xi> = NumberField(x^3-3)
        sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3)))

        sage: c3_func(SUK) # abs tol 1e-29
        0.4257859134798034746197327286726

    .. NOTE::

        The numerator should be as close to 1 as possible, especially as the rank of the `S`-units grows large

    REFERENCES:

    - [Sma1995]_ p. 823

    """

    R = RealField(prec)

    all_places = list(SUK.primes()) + SUK.number_field().places(prec)
    Possible_U = Combinations(all_places, SUK.rank())
    c1 = R(0)
    for U in Possible_U:
        # first, build the matrix C_{i,U}
        columns_of_C = []
        for unit in SUK.fundamental_units():
            columns_of_C.append(column_Log(SUK, unit, U, prec))
        C = Matrix(SUK.rank(), SUK.rank(), columns_of_C)
        # Is it invertible?
        if abs(C.determinant()) > 10**(-10):
            poss_c1 = C.inverse().apply_map(abs).norm(Infinity)
            c1 = R(max(poss_c1, c1))
    return R(0.9999999) / (c1*SUK.rank())
示例#13
0
    def fibration_generator(self, dim):
        """
        Generate the lattice polytope fibrations.

        For the purposes of this function, a lattice polytope fiber is
        a sub-lattice polytope. Projecting the plane spanned by the
        subpolytope to a point yields another lattice polytope, the
        base of the fibration.

        INPUT:

        - ``dim`` -- integer. The dimension of the lattice polytope
          fiber.

        OUTPUT:

        A generator yielding the distinct lattice polytope fibers of
        given dimension.

        EXAMPLES::

            sage: P = Polyhedron(toric_varieties.P4_11169().fan().rays(), base_ring=ZZ)
            sage: list( P.fibration_generator(2) )
            [A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 3 vertices]
        """
        from sage.combinat.combination import Combinations
        if not self.is_compact():
            raise ValueError('Only polytopes (compact polyhedra) are allowed.')

        nonzero_points = [p for p in self.integral_points() if not p.is_zero()]
        origin = [[0] * self.ambient_dim()]
        fibers = set()
        parent = self.parent()

        for points in Combinations(nonzero_points, dim):
            plane = parent.element_class(parent, [origin, [], points], None)
            if plane.dim() != dim:
                continue
            fiber = self.intersection(plane)
            if fiber.base_ring() is not ZZ:
                continue
            fiber_vertices = tuple(
                sorted(tuple(v) for v in fiber.vertex_generator()))
            if fiber_vertices not in fibers:
                yield fiber
                fibers.update([fiber_vertices])
            plane._delete()
    def attacking_boxes(self):
        """
        Returns a list of pairs of boxes in ``self`` that are attacking.

        EXAMPLES::

            sage: a = AugmentedLatticeDiagramFilling([[1,6],[2],[3,4,2],[],[],[5,5]])
            sage: a.attacking_boxes()[:5]
            [((1, 1), (2, 1)),
             ((1, 1), (3, 1)),
             ((1, 1), (6, 1)),
             ((1, 1), (2, 0)),
             ((1, 1), (3, 0))]
        """
        boxes = self.boxes()
        res = []
        for (i, j), (ii, jj) in Combinations(boxes, 2):
            if self.are_attacking(i, j, ii, jj):
                res.append(((i, j), (ii, jj)))
        return res
示例#15
0
    def _is_admissible(self, perm):
        """Check if perm is admissible."""

        if not isinstance(perm, PermFlag):
            raise ValueError("Input must be of a valid PermFlag object.")
        
        order = perm.N
        verdict = True
        
        for fp in self.forbidden_perms:
            perm_contains_fp = False
            for c in Combinations(order, fp.N):
                induced_subperm = perm._induced_subpattern(c)
                if induced_subperm == fp.perm:
                    perm_contains_fp = True
                    break
            if perm_contains_fp:
                verdict = False
                break
            
        return verdict
示例#16
0
    def _init_antisymmetric(self):
        """
        Initialization for the antisymmetric product

        EXAMPLES::

            sage: from sage.modules.tensor_operations import \
            ....:      VectorCollection, TensorOperation
            sage: R = VectorCollection([(1,0), (1,2), (-1,-2)], QQ, 2)
            sage: Alt2_R = TensorOperation([R, R], operation='antisymmetric')  # indirect doctest
            sage: sorted(Alt2_R._index_map.iteritems())
            [((0, 1), 0), ((0, 2), 1)]
        """
        n = len(self._V)
        dim = self._V[0].degree()
        Alt = antisymmetrized_coordinate_sums(dim, n)
        from sage.combinat.combination import Combinations
        for i in Combinations(range(self._V[0].n_vectors()), n):
            ray = self._init_power_operation_vectors(i, Alt)
            if ray is not None:
                self._index_map[tuple(i)] = ray
        self._symmetrize_indices = True
示例#17
0
 def first_node_leaves_construction(self):
     final_comb = Combinations(self.edge_labels*2, 2).list()
     for comb in Combinations(self.edge_labels*2, 2):
         if i not in comb and comb[0]!=comb[1]:
             final_comb.append([comb[1], comb[0]])
     return final_comb
示例#18
0
    def _compute_t_flag_products(self, ti):
        """For each type t, generate all quintuples (s, p1, p2, a, b):

        s: admissible permutation (its index)
        p1: flag1 index in self.flags[t]
        p2: flag2 index in self.flags[t]
        a/b: density of p1*p2 in s

        10 Dec 15: for N=6, runs 4min28s
        """
        
        Nset = range(self.N)
        
        num_types = len(self.types)
        num_admissible_perms = len(self.admissible_perms)
        range_num_admissible_perms = range(num_admissible_perms)

        t = self.types[ti]
        m = int((self.N + t.N)/2) # flag order
        t_products = list() # will hold products of flags on type t
        # p(F1,F2,A) = 1/|\Theta|*\sum_{\theta} p(F1,F2,theta,A)
        denom = binomial(self.N,t.N)*binomial(self.N-t.N,m-t.N) 
        
        bigTheta = Combinations(self.N,t.N)#.list()
        
        num_ti_flags = len(self.flags[ti])
        range_num_ti_flags = range(num_ti_flags)
        
        for permi in range_num_admissible_perms:
                
            perm = self.admissible_perms[permi]
            
            # count number of times when F1xF2 == (perm,theta)  // over all theta
            counter =  [[0 for fi in range_num_ti_flags] for fj in range_num_ti_flags]
            
            for S0 in bigTheta: # S0 := im(theta)
                S0vals_in_perm = [perm.perm[x] for x in S0]
                nonimtheta = [x for x in Nset if x not in S0]
                S1_possibilities = Combinations(nonimtheta, m-t.N)
                    
                # condition 1
                if not PermFlag(normalize(S0vals_in_perm, t.N)) == t:
                    continue # go to next theta
                    
                # given cond1, how many times does (cond2 && cond3) hold for each fi,fj from ti-flags
                
                for S1 in S1_possibilities:
                    S1S0 = S1+S0
                    S1S0.sort()
                    subperm1 = [perm.perm[x] for x in S1S0]
                    subperm1_t = [subperm1.index(perm.perm[x]) for x in S0]
                    subperm2 = [perm.perm[x] for x in [x for x in Nset if x not in S1]]
                    subperm2_t = [subperm2.index(perm.perm[x]) for x in S0]
                    
                    perm1flag = PermFlag(normalize(subperm1, m), subperm1_t)
                    
                    toperm = normalize(subperm2,m)
                    perm2flag = PermFlag(toperm, subperm2_t)
                    
                    for fi in range_num_ti_flags:
                        for fj in range(fi, num_ti_flags): # only need to do distinct flags
                            
                            flg1 = self.flags[ti][fi]
                            flg2 = self.flags[ti][fj]
                            
                            # condition 2
                            if not perm1flag == flg1:
                                continue # go to the next S1
                                
                            # condition 3
                            if perm2flag == flg2:
                                counter[fi][fj] += 1
                        # end fj
                    # end fi
                # end S1
                
            # end S0 (i.e. theta)
            for fi in range_num_ti_flags:
                for fj in range_num_ti_flags:
                    if counter[fi][fj] > 0: # save to t_products
                        t_products.append([permi, fi, fj, counter[fi][fj], denom])

        sys.stdout.write("%d, " % ti)
        sys.stdout.flush()
        
        return ti,t_products
示例#19
0
    def is_block_design(self):
        """
        Returns a pair True, pars if the incidence structure is a t-design,
        for some t, where pars is the list of parameters [t, v, k, lmbda].
        The largest possible t is returned, provided t=10.

        EXAMPLES::

            sage: BD = IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
            sage: BD.is_block_design()
            (True, [2, 7, 3, 1])
            sage: BD.block_design_checker(2, 7, 3, 1)
            True
            sage: BD = WittDesign(9)        # optional - gap_packages (design package)
            sage: BD.is_block_design()      # optional - gap_packages (design package)
            (True, [2, 9, 3, 1])
            sage: BD = WittDesign(12)       # optional - gap_packages (design package)
            sage: BD.is_block_design()      # optional - gap_packages (design package)
            (True, [5, 12, 6, 1])
            sage: BD = AffineGeometryDesign(3, 1, GF(2))
            sage: BD.is_block_design()
            (True, [2, 8, 2, 2])
        """
        from sage.combinat.designs.incidence_structures import coordinatewise_product
        from sage.combinat.combinat import unordered_tuples
        from sage.combinat.combination import Combinations
        A = self.incidence_matrix()
        v = len(self.points())
        b = len(self.blocks())
        k = sum(A.columns()[0])
        rowsA = A.rows()
        VS = rowsA[0].parent()
        r = sum(rowsA[0])
        for i in range(b):
            if not(sum(A.columns()[i]) == k):
                return False
        for i in range(v):
            if not(sum(A.rows()[i]) == r):
                return False
        t_found_yet = False
        lambdas = []
        for t in range(2,min(v,11)):
            #print t
            L1 = Combinations(range(v),t)
            L2 = [[rowsA[i] for i in L] for L in L1]
            #print t,len(L2)
            lmbda = VS(coordinatewise_product(L2[0])).hamming_weight()
            lambdas.append(lmbda)
            pars = [t,v,k,lmbda]
            #print pars
            for ell in L2:
                a = VS(coordinatewise_product(ell)).hamming_weight()
                if not(a == lmbda) or a==0:
                    if not(t_found_yet):
                        pars = [t-1,v,k,lambdas[t-3]]
                        return False, pars
                    else:
                        #print pars, lambdas
                        pars = [t-1,v,k,lambdas[t-3]]
                        return True, pars
                t_found_yet = True
        pars = [t-1,v,k,lambdas[t-3]]
        return True, pars
示例#20
0
def trivial_covering_design(v, k, t):
    r"""
    Construct a trivial covering design.

    INPUT:
        v -- integer, size of point set
        k -- integer, cardinality of each block
        t -- integer, cardinality of sets being covered

    OUTPUT:
        (v,k,t) covering design

    EXAMPLE:
        sage: C = trivial_covering_design(8,3,1)
        sage: print C
        C(8,3,1) = 3
        Method: Trivial
        0   1   2   
        0   6   7   
        3   4   5   
        sage: C = trivial_covering_design(5,3,2)
        sage: print C
        4 <= C(5,3,2) <= 10
        Method: Trivial
        0   1   2   
        0   1   3   
        0   1   4   
        0   2   3   
        0   2   4   
        0   3   4   
        1   2   3   
        1   2   4   
        1   3   4   
        2   3   4   

    NOTES:
        Cases are:
        \begin{enumerate}
        \item $t=0$: This could be empty, but it's a useful convention to
        have one block (which is empty if $k=0$).
        \item $t=1$: This contains $\lceil v/k \rceil$ blocks:
        $[0,...,k-1]$,[k,...,2k-1],...$.  The last block
        wraps around if $k$ does not divide $v$.
        \item anything else:  Just use every $k$-subset of $[0,1,...,v-1]$.
        \end{enumerate}

    """
    if t == 0:  #single block [0,...,k-1]
        blk = []
        for i in range(k):
            blk.append(i)
        return CoveringDesign(v, k, t, 1, range(v), [blk], 1, "Trivial")

    if t == 1:  #blocks [0,...,k-1],[k,...,2k-1],...
        size = Rational((v, k)).ceil()
        blocks = []
        for i in range(size - 1):
            blk = []
            for j in range(i * k, (i + 1) * k):
                blk.append(j)
            blocks.append(blk)

        blk = []  # last block: if k does not divide v, wrap around
        for j in range((size - 1) * k, v):
            blk.append(j)
        for j in range(k - len(blk)):
            blk.append(j)
        blk.sort()
        blocks.append(blk)
        return CoveringDesign(v, k, t, size, range(v), blocks, size, "Trivial")

    # default case, all k-subsets
    return CoveringDesign(v, k, t, binomial(v, k), range(v),
                          Combinations(range(v), k), schonheim(v, k, t),
                          "Trivial")
示例#21
0
def ChessboardGraphGenerator(dim_list,
                             rook=True,
                             rook_radius=None,
                             bishop=True,
                             bishop_radius=None,
                             knight=True,
                             knight_x=1,
                             knight_y=2,
                             relabel=False):
    r"""
    Returns a Graph built on a `d`-dimensional chessboard with prescribed
    dimensions and interconnections.

    This function allows to generate many kinds of graphs corresponding to legal
    movements on a `d`-dimensional chessboard: Queen Graph, King Graph, Knight
    Graphs, Bishop Graph, and many generalizations. It also allows to avoid
    redondant code.

    INPUT:

    - ``dim_list`` -- an iterable object (list, set, dict) providing the
      dimensions `n_1, n_2, \ldots, n_d`, with `n_i \geq 1`, of the chessboard.

    - ``rook`` -- (default: ``True``) boolean value indicating if the chess
      piece is able to move as a rook, that is at any distance along a
      dimension.

    - ``rook_radius`` -- (default: None) integer value restricting the rook-like
      movements to distance at most `rook_radius`.

    - ``bishop`` -- (default: ``True``) boolean value indicating if the chess
      piece is able to move like a bishop, that is along diagonals.

    - ``bishop_radius`` -- (default: None) integer value restricting the
      bishop-like movements to distance at most `bishop_radius`.

    - ``knight`` -- (default: ``True``) boolean value indicating if the chess
      piece is able to move like a knight.

    - ``knight_x`` -- (default: 1) integer indicating the number on steps the
      chess piece moves in one dimension when moving like a knight.

    - ``knight_y`` -- (default: 2) integer indicating the number on steps the
      chess piece moves in the second dimension when moving like a knight.

    - ``relabel`` -- (default: ``False``) a boolean set to ``True`` if vertices
      must be relabeled as integers.

    OUTPUT:

    - A Graph build on a `d`-dimensional chessboard with prescribed dimensions,
      and with edges according given parameters.

    - A string encoding the dimensions. This is mainly useful for providing
      names to graphs.

    EXAMPLES:

    A `(2,2)`-King Graph is isomorphic to the complete graph on 4 vertices::

        sage: G, _ = graphs.ChessboardGraphGenerator( [2,2] )
        sage: G.is_isomorphic( graphs.CompleteGraph(4) )
        True

    A Rook's Graph in 2 dimensions is isomporphic to the Cartesian product of 2
    complete graphs::

        sage: G, _ = graphs.ChessboardGraphGenerator( [3,4], rook=True, rook_radius=None, bishop=False, knight=False )
        sage: H = ( graphs.CompleteGraph(3) ).cartesian_product( graphs.CompleteGraph(4) )
        sage: G.is_isomorphic(H)
        True

    TESTS:

    Giving dimensions less than 2::

        sage: graphs.ChessboardGraphGenerator( [0, 2] )
        Traceback (most recent call last):
        ...
        ValueError: The dimensions must be positive integers larger than 1.

    Giving non integer dimensions::

        sage: graphs.ChessboardGraphGenerator( [4.5, 2] )
        Traceback (most recent call last):
        ...
        ValueError: The dimensions must be positive integers larger than 1.

    Giving too few dimensions::

        sage: graphs.ChessboardGraphGenerator( [2] )
        Traceback (most recent call last):
        ...
        ValueError: The chessboard must have at least 2 dimensions.

    Giving a non-iterable object as first parameter::

        sage: graphs.ChessboardGraphGenerator( 2, 3 )
        Traceback (most recent call last):
        ...
        TypeError: The first parameter must be an iterable object.

    Giving too small rook radius::

        sage: graphs.ChessboardGraphGenerator( [2, 3], rook=True, rook_radius=0 )
        Traceback (most recent call last):
        ...
        ValueError: The rook_radius must be either None or have an integer value >= 1.

    Giving wrong values for knights movements::

        sage: graphs.ChessboardGraphGenerator( [2, 3], rook=False, bishop=False, knight=True, knight_x=1, knight_y=-1 )
        Traceback (most recent call last):
        ...
        ValueError: The knight_x and knight_y values must be integers of value >= 1.
    """
    from sage.rings.integer_ring import ZZ

    # We decode the dimensions of the chessboard
    try:
        dim = list(dim_list)
        nb_dim = len(dim)
    except TypeError:
        raise TypeError('The first parameter must be an iterable object.')
    if nb_dim < 2:
        raise ValueError('The chessboard must have at least 2 dimensions.')
    if any(a not in ZZ or a < 1 for a in dim):
        raise ValueError(
            'The dimensions must be positive integers larger than 1.')
    dimstr = str(tuple(dim))

    # We check the radius toward neighbors
    if rook:
        if rook_radius is None:
            rook_radius = max(dim)
        elif not rook_radius in ZZ or rook_radius < 1:
            raise ValueError(
                'The rook_radius must be either None or have an integer value >= 1.'
            )
    if bishop:
        if bishop_radius is None:
            bishop_radius = max(dim)
        elif not bishop_radius in ZZ or bishop_radius < 1:
            raise ValueError(
                'The bishop_radius must be either None or have an integer value >= 1.'
            )
    if knight and (not knight_x in ZZ or not knight_y in ZZ or knight_x < 1
                   or knight_y < 1):
        raise ValueError(
            'The knight_x and knight_y values must be integers of value >= 1.')

    # We build the set of vertices of the d-dimensionnal chessboard
    from itertools import product
    V = [list(x) for x in list(product(*[range(_) for _ in dim]))]

    from sage.combinat.combination import Combinations
    combin = Combinations(range(nb_dim), 2)

    from sage.graphs.graph import Graph
    G = Graph()
    for u in V:
        uu = tuple(u)
        G.add_vertex(uu)

        if rook:
            # We add edges to vertices we can reach when moving in one dimension
            for d in xrange(nb_dim):
                v = u[:]
                for k in xrange(v[d] + 1, min(dim[d], v[d] + 1 + rook_radius)):
                    v[d] = k
                    G.add_edge(uu, tuple(v))

        if bishop or knight:
            # We add edges to vertices we can reach when moving in two dimensions
            for dx, dy in combin:
                n = dim[dx]
                m = dim[dy]
                v = u[:]
                i = u[dx]
                j = u[dy]

                if bishop:
                    # Diagonal
                    for k in xrange(1, min(n - i, m - j, bishop_radius + 1)):
                        v[dx] = i + k
                        v[dy] = j + k
                        G.add_edge(uu, tuple(v))

                    # Anti-diagonal
                    for k in xrange(min(i, m - j - 1, bishop_radius)):
                        v[dx] = i - k - 1
                        v[dy] = j + k + 1
                        G.add_edge(uu, tuple(v))

                if knight:
                    # Moving knight_x in one dimension and knight_y in another
                    # dimension
                    if i + knight_y < n:
                        if j + knight_x < m:
                            v[dx] = i + knight_y
                            v[dy] = j + knight_x
                            G.add_edge(uu, tuple(v))
                        if j - knight_x >= 0:
                            v[dx] = i + knight_y
                            v[dy] = j - knight_x
                            G.add_edge(uu, tuple(v))
                    if j + knight_y < m:
                        if i + knight_x < n:
                            v[dx] = i + knight_x
                            v[dy] = j + knight_y
                            G.add_edge(uu, tuple(v))
                        if i - knight_x >= 0:
                            v[dx] = i - knight_x
                            v[dy] = j + knight_y
                            G.add_edge(uu, tuple(v))

    if relabel:
        G.relabel(inplace=True)
    return G, dimstr
示例#22
0
def trivial_covering_design(v, k, t):
    r"""
    Construct a trivial covering design.

    INPUT:

    - ``v`` -- integer, size of point set

    - ``k`` -- integer, cardinality of each block

    - ``t`` -- integer, cardinality of sets being covered

    OUTPUT:

    A trivial `(v, k, t)` covering design

    EXAMPLES::

        sage: C = trivial_covering_design(8, 3, 1)
        sage: print(C)
        C(8, 3, 1) = 3
        Method: Trivial
        0   1   2
        0   6   7
        3   4   5
        sage: C = trivial_covering_design(5, 3, 2)
        sage: print(C)
        4 <= C(5, 3, 2) <= 10
        Method: Trivial
        0   1   2
        0   1   3
        0   1   4
        0   2   3
        0   2   4
        0   3   4
        1   2   3
        1   2   4
        1   3   4
        2   3   4

    NOTES:

    Cases are:

    * `t=0`: This could be empty, but it's a useful convention to have
      one block (which is empty if $k=0$).

    * `t=1` : This contains `\lceil v/k \rceil` blocks:
      `[0, ..., k-1], [k, ..., 2k-1], ...`.  The last block wraps around if
      `k` does not divide `v`.

    * anything else: Just use every `k`-subset of `[0, 1,..., v-1]`.

    """
    if t == 0:  # single block [0, ..., k-1]
        blk = []
        for i in range(k):
            blk.append(i)
        return CoveringDesign(v, k, t, 1, range(v), [blk], 1, "Trivial")
    if t == 1:  # blocks [0, ..., k-1], [k, ..., 2k-1], ...
        size = Rational((v, k)).ceil()
        blocks = []
        for i in range(size - 1):
            blk = []
            for j in range(i * k, (i + 1) * k):
                blk.append(j)
            blocks.append(blk)
        blk = []  # last block: if k does not divide v, wrap around
        for j in range((size - 1) * k, v):
            blk.append(j)
        for j in range(k - len(blk)):
            blk.append(j)
        blk.sort()
        blocks.append(blk)
        return CoveringDesign(v, k, t, size, range(v), blocks, size, "Trivial")
    # default case, all k-subsets
    return CoveringDesign(v, k, t, binomial(v, k), range(v),
                          Combinations(range(v), k), schonheim(v, k, t),
                          "Trivial")
示例#23
0
            def generalized_noncrossing_partitions(self,
                                                   m,
                                                   c=None,
                                                   positive=False):
                r"""
                Return the set of all chains of length ``m`` in the
                noncrossing partition lattice of ``self``, see
                :meth:`noncrossing_partition_lattice`.

                .. NOTE::

                    ``self`` is assumed to be well-generated.

                INPUT:

                - ``c`` -- (default: ``None``) if an element ``c`` in ``self``
                  is given, it is used as the maximal element in the interval

                - ``positive`` -- (default: ``False``) if ``True``, only those
                  generalized noncrossing partitions of full support are returned

                EXAMPLES::

                    sage: W = ReflectionGroup((1,1,3))                          # optional - gap3

                    sage: sorted([w.reduced_word() for w in chain]              # optional - gap3
                    ....:        for chain in W.generalized_noncrossing_partitions(2))  # optional - gap3
                    [[[], [], [1, 2]],
                     [[], [1], [2]],
                     [[], [1, 2], []],
                     [[], [1, 2, 1], [1]],
                     [[], [2], [1, 2, 1]],
                     [[1], [], [2]],
                     [[1], [2], []],
                     [[1, 2], [], []],
                     [[1, 2, 1], [], [1]],
                     [[1, 2, 1], [1], []],
                     [[2], [], [1, 2, 1]],
                     [[2], [1, 2, 1], []]]

                    sage: sorted([w.reduced_word() for w in chain]              # optional - gap3
                    ....:        for chain in W.generalized_noncrossing_partitions(2, positive=True))   # optional - gap3
                    [[[], [1, 2], []],
                     [[], [1, 2, 1], [1]],
                     [[1], [2], []],
                     [[1, 2], [], []],
                     [[1, 2, 1], [], [1]],
                     [[1, 2, 1], [1], []],
                     [[2], [1, 2, 1], []]]
                """
                from sage.combinat.combination import Combinations
                NC = self.noncrossing_partition_lattice(c=c)
                one = self.one()
                if c is None:
                    c = self.coxeter_element()
                chains = NC.chains()
                NCm = set()
                iter = chains.breadth_first_search_iterator()
                chain = next(iter)
                chain = next(iter)
                while len(chain) <= m:
                    chain.append(c)
                    for i in range(len(chain) - 1, 0, -1):
                        chain[i] = chain[i - 1]**-1 * chain[i]
                    k = m + 1 - len(chain)
                    for positions in Combinations(range(m + 1), k):
                        ncm = []
                        for l in range(m + 1):
                            if l in positions:
                                ncm.append(one)
                            else:
                                l_prime = l - len(
                                    [i for i in positions if i <= l])
                                ncm.append(chain[l_prime])
                        if not positive or prod(ncm[:-1]).has_full_support():
                            NCm.add(tuple(ncm))
                    try:
                        chain = next(iter)
                    except StopIteration:
                        chain = list(range(m + 1))
                return NCm