コード例 #1
0
def _fraction_field(ring):
    r"""
    Return a fraction field of ``ring``.

    EXAMPLES:

    This works around some annoyances with ``ring.fraction_field()``::

        sage: R.<x> = ZZ[]
        sage: S = R.quo(x^2 + 1)
        sage: S.fraction_field()
        Fraction Field of Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1

        sage: from mac_lane.padic_valuation import _fraction_field
        sage: _fraction_field(S)
        Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1

    """
    from sage.categories.all import Fields
    if ring in Fields():
        return ring

    from sage.rings.polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing
    if is_PolynomialQuotientRing(ring):
        from sage.categories.all import IntegralDomains
        if ring in IntegralDomains():
            return ring.base().change_ring(ring.base_ring().fraction_field()).quo(ring.modulus())
    return ring.fraction_field()
コード例 #2
0
    def super_categories(self):
        """
        EXAMPLES::

            sage: FiniteFields().super_categories()
            [Category of fields, Category of finite enumerated sets]
        """
        from sage.categories.all import Fields, FiniteEnumeratedSets
        return [Fields(), FiniteEnumeratedSets()]
コード例 #3
0
ファイル: homset.py プロジェクト: sagemath/sagetrac-mirror
    def __init__(self, R, S, category=None):
        """
        TESTS:

        Check that :trac:`23647` is fixed::

            sage: K.<a, b> = NumberField([x^2 - 2, x^2 - 3])
            sage: e, u, v, w = End(K)
            sage: e.abs_hom().parent().category()
            Category of homsets of number fields
            sage: (v*v).abs_hom().parent().category()
            Category of homsets of number fields
        """
        if category is None:
            from sage.categories.all import Fields, NumberFields
            if S in NumberFields():
                category = NumberFields()
            elif S in Fields():
                category = Fields()
        RingHomset_generic.__init__(self, R, S, category)
コード例 #4
0
ファイル: category_types.py プロジェクト: yarv/sage
    def super_categories(self):
        """
        EXAMPLES::

            sage: ChainComplexes(Integers(9)).super_categories()
            [Category of modules over Ring of integers modulo 9]
        """
        from sage.categories.all import Fields, Modules, VectorSpaces
        base_ring = self.base_ring()
        if base_ring in Fields():
            return [VectorSpaces(base_ring)]
        return [Modules(base_ring)]
コード例 #5
0
    def value_semigroup(self):
        r"""
        Return the value semigroup of this valuation.

        EXAMPLES::

            sage: v = GaussianIntegers().valuation(2)
            sage: v.value_semigroup()
            Additive Abelian Semigroup generated by 1/2

        """
        from sage.categories.all import Fields
        v = self(self.uniformizer())
        if self.domain() in Fields():
            return DiscreteValueSemigroup([-v, v])
        else:
            return DiscreteValueSemigroup([v])
コード例 #6
0
    def value_semigroup(self):
        r"""
        Return the value semigroup of this valuation.

        EXAMPLES::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: v = pAdicValuation(GaussianIntegers(), 2)
            sage: v.value_semigroup()
            Additive Abelian Semigroup generated by 1/2

        """
        from sage.categories.all import Fields
        v = self(self.uniformizer())
        if self.domain() in Fields():
            return DiscreteValueSemigroup([-v,v])
        else:
            return DiscreteValueSemigroup([v])
コード例 #7
0
    def create_object(self, version, key):
        ring, polynomial, names = key

        R = ring.base_ring()
        from sage.categories.all import IntegralDomains
        if R in IntegralDomains():
            try:
                is_irreducible = polynomial.is_irreducible()
            except NotImplementedError: # is_irreducible sometimes not implemented
                pass
            else:
                if is_irreducible:
                    from sage.categories.all import Fields
                    if R in Fields():
                        from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_field
                        return PolynomialQuotientRing_field(ring, polynomial, names)
                    else:
                        from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_domain
                        return PolynomialQuotientRing_domain(ring, polynomial, names)
        from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic
        return PolynomialQuotientRing_generic(ring, polynomial, names)
コード例 #8
0
    def __init__(self, p, V):
        r"""
        Construct an :class:`AffineSubspace`.

        TESTS::

            sage: from sage.geometry.hyperplane_arrangement.affine_subspace import AffineSubspace
            sage: a = AffineSubspace([1,0,0,0], VectorSpace(QQ,4))
            sage: TestSuite(a).run()
            sage: AffineSubspace(0, VectorSpace(QQ,4)).point()
            (0, 0, 0, 0)
        """
        R = V.base_ring()
        from sage.categories.all import Fields
        if R not in Fields():
            R = R.fraction_field()
            V = V.change_ring(R)
        self._base_ring = R
        self._linear_part = V
        p = V.ambient_vector_space()(p)
        p.set_immutable()
        self._point = p
コード例 #9
0
def Polyhedron(vertices=None,
               rays=None,
               lines=None,
               ieqs=None,
               eqns=None,
               ambient_dim=None,
               base_ring=None,
               minimize=True,
               verbose=False,
               backend=None):
    """
    Construct a polyhedron object.

    You may either define it with vertex/ray/line or
    inequalities/equations data, but not both. Redundant data will
    automatically be removed (unless ``minimize=False``), and the
    complementary representation will be computed.

    INPUT:

    - ``vertices`` -- list of point. Each point can be specified as
      any iterable container of ``base_ring`` elements. If ``rays`` or
      ``lines`` are specified but no ``vertices``, the origin is
      taken to be the single vertex.

    - ``rays`` -- list of rays. Each ray can be specified as any
      iterable container of ``base_ring`` elements.

    - ``lines`` -- list of lines. Each line can be specified as any
      iterable container of ``base_ring`` elements.

    - ``ieqs`` -- list of inequalities. Each line can be specified as any
      iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`.

    - ``eqns`` -- list of equalities. Each line can be specified as
      any iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`.

    - ``base_ring`` -- a sub-field of the reals implemented in
      Sage. The field over which the polyhedron will be defined. For
      ``QQ`` and algebraic extensions, exact arithmetic will be
      used. For ``RDF``, floating point numbers will be used. Floating
      point arithmetic is faster but might give the wrong result for
      degenerate input.

    - ``ambient_dim`` -- integer. The ambient space dimension. Usually
      can be figured out automatically from the H/Vrepresentation
      dimensions.

    - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are

      * ``'cdd'``: use cdd
        (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or
        `\RDF` coefficients depending on ``base_ring``.

      * ``'normaliz'``: use normaliz
        (:mod:`~sage.geometry.polyhedron.backend_normaliz`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``.

      * ``'polymake'``: use polymake
        (:mod:`~sage.geometry.polyhedron.backend_polymake`) with `\QQ`, `\RDF` or
        ``QuadraticField`` coefficients depending on ``base_ring``.

      * ``'ppl'``: use ppl
        (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``.

      * ``'field'``: use python implementation
        (:mod:`~sage.geometry.polyhedron.backend_field`) for any field

    Some backends support further optional arguments:

    - ``minimize`` -- boolean (default: ``True``). Whether to
      immediately remove redundant H/V-representation data. Currently
      not used.

    - ``verbose`` -- boolean (default: ``False``). Whether to print
      verbose output for debugging purposes. Only supported by the cdd
      backends.

    OUTPUT:

    The polyhedron defined by the input data.

    EXAMPLES:

    Construct some polyhedra::

        sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]])
        sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]])
        sage: list(square_from_ieqs.vertex_generator())
        [A vertex at (1, -1),
         A vertex at (1, 1),
         A vertex at (-1, 1),
         A vertex at (-1, -1)]
        sage: list(square_from_vertices.inequality_generator())
        [An inequality (1, 0) x + 1 >= 0,
         An inequality (0, 1) x + 1 >= 0,
         An inequality (-1, 0) x + 1 >= 0,
         An inequality (0, -1) x + 1 >= 0]
        sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF)
        sage: p.n_inequalities()
        2

    The same polyhedron given in two ways::

        sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]])
        sage: p.Vrepresentation()
        (A line in the direction (0, 0, 1),
         A ray in the direction (1, 0, 0),
         A ray in the direction (0, 1, 0),
         A vertex at (0, 0, 0))
        sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]])
        sage: q.Hrepresentation()
        (An inequality (1, 0, 0) x + 0 >= 0,
         An inequality (0, 1, 0) x + 0 >= 0)

    Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with
    coordinates `a, b, \dots, f` and

      * The inequality `e+b \geq c+d`
      * The inequality `e+c \geq b+d`
      * The equation `a+b+c+d+e+f = 31`

    ::

        sage: positive_coords = Polyhedron(ieqs=[
        ....:     [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0],
        ....:     [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])
        sage: P = Polyhedron(ieqs=positive_coords.inequalities() + (
        ....:     [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]])
        sage: P
        A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices
        sage: P.dim()
        5
        sage: P.Vrepresentation()
        (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31),
         A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0),
         A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0),
         A vertex at (0, 0, 0, 31/2, 31/2, 0))

    When the input contains elements of a Number Field, they require an
    embedding::

        sage: K = NumberField(x^2-2,'s')
        sage: s = K.0
        sage: L = NumberField(x^3-2,'t')
        sage: t = L.0
        sage: P = Polyhedron(vertices = [[0,s],[t,0]])
        Traceback (most recent call last):
        ...
        ValueError: invalid base ring

    .. NOTE::

      * Once constructed, a ``Polyhedron`` object is immutable.

      * Although the option ``base_ring=RDF`` allows numerical data to
        be used, it might not give the right answer for degenerate
        input data - the results can depend upon the tolerance
        setting of cdd.


    TESTS:

    Check that giving ``float`` input gets converted to ``RDF`` (see :trac:`22605`)::

        sage: f = float(1.1)
        sage: Polyhedron(vertices=[[f]])
        A 0-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex

    Check that giving ``int`` input gets converted to ``ZZ`` (see :trac:`22605`)::

        sage: Polyhedron(vertices=[[int(42)]])
        A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex

    Check that giving ``Fraction`` input gets converted to ``QQ`` (see :trac:`22605`)::

        sage: from fractions import Fraction
        sage: f = Fraction(int(6), int(8))
        sage: Polyhedron(vertices=[[f]])
        A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex

    Check that input with too many bits of precision returns an error (see
    :trac:`22552`)::

        sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), (6.4876921900819049, 4.8435898415984129)])
        Traceback (most recent call last):
        ...
        ValueError: for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd'
    
    Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`)::
    
        sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40))
        Traceback (most recent call last):
        ...
        ValueError: no appropriate backend for computations with Real Field with 40 bits of precision
        sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53))
        Traceback (most recent call last):
        ...
        ValueError: no appropriate backend for computations with Real Field with 53 bits of precision
    """
    # Clean up the arguments
    vertices = _make_listlist(vertices)
    rays = _make_listlist(rays)
    lines = _make_listlist(lines)
    ieqs = _make_listlist(ieqs)
    eqns = _make_listlist(eqns)

    got_Vrep = (len(vertices + rays + lines) > 0)
    got_Hrep = (len(ieqs + eqns) > 0)

    if got_Vrep and got_Hrep:
        raise ValueError('cannot specify both H- and V-representation.')
    elif got_Vrep:
        deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1]
    elif got_Hrep:
        deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1
    else:
        if ambient_dim is None:
            deduced_ambient_dim = 0
        else:
            deduced_ambient_dim = ambient_dim
        if base_ring is None:
            base_ring = ZZ

    # set ambient_dim
    if ambient_dim is not None and deduced_ambient_dim != ambient_dim:
        raise ValueError(
            'ambient space dimension mismatch. Try removing the "ambient_dim" parameter.'
        )
    ambient_dim = deduced_ambient_dim

    # figure out base_ring
    from sage.misc.flatten import flatten
    from sage.structure.element import parent
    from sage.categories.all import Rings, Fields

    values = flatten(vertices + rays + lines + ieqs + eqns)
    if base_ring is not None:
        convert = any(parent(x) is not base_ring for x in values)
    elif not values:
        base_ring = ZZ
        convert = False
    else:
        P = parent(values[0])
        if any(parent(x) is not P for x in values):
            from sage.structure.sequence import Sequence
            P = Sequence(values).universe()
            convert = True
        else:
            convert = False

        from sage.structure.coerce import py_scalar_parent
        if isinstance(P, type):
            base_ring = py_scalar_parent(P)
            convert = convert or P is not base_ring
        else:
            base_ring = P

        if not got_Vrep and base_ring not in Fields():
            base_ring = base_ring.fraction_field()
            convert = True

        if base_ring not in Rings():
            raise ValueError('invalid base ring')

        if not base_ring.is_exact():
            # TODO: remove this hack?
            if base_ring is RR:
                base_ring = RDF
                convert = True
            elif base_ring is not RDF:
                raise ValueError(
                    "for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd'"
                )

    # Add the origin if necessary
    if got_Vrep and len(vertices) == 0:
        vertices = [[0] * ambient_dim]

    # Specific backends can override the base_ring
    from sage.geometry.polyhedron.parent import Polyhedra
    parent = Polyhedra(base_ring, ambient_dim, backend=backend)
    base_ring = parent.base_ring()

    # finally, construct the Polyhedron
    Hrep = Vrep = None
    if got_Hrep:
        Hrep = [ieqs, eqns]
    if got_Vrep:
        Vrep = [vertices, rays, lines]
    return parent(Vrep, Hrep, convert=convert, verbose=verbose)
コード例 #10
0
def Matroid(groundset=None, data=None, **kwds):
    r"""
    Construct a matroid.

    Matroids are combinatorial structures that capture the abstract properties
    of (linear/algebraic/...) dependence. Formally, a matroid is a pair
    `M = (E, I)` of a finite set `E`, the *groundset*, and a collection of
    subsets `I`, the independent sets, subject to the following axioms:

    * `I` contains the empty set
    * If `X` is a set in `I`, then each subset of `X` is in `I`
    * If two subsets `X`, `Y` are in `I`, and `|X| > |Y|`, then there exists
      `x \in X - Y` such that `Y + \{x\}` is in `I`.

    See the :wikipedia:`Wikipedia article on matroids <Matroid>` for more
    theory and examples. Matroids can be obtained from many types of
    mathematical structures, and Sage supports a number of them.

    There are two main entry points to Sage's matroid functionality. For
    built-in matroids, do the following:

    * Within a Sage session, type "matroids." (Do not press "Enter", and do
      not forget the final period ".")
    * Hit "tab".

    You will see a list of methods which will construct matroids. For
    example::

        sage: F7 = matroids.named_matroids.Fano()
        sage: len(F7.nonspanning_circuits())
        7

    or::

        sage: U36 = matroids.Uniform(3, 6)
        sage: U36.equals(U36.dual())
        True

    To define your own matroid, use the function ``Matroid()``.
    This function attempts to interpret its arguments to create an appropriate
    matroid. The following named arguments are supported:

    INPUT:

    - ``groundset`` -- (optional) If provided, the groundset of the
      matroid. Otherwise, the function attempts to determine a groundset
      from the data.

    Exactly one of the following inputs must be given (where ``data``
    must be a positional argument and anything else must be a keyword
    argument):

    - ``data`` -- a graph or a matrix or a RevLex-Index string or a list
      of independent sets containing all bases or a matroid.
    - ``bases`` -- The list of bases (maximal independent sets) of the
      matroid.
    - ``independent_sets`` -- The list of independent sets of the matroid.
    - ``circuits`` -- The list of circuits of the matroid.
    - ``graph`` -- A graph, whose edges form the elements of the matroid.
    - ``matrix`` -- A matrix representation of the matroid.
    - ``reduced_matrix`` -- A reduced representation of the matroid: if
      ``reduced_matrix = A``
      then the matroid is represented by `[I\ \ A]` where `I` is an
      appropriately sized identity matrix.
    - ``rank_function`` -- A function that computes the rank of each subset.
      Can only be provided together with a groundset.
    - ``circuit_closures`` -- Either a list of tuples ``(k, C)`` with ``C``
      the closure of a circuit, and ``k`` the rank of ``C``, or a dictionary
      ``D`` with ``D[k]`` the set of closures of rank-``k`` circuits.
    - ``revlex`` -- the encoding as a string of ``0`` and ``*`` symbols.
      Used by [MatroidDatabase]_ and explained in [MMIB2012]_.
    - ``matroid`` -- An object that is already a matroid. Useful only with the
      ``regular`` option.

    Further options:

    - ``regular`` -- (default: ``False``) boolean. If ``True``,
      output a
      :class:`RegularMatroid <sage.matroids.linear_matroid.RegularMatroid>`
      instance such that, *if* the input defines a valid regular matroid, then
      the output represents this matroid. Note that this option can be
      combined with any type of input.
    - ``ring`` -- any ring. If provided, and the input is a ``matrix`` or
      ``reduced_matrix``, output will be a linear matroid over the ring or
      field ``ring``.
    - ``field`` -- any field. Same as ``ring``, but only fields are allowed.
    - ``check`` -- (default: ``True``) boolean. If ``True`` and
      ``regular`` is true, the output is checked to make sure it is a valid
      regular matroid.

    .. WARNING::

        Except for regular matroids, the input is not checked for validity. If
        your data does not correspond to an actual matroid, the behavior of
        the methods is undefined and may cause strange errors. To ensure you
        have a matroid, run
        :meth:`M.is_valid() <sage.matroids.matroid.Matroid.is_valid>`.

    .. NOTE::

        The ``Matroid()`` method will return instances of type
        :class:`BasisMatroid <sage.matroids.basis_matroid.BasisMatroid>`,
        :class:`CircuitClosuresMatroid <sage.matroids.circuit_closures_matroid.CircuitClosuresMatroid>`,
        :class:`LinearMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`BinaryMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`TernaryMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`QuaternaryMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`RegularMatroid <sage.matroids.linear_matroid.LinearMatroid>`, or
        :class:`RankMatroid <sage.matroids.rank_matroid.RankMatroid>`. To
        import these classes (and other useful functions) directly into Sage's
        main namespace, type::

            sage: from sage.matroids.advanced import *

        See :mod:`sage.matroids.advanced <sage.matroids.advanced>`.

    EXAMPLES:

    Note that in these examples we will often use the fact that strings are
    iterable in these examples. So we type ``'abcd'`` to denote the list
    ``['a', 'b', 'c', 'd']``.

    #.  List of bases:

        All of the following inputs are allowed, and equivalent::

            sage: M1 = Matroid(groundset='abcd', bases=['ab', 'ac', 'ad',
            ....:                                       'bc', 'bd', 'cd'])
            sage: M2 = Matroid(bases=['ab', 'ac', 'ad', 'bc', 'bd', 'cd'])
            sage: M3 = Matroid(['ab', 'ac', 'ad', 'bc', 'bd', 'cd'])
            sage: M4 = Matroid('abcd', ['ab', 'ac', 'ad', 'bc', 'bd', 'cd'])
            sage: M5 = Matroid('abcd', bases=[['a', 'b'], ['a', 'c'],
            ....:                             ['a', 'd'], ['b', 'c'],
            ....:                             ['b', 'd'], ['c', 'd']])
            sage: M1 == M2
            True
            sage: M1 == M3
            True
            sage: M1 == M4
            True
            sage: M1 == M5
            True

        We do not check if the provided input forms an actual matroid::

            sage: M1 = Matroid(groundset='abcd', bases=['ab', 'cd'])
            sage: M1.full_rank()
            2
            sage: M1.is_valid()
            False

        Bases may be repeated::

            sage: M1 = Matroid(['ab', 'ac'])
            sage: M2 = Matroid(['ab', 'ac', 'ab'])
            sage: M1 == M2
            True

    #.  List of independent sets:

        ::

            sage: M1 = Matroid(groundset='abcd',
            ....:              independent_sets=['', 'a', 'b', 'c', 'd', 'ab',
            ....:                               'ac', 'ad', 'bc', 'bd', 'cd'])

        We only require that the list of independent sets contains each basis
        of the matroid; omissions of smaller independent sets and
        repetitions are allowed::

            sage: M1 = Matroid(bases=['ab', 'ac'])
            sage: M2 = Matroid(independent_sets=['a', 'ab', 'b', 'ab', 'a',
            ....:                                'b', 'ac'])
            sage: M1 == M2
            True

    #.  List of circuits:

        ::

            sage: M1 = Matroid(groundset='abc', circuits=['bc'])
            sage: M2 = Matroid(bases=['ab', 'ac'])
            sage: M1 == M2
            True

        A matroid specified by a list of circuits gets converted to a
        :class:`BasisMatroid <sage.matroids.basis_matroid.BasisMatroid>`
        internally::

            sage: M = Matroid(groundset='abcd', circuits=['abc', 'abd', 'acd',
            ....:                                         'bcd'])
            sage: type(M)
            <... 'sage.matroids.basis_matroid.BasisMatroid'>

        Strange things can happen if the input does not satisfy the circuit
        axioms, and these are not always caught by the
        :meth:`is_valid() <sage.matroids.matroid.Matroid.is_valid>` method. So
        always check whether your input makes sense!

        ::

            sage: M = Matroid('abcd', circuits=['ab', 'acd'])
            sage: M.is_valid()
            True
            sage: [sorted(C) for C in M.circuits()] # random
            [['a']]



    #.  Graph:

        Sage has great support for graphs, see :mod:`sage.graphs.graph`.

        ::

            sage: G = graphs.PetersenGraph()
            sage: Matroid(G)
            Graphic matroid of rank 9 on 15 elements

        If each edge has a unique label, then those are used as the ground set
        labels::

            sage: G = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'c')])
            sage: M = Matroid(G)
            sage: sorted(M.groundset())
            ['a', 'b', 'c']

        If there are parallel edges, then integers are used for the ground set.
        If there are no edges in parallel, and is not a complete list of labels,
        or the labels are not unique, then vertex tuples are used::

            sage: G = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'b')])
            sage: M = Matroid(G)
            sage: sorted(M.groundset())
            [(0, 1), (0, 2), (1, 2)]
            sage: H = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'b'), (1, 2, 'c')], multiedges=True)
            sage: N = Matroid(H)
            sage: sorted(N.groundset())
            [0, 1, 2, 3]

        The GraphicMatroid object forces its graph to be connected. If a
        disconnected graph is used as input, it will connect the components.

            sage: G1 = graphs.CycleGraph(3); G2 = graphs.DiamondGraph()
            sage: G = G1.disjoint_union(G2)
            sage: M = Matroid(G)
            sage: M
            Graphic matroid of rank 5 on 8 elements
            sage: M.graph()
            Looped multi-graph on 6 vertices
            sage: M.graph().is_connected()
            True
            sage: M.is_connected()
            False


        If the keyword ``regular`` is set to ``True``, the output will instead
        be an instance of ``RegularMatroid``.

        ::

            sage: G = Graph([(0, 1), (0, 2), (1, 2)])
            sage: M = Matroid(G, regular=True); M
            Regular matroid of rank 2 on 3 elements with 3 bases

        Note: if a groundset is specified, we assume it is in the same order
        as
        :meth:`G.edge_iterator() <sage.graphs.generic_graph.GenericGraph.edge_iterator>`
        provides::

            sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True)
            sage: M = Matroid('abcd', G)
            sage: M.rank(['b', 'c'])
            1

        As before,
        if no edge labels are present and the graph is simple, we use the
        tuples ``(i, j)`` of endpoints. If that fails, we simply use a list
        ``[0..m-1]`` ::

            sage: G = Graph([(0, 1), (0, 2), (1, 2)])
            sage: M = Matroid(G, regular=True)
            sage: sorted(M.groundset())
            [(0, 1), (0, 2), (1, 2)]

            sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True)
            sage: M = Matroid(G, regular=True)
            sage: sorted(M.groundset())
            [0, 1, 2, 3]

        When the ``graph`` keyword is used, a variety of inputs can be
        converted to a graph automatically. The following uses a graph6 string
        (see the :class:`Graph <sage.graphs.graph.Graph>` method's
        documentation)::

            sage: Matroid(graph=':I`AKGsaOs`cI]Gb~')
            Graphic matroid of rank 9 on 17 elements

        However, this method is no more clever than ``Graph()``::

            sage: Matroid(graph=41/2)
            Traceback (most recent call last):
            ...
            ValueError: This input cannot be turned into a graph

    #.  Matrix:

        The basic input is a
        :mod:`Sage matrix <sage.matrix.constructor>`::

            sage: A = Matrix(GF(2), [[1, 0, 0, 1, 1, 0],
            ....:                    [0, 1, 0, 1, 0, 1],
            ....:                    [0, 0, 1, 0, 1, 1]])
            sage: M = Matroid(matrix=A)
            sage: M.is_isomorphic(matroids.CompleteGraphic(4))
            True

        Various shortcuts are possible::

            sage: M1 = Matroid(matrix=[[1, 0, 0, 1, 1, 0],
            ....:                      [0, 1, 0, 1, 0, 1],
            ....:                      [0, 0, 1, 0, 1, 1]], ring=GF(2))
            sage: M2 = Matroid(reduced_matrix=[[1, 1, 0],
            ....:                              [1, 0, 1],
            ....:                              [0, 1, 1]], ring=GF(2))
            sage: M3 = Matroid(groundset=[0, 1, 2, 3, 4, 5],
            ....:              matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:              ring=GF(2))
            sage: A = Matrix(GF(2), [[1, 1, 0], [1, 0, 1], [0, 1, 1]])
            sage: M4 = Matroid([0, 1, 2, 3, 4, 5], A)
            sage: M1 == M2
            True
            sage: M1 == M3
            True
            sage: M1 == M4
            True

        However, with unnamed arguments the input has to be a ``Matrix``
        instance, or the function will try to interpret it as a set of bases::

            sage: Matroid([0, 1, 2], [[1, 0, 1], [0, 1, 1]])
            Traceback (most recent call last):
            ...
            ValueError: basis has wrong cardinality.

        If the groundset size equals number of rows plus number of columns, an
        identity matrix is prepended. Otherwise the groundset size must equal
        the number of columns::

            sage: A = Matrix(GF(2), [[1, 1, 0], [1, 0, 1], [0, 1, 1]])
            sage: M = Matroid([0, 1, 2], A)
            sage: N = Matroid([0, 1, 2, 3, 4, 5], A)
            sage: M.rank()
            2
            sage: N.rank()
            3

        We automatically create an optimized subclass, if available::

            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(2))
            Binary matroid of rank 3 on 6 elements, type (2, 7)
            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(3))
            Ternary matroid of rank 3 on 6 elements, type 0-
            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(4, 'x'))
            Quaternary matroid of rank 3 on 6 elements
            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(2), regular=True)
            Regular matroid of rank 3 on 6 elements with 16 bases

        Otherwise the generic LinearMatroid class is used::

            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(83))
            Linear matroid of rank 3 on 6 elements represented over the Finite
            Field of size 83

        An integer matrix is automatically converted to a matrix over `\QQ`.
        If you really want integers, you can specify the ring explicitly::

            sage: A = Matrix([[1, 1, 0], [1, 0, 1], [0, 1, -1]])
            sage: A.base_ring()
            Integer Ring
            sage: M = Matroid([0, 1, 2, 3, 4, 5], A)
            sage: M.base_ring()
            Rational Field
            sage: M = Matroid([0, 1, 2, 3, 4, 5], A, ring=ZZ)
            sage: M.base_ring()
            Integer Ring

    #.  Rank function:

        Any function mapping subsets to integers can be used as input::

            sage: def f(X):
            ....:     return min(len(X), 2)
            sage: M = Matroid('abcd', rank_function=f)
            sage: M
            Matroid of rank 2 on 4 elements
            sage: M.is_isomorphic(matroids.Uniform(2, 4))
            True

    #.  Circuit closures:

        This is often a really concise way to specify a matroid. The usual way
        is a dictionary of lists::

            sage: M = Matroid(circuit_closures={3: ['edfg', 'acdg', 'bcfg',
            ....:     'cefh', 'afgh', 'abce', 'abdf', 'begh', 'bcdh', 'adeh'],
            ....:     4: ['abcdefgh']})
            sage: M.equals(matroids.named_matroids.P8())
            True

        You can also input tuples `(k, X)` where `X` is the closure of a
        circuit, and `k` the rank of `X`::

            sage: M = Matroid(circuit_closures=[(2, 'abd'), (3, 'abcdef'),
            ....:                               (2, 'bce')])
            sage: M.equals(matroids.named_matroids.Q6())
            True

    #.  RevLex-Index:

        This requires the ``groundset`` to be given and also needs a
        additional keyword argument ``rank`` to specify the rank of the
        matroid::

            sage: M = Matroid("abcdef", "000000******0**", rank=4); M
            Matroid of rank 4 on 6 elements with 8 bases
            sage: list(M.bases())
            [frozenset({'a', 'b', 'd', 'f'}),
             frozenset({'a', 'c', 'd', 'f'}),
             frozenset({'b', 'c', 'd', 'f'}),
             frozenset({'a', 'b', 'e', 'f'}),
             frozenset({'a', 'c', 'e', 'f'}),
             frozenset({'b', 'c', 'e', 'f'}),
             frozenset({'b', 'd', 'e', 'f'}),
             frozenset({'c', 'd', 'e', 'f'})]

        Only the ``0`` symbols really matter, any symbol can be used
        instead of ``*``:

            sage: Matroid("abcdefg", revlex="0++++++++0++++0+++++0+--++----+--++", rank=4)
            Matroid of rank 4 on 7 elements with 31 bases

        It is checked that the input makes sense (but not that it
        defines a matroid)::

            sage: Matroid("abcdef", "000000******0**")
            Traceback (most recent call last):
            ...
            TypeError: for RevLex-Index, the rank needs to be specified
            sage: Matroid("abcdef", "000000******0**", rank=3)
            Traceback (most recent call last):
            ...
            ValueError: expected string of length 20 (6 choose 3), got 15
            sage: M = Matroid("abcdef", "*0000000000000*", rank=4); M
            Matroid of rank 4 on 6 elements with 2 bases
            sage: M.is_valid()
            False

    #.  Matroid:

        Most of the time, the matroid itself is returned::

            sage: M = matroids.named_matroids.Fano()
            sage: N = Matroid(M)
            sage: N is M
            True

        But it can be useful with the ``regular`` option::

            sage: M = Matroid(circuit_closures={2:['adb', 'bec', 'cfa',
            ....:                                  'def'], 3:['abcdef']})
            sage: N = Matroid(M, regular=True)
            sage: N
            Regular matroid of rank 3 on 6 elements with 16 bases
            sage: M == N
            False
            sage: M.is_isomorphic(N)
            True
            sage: Matrix(N) # random
            [1 0 0 1 1 0]
            [0 1 0 1 1 1]
            [0 0 1 0 1 1]

    The ``regular`` option::

        sage: M = Matroid(reduced_matrix=[[1, 1, 0],
        ....:                             [1, 0, 1],
        ....:                             [0, 1, 1]], regular=True)
        sage: M
        Regular matroid of rank 3 on 6 elements with 16 bases

        sage: M.is_isomorphic(matroids.CompleteGraphic(4))
        True

    By default we check if the resulting matroid is actually regular. To
    increase speed, this check can be skipped::

        sage: M = matroids.named_matroids.Fano()
        sage: N = Matroid(M, regular=True)
        Traceback (most recent call last):
        ...
        ValueError: input is not a valid regular matroid
        sage: N = Matroid(M, regular=True, check=False)
        sage: N
        Regular matroid of rank 3 on 7 elements with 32 bases

        sage: N.is_valid()
        False

    Sometimes the output is regular, but represents a different matroid
    from the one you intended::

        sage: M = Matroid(Matrix(GF(3), [[1, 0, 1, 1], [0, 1, 1, 2]]))
        sage: N = Matroid(Matrix(GF(3), [[1, 0, 1, 1], [0, 1, 1, 2]]),
        ....:             regular=True)
        sage: N.is_valid()
        True
        sage: N.is_isomorphic(M)
        False

    TESTS::

        sage: Matroid()
        Traceback (most recent call last):
        ...
        TypeError: no input data given for Matroid()
        sage: Matroid("abc", bases=["abc"], foo="bar")
        Traceback (most recent call last):
        ...
        TypeError: ...Matroid() got an unexpected keyword argument 'foo'
        sage: Matroid(data=["x"], matrix=Matrix(1,1))
        Traceback (most recent call last):
        ...
        TypeError: ...Matroid() got an unexpected keyword argument 'matrix'
        sage: Matroid(bases=["x"], matrix=Matrix(1,1))
        Traceback (most recent call last):
        ...
        TypeError: ...Matroid() got an unexpected keyword argument 'matrix'
        sage: Matroid(Matrix(1,1), ring=ZZ, field=QQ)
        Traceback (most recent call last):
        ...
        TypeError: ...Matroid() got an unexpected keyword argument 'ring'
        sage: Matroid(rank_function=lambda X: len(X))
        Traceback (most recent call last):
        ...
        TypeError: for rank functions, the groundset needs to be specified
        sage: Matroid(matroid="rubbish")
        Traceback (most recent call last):
        ...
        TypeError: input 'rubbish' is not a matroid
    """
    # process options
    want_regular = kwds.pop('regular', False)
    check = kwds.pop('check', True)

    base_ring = None
    if 'field' in kwds:
        base_ring = kwds.pop('field')
        if check and base_ring not in Fields():
            raise TypeError("{} is not a field".format(base_ring))
    elif 'ring' in kwds:
        base_ring = kwds.pop('ring')
        if check and base_ring not in Rings():
            raise TypeError("{} is not a ring".format(base_ring))

    # "key" is the kind of data we got
    key = None
    if data is None:
        for k in [
                'bases', 'independent_sets', 'circuits', 'graph', 'matrix',
                'reduced_matrix', 'rank_function', 'revlex',
                'circuit_closures', 'matroid'
        ]:
            if k in kwds:
                data = kwds.pop(k)
                key = k
                break
        else:
            # Assume that the single positional argument was actually
            # the data (instead of the groundset)
            data = groundset
            groundset = None

    if key is None:
        if isinstance(data, sage.graphs.graph.Graph):
            key = 'graph'
        elif is_Matrix(data):
            key = 'matrix'
        elif isinstance(data, sage.matroids.matroid.Matroid):
            key = 'matroid'
        elif isinstance(data, str):
            key = 'revlex'
        elif data is None:
            raise TypeError("no input data given for Matroid()")
        else:
            key = 'independent_sets'

    # Bases:
    if key == 'bases':
        if groundset is None:
            groundset = set()
            for B in data:
                groundset.update(B)
        M = BasisMatroid(groundset=groundset, bases=data)

    # Independent sets:
    elif key == 'independent_sets':
        # Convert to list of bases first
        rk = -1
        bases = []
        for I in data:
            if len(I) == rk:
                bases.append(I)
            elif len(I) > rk:
                bases = [I]
                rk = len(I)
        if groundset is None:
            groundset = set()
            for B in bases:
                groundset.update(B)
        M = BasisMatroid(groundset=groundset, bases=bases)

    # Circuits:
    elif key == 'circuits':
        # Convert to list of bases first
        # Determine groundset (note that this cannot detect coloops)
        if groundset is None:
            groundset = set()
            for C in data:
                groundset.update(C)
        # determine the rank by computing a basis element
        b = set(groundset)
        for C in data:
            I = b.intersection(C)
            if len(I) >= len(C):
                b.discard(I.pop())
        rk = len(b)
        # Construct the basis matroid of appropriate rank. Note: slow!
        BB = [
            frozenset(B) for B in combinations(groundset, rk)
            if not any(frozenset(C).issubset(B) for C in data)
        ]
        M = BasisMatroid(groundset=groundset, bases=BB)

    # Graphs:

    elif key == 'graph':
        if isinstance(data, sage.graphs.generic_graph.GenericGraph):
            G = data
        else:
            G = Graph(data)
        # Decide on the groundset
        m = G.num_edges()
        if groundset is None:
            # 1. Attempt to use edge labels.
            sl = G.edge_labels()
            if len(sl) == len(set(sl)):
                groundset = sl
                # 2. If simple, use vertex tuples
            elif not G.has_multiple_edges():
                groundset = [(i, j) for i, j, k in G.edge_iterator()]
            else:
                # 3. Use numbers
                groundset = list(range(m))
        if want_regular:
            # Construct the incidence matrix
            # NOTE: we are not using Sage's built-in method because
            # 1) we would need to fix the loops anyway
            # 2) Sage will sort the columns, making it impossible to keep labels!
            V = G.vertices()
            n = G.num_verts()
            A = Matrix(ZZ, n, m, 0)
            mm = 0
            for i, j, k in G.edge_iterator():
                A[V.index(i), mm] = -1
                A[V.index(j), mm] += 1  # So loops get 0
                mm += 1
            M = RegularMatroid(matrix=A, groundset=groundset)
            want_regular = False  # Save some time, since result is already regular
        else:
            M = GraphicMatroid(G, groundset=groundset)

    # Matrices:
    elif key in ['matrix', 'reduced_matrix']:
        A = data
        is_reduced = (key == 'reduced_matrix')

        # Fix the representation
        if not is_Matrix(A):
            if base_ring is not None:
                A = Matrix(base_ring, A)
            else:
                A = Matrix(A)

        # Fix the ring
        if base_ring is not None:
            if A.base_ring() is not base_ring:
                A = A.change_ring(base_ring)
        elif A.base_ring(
        ) is ZZ and not want_regular:  # Usually a rational matrix is intended, we presume.
            A = A.change_ring(QQ)
            base_ring = QQ
        else:
            base_ring = A.base_ring()

        # Check groundset
        if groundset is not None:
            if not is_reduced:
                if len(groundset) == A.ncols():
                    pass
                elif len(groundset) == A.nrows() + A.ncols():
                    is_reduced = True
                else:
                    raise ValueError(
                        "groundset size does not correspond to matrix size")
            elif is_reduced:
                if len(groundset) == A.nrows() + A.ncols():
                    pass
                else:
                    raise ValueError(
                        "groundset size does not correspond to matrix size")

        if is_reduced:
            kw = dict(groundset=groundset, reduced_matrix=A)
        else:
            kw = dict(groundset=groundset, matrix=A)

        if isinstance(base_ring, FiniteField):
            q = base_ring.order()
        else:
            q = 0

        if q == 2:
            M = BinaryMatroid(**kw)
        elif q == 3:
            M = TernaryMatroid(**kw)
        elif q == 4:
            M = QuaternaryMatroid(**kw)
        else:
            M = LinearMatroid(ring=base_ring, **kw)

    # Rank functions:
    elif key == 'rank_function':
        if groundset is None:
            raise TypeError(
                'for rank functions, the groundset needs to be specified')
        M = RankMatroid(groundset=groundset, rank_function=data)

    # RevLex-Index:
    elif key == "revlex":
        if groundset is None:
            raise TypeError(
                'for RevLex-Index, the groundset needs to be specified')
        try:
            rk = kwds.pop("rank")
        except KeyError:
            raise TypeError('for RevLex-Index, the rank needs to be specified')

        groundset = tuple(groundset)
        data = tuple(data)
        rk = int(rk)
        N = len(groundset)

        def revlex_sort_key(s):
            return tuple(reversed(s))

        subsets = sorted(combinations(range(N), rk), key=revlex_sort_key)
        if len(data) != len(subsets):
            raise ValueError(
                "expected string of length %s (%s choose %s), got %s" %
                (len(subsets), N, rk, len(data)))
        bases = []
        for i, x in enumerate(data):
            if x != '0':
                bases.append([groundset[c] for c in subsets[i]])
        M = BasisMatroid(groundset=groundset, bases=bases)

    # Circuit closures:
    elif key == 'circuit_closures':
        if isinstance(data, dict):
            CC = data
        else:
            # Convert to dictionary
            CC = {}
            for X in data:
                if X[0] not in CC:
                    CC[X[0]] = []
                CC[X[0]].append(X[1])

        if groundset is None:
            groundset = set()
            for X in CC.values():
                for Y in X:
                    groundset.update(Y)

        M = CircuitClosuresMatroid(groundset=groundset, circuit_closures=CC)

    # Matroids:
    elif key == 'matroid':
        if not isinstance(data, sage.matroids.matroid.Matroid):
            raise TypeError("input {!r} is not a matroid".format(data))
        M = data

    else:
        raise AssertionError("unknown key %r" % key)

    # All keywords should be used
    for k in kwds:
        raise TypeError(
            "Matroid() got an unexpected keyword argument '{}'".format(k))

    if want_regular:
        M = sage.matroids.utilities.make_regular_matroid_from_matroid(M)
        if check and not M.is_valid():
            raise ValueError('input is not a valid regular matroid')

    return M
コード例 #11
0
ファイル: padic_valuation.py プロジェクト: timgates42/sage
    def simplify(self, x, error=None, force=False, size_heuristic_bound=32):
        r"""
        Return a simplified version of ``x``.

        Produce an element which differs from ``x`` by an element of
        valuation strictly greater than the valuation of ``x`` (or strictly
        greater than ``error`` if set.)

        INPUT:

        - ``x`` -- an element in the domain of this valuation

        - ``error`` -- a rational, infinity, or ``None`` (default: ``None``),
          the error allowed to introduce through the simplification

        - ``force`` -- ignored

        - ``size_heuristic_bound`` -- when ``force`` is not set, the expected
          factor by which the ``x`` need to shrink to perform an actual
          simplification (default: 32)

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: v.simplify(6, force=True)
            2
            sage: v.simplify(6, error=0, force=True)
            0

        In this example, the usual rational reconstruction misses a good answer
        for some moduli (because the absolute value of the numerator is not
        bounded by the square root of the modulus)::

            sage: v = QQ.valuation(2)
            sage: v.simplify(110406, error=16, force=True)
            562/19
            sage: Qp(2, 16)(110406).rational_reconstruction()
            Traceback (most recent call last):
            ...
            ArithmeticError: rational reconstruction of 55203 (mod 65536) does not exist

        """
        if not force and self._relative_size(x) <= size_heuristic_bound:
            return x

        x = self.domain().coerce(x)

        v = self(x)
        if error is None:
            error = v
        from sage.rings.all import infinity
        if error is infinity:
            return x
        if error < v:
            return self.domain().zero()

        from sage.rings.all import QQ
        from sage.rings.all import Qp
        precision_ring = Qp(self.p(), QQ(error).floor() + 1 - v)
        reduced = precision_ring(x)
        lift = (reduced >> v).lift()
        best = self.domain()(lift) * self.p()**v

        if self._relative_size(x) < self._relative_size(best):
            best = x

        # We implement a modified version of the usual rational reconstruction
        # algorithm (based on the extended Euclidean algorithm) here. We do not
        # get the uniqueness properties but we do not need them actually.
        # This is certainly slower than the implementation in Cython.
        from sage.categories.all import Fields
        m = self.p()**(QQ(error).floor() + 1 - v)
        if self.domain() in Fields():
            r = (m, lift)
            s = (0, 1)
            while r[1]:
                qq, rr = r[0].quo_rem(r[1])
                r = r[1], rr
                s = s[1], s[0] - qq * s[1]
                from sage.arith.all import gcd
                if s[1] != 0 and gcd(s[1], r[1]) == 1:
                    rational = self.domain()(r[1]) / self.domain()(
                        s[1]) * self.p()**v
                    if self._relative_size(rational) < self._relative_size(
                            best):
                        best = rational

        assert (self(x - best) > error)

        return best