|
209 | 209 | from sage.matrix.all import column_matrix, matrix, MatrixSpace |
210 | 210 | from sage.misc.all import cached_method, flatten, latex |
211 | 211 | from sage.modules.all import span, vector, VectorSpace |
212 | | -from sage.rings.all import QQ, RR, ZZ |
| 212 | +from sage.rings.all import QQ, ZZ |
213 | 213 | from sage.structure.all import SageObject, parent |
214 | 214 | from sage.structure.richcmp import richcmp_method, richcmp |
215 | 215 | from ppl import (C_Polyhedron, Generator_System, Constraint_System, |
@@ -526,47 +526,85 @@ def _ambient_space_point(body, data): |
526 | 526 |
|
527 | 527 | OUTPUT: |
528 | 528 |
|
529 | | - - integral, rational or numeric point of the ambient space of ``body`` |
530 | | - if ``data`` were successfully interpreted in such a way, otherwise a |
531 | | - ``TypeError`` exception is raised |
| 529 | + An integral, rational, real algebraic, or numeric point of the |
| 530 | + ambient space of ``body`` is returned if ``data`` were |
| 531 | + successfully interpreted in such a way. A ``TypeError`` is raised |
| 532 | + otherwise. |
532 | 533 |
|
533 | 534 | TESTS:: |
534 | 535 |
|
535 | 536 | sage: from sage.geometry.cone import _ambient_space_point |
536 | 537 | sage: c = Cone([(1,0), (0,1)]) |
537 | 538 | sage: _ambient_space_point(c, [1,1]) |
538 | 539 | N(1, 1) |
| 540 | + sage: _ambient_space_point(c, vector(ZZ,[1,1])) |
| 541 | + N(1, 1) |
539 | 542 | sage: _ambient_space_point(c, c.dual_lattice()([1,1])) |
540 | 543 | Traceback (most recent call last): |
541 | 544 | ... |
542 | 545 | TypeError: the point M(1, 1) and |
543 | 546 | 2-d cone in 2-d lattice N have incompatible lattices |
544 | 547 | sage: _ambient_space_point(c, [1,1/3]) |
545 | 548 | (1, 1/3) |
| 549 | + sage: _ambient_space_point(c, vector(QQ,[1,1/3])) |
| 550 | + (1, 1/3) |
546 | 551 | sage: _ambient_space_point(c, [1/2,1/sqrt(3)]) |
547 | | - (0.500000000000000, 0.577350269189626) |
| 552 | + (1/2, 0.5773502691896258?) |
| 553 | + sage: _ambient_space_point(c, vector(AA,[1/2,1/sqrt(3)])) |
| 554 | + (1/2, 0.5773502691896258?) |
548 | 555 | sage: _ambient_space_point(c, [1,1,3]) |
549 | 556 | Traceback (most recent call last): |
550 | 557 | ... |
551 | 558 | TypeError: [1, 1, 3] does not represent a valid point |
552 | | - in the ambient space of 2-d cone in 2-d lattice N |
| 559 | + in the ambient space of 2-d cone in 2-d lattice N |
| 560 | + sage: _ambient_space_point(c, vector(ZZ,[1,1,3])) |
| 561 | + Traceback (most recent call last): |
| 562 | + ... |
| 563 | + TypeError: (1, 1, 3) does not represent a valid point |
| 564 | + in the ambient space of 2-d cone in 2-d lattice N |
| 565 | +
|
| 566 | + Ensure that transcendental elements can, at the very least, be |
| 567 | + represented numerically:: |
| 568 | +
|
| 569 | + sage: from sage.geometry.cone import _ambient_space_point |
| 570 | + sage: c = Cone([(1,0), (0,1)]) |
| 571 | + sage: _ambient_space_point(c, [1, pi]) |
| 572 | + (1.00000000000000, 3.14159265358979) |
| 573 | + sage: _ambient_space_point(c, vector(SR,[1, pi])) |
| 574 | + (1.00000000000000, 3.14159265358979) |
| 575 | +
|
553 | 576 | """ |
| 577 | + from sage.rings.all import AA, RR |
| 578 | + |
554 | 579 | L = body.lattice() |
555 | | - try: # to make a lattice element... |
556 | | - return L(data) |
557 | | - except TypeError: |
558 | | - # Special treatment for toric lattice elements |
559 | | - if is_ToricLattice(parent(data)): |
560 | | - raise TypeError("the point %s and %s have incompatible " |
561 | | - "lattices" % (data, body)) |
562 | | - try: # ... or an exact point... |
563 | | - return L.base_extend(QQ)(data) |
564 | | - except TypeError: |
565 | | - pass |
566 | | - try: # ... or at least a numeric one |
567 | | - return L.base_extend(RR)(data) |
568 | | - except TypeError: |
569 | | - pass |
| 580 | + |
| 581 | + def try_base_extend(ring): |
| 582 | + # Factor out the "try this ring..." code that's repeated four |
| 583 | + # times. |
| 584 | + try: |
| 585 | + return L.base_extend(ring)(data) |
| 586 | + except TypeError: |
| 587 | + pass |
| 588 | + except ValueError as ex: |
| 589 | + if str(ex).startswith("Cannot coerce"): |
| 590 | + pass |
| 591 | + |
| 592 | + # Special treatment for toric lattice elements |
| 593 | + p = try_base_extend(ZZ) |
| 594 | + if p is not None: |
| 595 | + return p |
| 596 | + if is_ToricLattice(parent(data)): |
| 597 | + raise TypeError("the point %s and %s have incompatible " |
| 598 | + "lattices" % (data, body)) |
| 599 | + |
| 600 | + # If we don't have a lattice element, try successively |
| 601 | + # less-desirable ambient spaces until (as a last resort) we |
| 602 | + # attempt a numerical representation. |
| 603 | + for ring in [QQ, AA, RR]: |
| 604 | + p = try_base_extend(ring) |
| 605 | + if p is not None: |
| 606 | + return p |
| 607 | + |
570 | 608 | # Raise TypeError with our own message |
571 | 609 | raise TypeError("%s does not represent a valid point in the ambient " |
572 | 610 | "space of %s" % (data, body)) |
@@ -1546,34 +1584,67 @@ def _contains(self, point, region='whole cone'): |
1546 | 1584 | This function is called by :meth:`__contains__` and :meth:`contains` |
1547 | 1585 | to ensure the same call depth for warning messages. |
1548 | 1586 |
|
| 1587 | + By default, a point on the boundary of the cone is considered |
| 1588 | + part of the cone. If you want to test whether the |
| 1589 | + **interior** of the cone contains the point, you need to pass |
| 1590 | + the optional argument ``'interior'``. If you want to test |
| 1591 | + whether the **relative interior** of the cone contains the |
| 1592 | + point, you need to pass the optional argument |
| 1593 | + ``'relative_interior'``. |
| 1594 | +
|
| 1595 | + .. WARNING:: |
| 1596 | +
|
| 1597 | + The boundary of a closed convex cone is determined by a |
| 1598 | + set of inequalities. If your ``point`` has entries in an |
| 1599 | + inexact ring, it will sometimes be impossible to say (with |
| 1600 | + confidence) if that point lies on the boundary of the cone |
| 1601 | + or slightly inside it. |
| 1602 | +
|
1549 | 1603 | INPUT: |
1550 | 1604 |
|
1551 | | - - ``point`` -- anything. An attempt will be made to convert it into a |
1552 | | - single element of the ambient space of ``self``. If it fails, |
1553 | | - ``False`` is returned; |
| 1605 | + - ``point`` -- anything; an attempt will be made to convert it |
| 1606 | + into an element compatible with the ambient space of ``self``. |
1554 | 1607 |
|
1555 | | - - ``region`` -- string. Can be either 'whole cone' (default), |
1556 | | - 'interior', or 'relative interior'. By default, a point on |
1557 | | - the boundary of the cone is considered part of the cone. If |
1558 | | - you want to test whether the **interior** of the cone |
1559 | | - contains the point, you need to pass the optional argument |
1560 | | - ``'interior'``. If you want to test whether the **relative |
1561 | | - interior** of the cone contains the point, you need to pass |
1562 | | - the optional argument ``'relative_interior'``. |
| 1608 | + - ``region`` -- a string (default: 'whole cone'); can be |
| 1609 | + either 'whole cone', 'interior', or 'relative interior'. |
1563 | 1610 |
|
1564 | 1611 | OUTPUT: |
1565 | 1612 |
|
1566 | | - - ``True`` if ``point`` is contained in the specified ``region`` of |
1567 | | - ``self``, ``False`` otherwise. |
| 1613 | + ``True`` is returned if ``point`` is contained in the |
| 1614 | + specified ``region`` of ``self``. ``False`` is returned |
| 1615 | + otherwise, in particular when ``point`` is incompatible with |
| 1616 | + the ambient space. |
1568 | 1617 |
|
1569 | | - Raises a ``ValueError`` if ``region`` is not one of the |
| 1618 | + A ``ValueError`` is raised if ``region`` is not one of the |
1570 | 1619 | three allowed values. |
1571 | 1620 |
|
1572 | 1621 | TESTS:: |
1573 | 1622 |
|
1574 | 1623 | sage: c = Cone([(1,0), (0,1)]) |
1575 | 1624 | sage: c._contains((1,1)) |
1576 | 1625 | True |
| 1626 | +
|
| 1627 | + We can test vectors with irrational components:: |
| 1628 | +
|
| 1629 | + sage: c = Cone([(1,0), (0,1)]) |
| 1630 | + sage: c._contains((1,sqrt(2))) |
| 1631 | + True |
| 1632 | + sage: c._contains(vector(SR, [1,pi])) |
| 1633 | + True |
| 1634 | +
|
| 1635 | + Ensure that complex vectors are not contained in a real cone:: |
| 1636 | +
|
| 1637 | + sage: c = Cone([(1,0), (0,1)]) |
| 1638 | + sage: c._contains((1,I)) |
| 1639 | + False |
| 1640 | + sage: c._contains(vector(QQbar,[1,I])) |
| 1641 | + False |
| 1642 | +
|
| 1643 | + And we refuse to coerce elements of another lattice into ours:: |
| 1644 | +
|
| 1645 | + sage: c = Cone([(1,0), (0,1)]) |
| 1646 | + sage: c._contains(c.dual().ray(0)) |
| 1647 | + False |
1577 | 1648 | """ |
1578 | 1649 | try: |
1579 | 1650 | point = _ambient_space_point(self, point) |
|
0 commit comments