Repository: sympy/sympy

Issue:
Circle radius should be real
In #15273 a decision was made to not forbid the creation of circles with imaginary radius. I'm not sure this is a useful idea (though looking at imaginary coordinates has been a fruitful and interesting endeavor for [some](https://phantomgraphs.weebly.com/)). Since all Points in geometry are expected to be real, it seems like it would have been better to insist that all geometry parameters are real.

The machinery of Point can be used to make a parameter Rational and insist on being real by doing something like `r = Point(r, 0, evaluate=evaluate).x` as noted in #15816.

cf [here](https://github.com/sympy/sympy/pull/15273#discussion_r219672628)

Discussion:

Patch:
diff --git a/sympy/geometry/ellipse.py b/sympy/geometry/ellipse.py
index d0bd20a059..cbae7e7bd1 100644
--- a/sympy/geometry/ellipse.py
+++ b/sympy/geometry/ellipse.py
@@ -1454,11 +1454,11 @@ def __new__(cls, *args, **kwargs):
                 # Assume (center, radius) pair
                 c = Point(args[0], dim=2, evaluate=evaluate)
                 r = args[1]
-                # TODO: use this instead of the 'if evaluate' block below, but
                 # this will prohibit imaginary radius
-                # r = Point(r, 0, evaluate=evaluate).x  # convert via Point as necessary
-                if evaluate:
-                    r = simplify(nsimplify(r, rational=True))
+                try:
+                    r = Point(r, 0, evaluate=evaluate).x
+                except:
+                    raise GeometryError("Circle with imaginary radius is not permitted")
 
             if not (c is None or r is None):
                 if r == 0:
diff --git a/sympy/logic/boolalg.py b/sympy/logic/boolalg.py
index e5cc6f680b..ffd7c55158 100644
--- a/sympy/logic/boolalg.py
+++ b/sympy/logic/boolalg.py
@@ -5,6 +5,7 @@
 
 from collections import defaultdict
 from itertools import combinations, product
+
 from sympy.core.add import Add
 from sympy.core.basic import Basic
 from sympy.core.cache import cacheit
@@ -15,7 +16,7 @@
 from sympy.core.operations import LatticeOp
 from sympy.core.singleton import Singleton, S
 from sympy.core.sympify import converter, _sympify, sympify
-from sympy.utilities.iterables import sift, ibin
+from sympy.utilities.iterables import sift
 from sympy.utilities.misc import filldedent
 
 
@@ -1492,8 +1493,7 @@ def to_cnf(expr, simplify=False):
     """
     Convert a propositional logical sentence s to conjunctive normal form.
     That is, of the form ((A | ~B | ...) & (B | C | ...) & ...)
-    If simplify is True, the expr is evaluated to its simplest CNF form  using
-    the Quine-McCluskey algorithm.
+    If simplify is True, the expr is evaluated to its simplest CNF form.
 
     Examples
     ========
@@ -1525,8 +1525,7 @@ def to_dnf(expr, simplify=False):
     """
     Convert a propositional logical sentence s to disjunctive normal form.
     That is, of the form ((A & ~B & ...) | (B & C & ...) | ...)
-    If simplify is True, the expr is evaluated to its simplest DNF form using
-    the Quine-McCluskey algorithm.
+    If simplify is True, the expr is evaluated to its simplest DNF form.
 
     Examples
     ========
@@ -1969,71 +1968,28 @@ def _rem_redundancy(l1, terms):
     implicant table method to recognize and eliminate redundant pairs,
     and return the essential arguments.
     """
-
-    if len(terms):
-        # Create dominating matrix
-        dominationmatrix = [[0]*len(l1) for n in range(len(terms))]
-        for primei, prime in enumerate(l1):
-            for termi, term in enumerate(terms):
-                if _compare_term(term, prime):
-                    dominationmatrix[termi][primei] = 1
-
-        nondominatedprimeimplicants = list(range(len(l1)))
-        nondominatedterms = list(range(len(terms)))
-
-        # Mark dominated rows and columns
-        oldnondominatedterms = None
-        oldnondominatedprimeimplicants = None
-        while nondominatedterms != oldnondominatedterms or nondominatedprimeimplicants != oldnondominatedprimeimplicants:
-            oldnondominatedterms = nondominatedterms[:]
-            oldnondominatedprimeimplicants = nondominatedprimeimplicants[:]
-            for rowi, row in enumerate(dominationmatrix):
-                if nondominatedterms[rowi] is not None:
-                    row = [row[i] for i in [_ for _ in nondominatedprimeimplicants if _ is not None]]
-                    for row2i, row2 in enumerate(dominationmatrix):
-                        if rowi != row2i and nondominatedterms[row2i] is not None:
-                            row2 = [row2[i] for i in [_ for _ in nondominatedprimeimplicants if _ is not None]]
-                            if all(a >= b for (a, b) in zip(row2, row)):
-                                # row2 dominating row, keep row
-                                nondominatedterms[row2i] = None
-            for coli in range(len(l1)):
-                if nondominatedprimeimplicants[coli] is not None:
-                    col = [dominationmatrix[a][coli] for a in range(len(terms))]
-                    col = [col[i] for i in [_ for _ in oldnondominatedterms if _ is not None]]
-                    for col2i in range(len(l1)):
-                        if coli != col2i and nondominatedprimeimplicants[col2i] is not None:
-                            col2 = [dominationmatrix[a][col2i] for a in range(len(terms))]
-                            col2 = [col2[i] for i in [_ for _ in oldnondominatedterms if _ is not None]]
-                            if all(a >= b for (a, b) in zip(col, col2)):
-                                # col dominating col2, keep col
-                                nondominatedprimeimplicants[col2i] = None
-        l1 = [l1[i] for i in [_ for _ in nondominatedprimeimplicants if _ is not None]]
-
-        return l1
-    else:
-        return []
-
-def _input_to_binlist(inputlist, variables):
-    binlist = []
-    bits = len(variables)
-    for val in inputlist:
-        if isinstance(val, int):
-            binlist.append(ibin(val, bits))
-        elif isinstance(val, dict):
-            nonspecvars = list(variables)
-            for key in val.keys():
-                nonspecvars.remove(key)
-            for t in product([0, 1], repeat=len(nonspecvars)):
-                d = dict(zip(nonspecvars, t))
-                d.update(val)
-                binlist.append([d[v] for v in variables])
-        elif isinstance(val, (list, tuple)):
-            if len(val) != bits:
-                raise ValueError("Each term must contain {} bits as there are {} variables\n(or be an integer)".format(bits, bits))
-            binlist.append(list(val))
+    essential = []
+    for x in terms:
+        temporary = []
+        for y in l1:
+            if _compare_term(x, y):
+                temporary.append(y)
+        if len(temporary) == 1:
+            if temporary[0] not in essential:
+                essential.append(temporary[0])
+    for x in terms:
+        for y in essential:
+            if _compare_term(x, y):
+                break
         else:
-            raise TypeError("A term list can only contain lists, ints or dicts.")
-    return binlist
+            for z in l1:
+                if _compare_term(x, z):
+                    if z not in essential:
+                        essential.append(z)
+                    break
+
+    return essential
+
 
 def SOPform(variables, minterms, dontcares=None):
     """
@@ -2062,27 +2018,6 @@ def SOPform(variables, minterms, dontcares=None):
     >>> SOPform([w, x, y, z], minterms, dontcares)
     (y & z) | (z & ~w)
 
-    The terms can also be represented as integers:
-
-    >>> minterms = [1, 3, 7, 11, 15]
-    >>> dontcares = [0, 2, 5]
-    >>> SOPform([w, x, y, z], minterms, dontcares)
-    (y & z) | (z & ~w)
-
-    They can also be specified using dicts, which does not have to be fully
-    specified:
-
-    >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
-    >>> SOPform([w, x, y, z], minterms)
-    (x & ~w) | (y & z & ~x)
-
-    Or a combination:
-
-    >>> minterms = [4, 7, 11, [1, 1, 1, 1]]
-    >>> dontcares = [{w : 0, x : 0, y: 0}, 5]
-    >>> SOPform([w, x, y, z], minterms, dontcares)
-    (w & y & z) | (x & y & z) | (~w & ~y)
-
     References
     ==========
 
@@ -2093,8 +2028,8 @@ def SOPform(variables, minterms, dontcares=None):
     if minterms == []:
         return false
 
-    minterms = _input_to_binlist(minterms, variables)
-    dontcares = _input_to_binlist((dontcares or []), variables)
+    minterms = [list(i) for i in minterms]
+    dontcares = [list(i) for i in (dontcares or [])]
     for d in dontcares:
         if d in minterms:
             raise ValueError('%s in minterms is also in dontcares' % d)
@@ -2135,28 +2070,6 @@ def POSform(variables, minterms, dontcares=None):
     >>> POSform([w, x, y, z], minterms, dontcares)
     z & (y | ~w)
 
-    The terms can also be represented as integers:
-
-    >>> minterms = [1, 3, 7, 11, 15]
-    >>> dontcares = [0, 2, 5]
-    >>> POSform([w, x, y, z], minterms, dontcares)
-    z & (y | ~w)
-
-    They can also be specified using dicts, which does not have to be fully
-    specified:
-
-    >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}]
-    >>> POSform([w, x, y, z], minterms)
-    (x | y) & (x | z) & (~w | ~x)
-
-    Or a combination:
-
-    >>> minterms = [4, 7, 11, [1, 1, 1, 1]]
-    >>> dontcares = [{w : 0, x : 0, y: 0}, 5]
-    >>> POSform([w, x, y, z], minterms, dontcares)
-    (w | x) & (y | ~w) & (z | ~y)
-
-
     References
     ==========
 
@@ -2167,8 +2080,8 @@ def POSform(variables, minterms, dontcares=None):
     if minterms == []:
         return false
 
-    minterms = _input_to_binlist(minterms, variables)
-    dontcares = _input_to_binlist((dontcares or []), variables)
+    minterms = [list(i) for i in minterms]
+    dontcares = [list(i) for i in (dontcares or [])]
     for d in dontcares:
         if d in minterms:
             raise ValueError('%s in minterms is also in dontcares' % d)


Test patch:
diff --git a/sympy/geometry/tests/test_ellipse.py b/sympy/geometry/tests/test_ellipse.py
index 76125e5d58..3e15b90986 100644
--- a/sympy/geometry/tests/test_ellipse.py
+++ b/sympy/geometry/tests/test_ellipse.py
@@ -33,9 +33,9 @@ def test_object_from_equation():
     assert Circle(x**2 + y**2 + 6*x + 8) == Circle(Point2D(-3, 0), 1)
     assert Circle(x**2 + y**2 + 6*y + 8) == Circle(Point2D(0, -3), 1)
     assert Circle(6*(x**2) + 6*(y**2) + 6*x + 8*y - 25) == Circle(Point2D(-S(1)/2, -S(2)/3), 5*sqrt(37)/6)
-    assert Circle(x**2 + y**2 + 3*x + 4*y + 26) == Circle(Point2D(-S(3)/2, -2), sqrt(79)*I/2)
-    assert Circle(x**2 + y**2 + 25) == Circle(Point2D(0, 0), 5*I)
-    assert Circle(a**2 + b**2 + 25, x='a', y='b') == Circle(Point2D(0, 0), 5*I)
+    raises(GeometryError, lambda: Circle(x**2 + y**2 + 3*x + 4*y + 26))
+    raises(GeometryError, lambda: Circle(x**2 + y**2 + 25))
+    raises(GeometryError, lambda: Circle(a**2 + b**2 + 25, x='a', y='b'))
     raises(GeometryError, lambda: Circle(x**2 + 6*y + 8))
     raises(GeometryError, lambda: Circle(6*(x ** 2) + 4*(y**2) + 6*x + 8*y + 25))
     raises(ValueError, lambda: Circle(a**2 + b**2 + 3*a + 4*b - 8))
diff --git a/sympy/logic/tests/test_boolalg.py b/sympy/logic/tests/test_boolalg.py
index 529a489221..fab6236892 100644
--- a/sympy/logic/tests/test_boolalg.py
+++ b/sympy/logic/tests/test_boolalg.py
@@ -228,30 +228,6 @@ def test_simplification():
         Or(And(Not(w), z), And(y, z)))
     assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
 
-    minterms = [1, 3, 7, 11, 15]
-    dontcares = [0, 2, 5]
-    assert (
-        SOPform([w, x, y, z], minterms, dontcares) ==
-        Or(And(Not(w), z), And(y, z)))
-    assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
-
-    minterms = [1, [0, 0, 1, 1], 7, [1, 0, 1, 1],
-        [1, 1, 1, 1]]
-    dontcares = [0, [0, 0, 1, 0], 5]
-    assert (
-        SOPform([w, x, y, z], minterms, dontcares) ==
-        Or(And(Not(w), z), And(y, z)))
-    assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z)
-
-    minterms = [{y : 1, z: 1}, 1]
-    dontcares = [[0, 0, 0, 0]]
-
-    minterms = [[0, 0, 0]]
-    raises(ValueError, lambda : SOPform([w, x, y, z], minterms))
-    raises(ValueError, lambda : POSform([w, x, y, z], minterms))
-
-    raises(TypeError, lambda : POSform([w, x, y, z], ["abcdefg"]))
-
     # test simplification
     ans = And(A, Or(B, C))
     assert simplify_logic(A & (B | C)) == ans
@@ -861,33 +837,6 @@ def test_BooleanFunction_diff():
     assert And(x, y).diff(x) == Piecewise((0, Eq(y, False)), (1, True))
 
 
-def test_issue_14700():
-    A, B, C, D, E, F, G, H = symbols('A B C D E F G H')
-    q = ((B & D & H & ~F) | (B & H & ~C & ~D) | (B & H & ~C & ~F) |
-            (B & H & ~D & ~G) | (B & H & ~F & ~G) | (C & G & ~B & ~D) |
-            (C & G & ~D & ~H) | (C & G & ~F & ~H) | (D & F & H & ~B) |
-            (D & F & ~G & ~H) | (B & D & F & ~C & ~H) | (D & E & F & ~B & ~C) |
-            (D & F & ~A & ~B & ~C) | (D & F & ~A & ~C & ~H) |
-            (A & B & D & F & ~E & ~H))
-    soldnf = ((B & D & H & ~F) | (D & F & H & ~B) | (B & H & ~C & ~D) |
-            (B & H & ~D & ~G) | (C & G & ~B & ~D) | (C & G & ~D & ~H) |
-            (C & G & ~F & ~H) | (D & F & ~G & ~H) | (D & E & F & ~C & ~H) |
-            (D & F & ~A & ~C & ~H) | (A & B & D & F & ~E & ~H))
-    solcnf = ((B | C | D) & (B | D | G) & (C | D | H) & (C | F | H) &
-              (D | G | H) & (F | G | H) & (B | F | ~D | ~H) &
-              (~B | ~D | ~F | ~H) & (D | ~B | ~C | ~G | ~H) &
-              (A | H | ~C | ~D | ~F | ~G) & (H | ~C | ~D | ~E | ~F | ~G) &
-              (B | E | H | ~A | ~D | ~F | ~G))
-    assert simplify_logic(q, "dnf") == soldnf
-    assert simplify_logic(q, "cnf") == solcnf
-
-    minterms = [[0, 1, 0, 0], [0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1], [0, 0, 1, 1], [1, 0, 1, 1]]
-    dontcares = [[1, 0, 0, 0], [1, 0, 0, 1], [1, 1, 0, 0], [1, 1, 0, 1]]
-    assert SOPform([w, x, y, z], minterms) == (x & ~w) | (y & z & ~x)
-    # Should not be more complicated with don't cares
-    assert SOPform([w, x, y, z], minterms, dontcares) == (x & ~w) | (y & z & ~x)
-
-
 def test_relational_simplification():
     w, x, y, z = symbols('w x y z', real=True)
     d, e = symbols('d e', real=False)