README.md

# quadratic

A small Python library for solving real quadratic equations. We return
the discriminant, the set of real roots, the number of real roots, and
the vertex of the parabola.

## Tutorial

We are going to solve the quadratic \(x^2 - 3 x + 2 = 0\). The
coefficients are \(a = 1\), \(b = -3\), \(c = 2\). We start by importing
the library:

```python
>>> import sympy
>>> import quadratic
>>> x = sympy.Symbol("x")

```

The discriminant is positive:

```python
>>> quadratic.discriminant(1, -3, 2)
1

```

so we expect two distinct real roots. Calling `solutions` returns a
`sympy` set containing them:

```python
>>> quadratic.solutions(1, -3, 2, x)
{1, 2}

```

The number of real roots is

```python
>>> quadratic.number_of_real_roots(1, -3, 2)
2

```

and the vertex of the parabola \(y = x^2 - 3 x + 2\) is at

```python
>>> quadratic.vertex(1, -3, 2)
(3/2, -1/4)

```

## How to guide

### How to compute the discriminant

To compute \(b^2 - 4 a c\) for a quadratic \(a x^2 + b x + c\):

```python
>>> import quadratic
>>> quadratic.discriminant(2, 4, 2)
0

```

### How to find the real roots

To find the real roots we need to pass a `sympy.Symbol` for the
unknown:

```python
>>> import sympy
>>> import quadratic
>>> x = sympy.Symbol("x")
>>> quadratic.solutions(1, -2, 1, x)
{1}

```

If there are no real roots the returned set is empty:

```python
>>> quadratic.solutions(1, 0, 1, x)
EmptySet

```

### How to classify by number of real roots

```python
>>> import quadratic
>>> quadratic.number_of_real_roots(1, -3, 2)
2
>>> quadratic.number_of_real_roots(1, -2, 1)
1
>>> quadratic.number_of_real_roots(1, 0, 1)
0

```

### How to find the vertex of the parabola

```python
>>> import quadratic
>>> quadratic.vertex(1, -2, 1)
(1, 0)

```

## Discussion

A quadratic equation has the form \(a x^2 + b x + c = 0\) with
\(a \ne 0\). The quadratic formula gives the two solutions as

\[
    x = \frac{-b \pm \sqrt{b^2 - 4 a c}}{2 a}.
\]

The quantity under the square root is the discriminant
\(\Delta = b^2 - 4 a c\). When \(\Delta > 0\) the equation has two
distinct real roots; when \(\Delta = 0\) the two roots collapse onto a
single repeated root; and when \(\Delta < 0\) there are no real roots
because the formula asks for the square root of a negative number.

The vertex of the parabola \(y = a x^2 + b x + c\) is at
\(x = -b / (2 a)\), which is also halfway between the two real roots
when they exist. We expose this as a separate function because it is
useful for sketching the parabola without having to solve the quadratic
first.

### How we built this

We could have implemented the quadratic formula by hand, but
`sympy.solveset` already handles every case, including the empty-set
case when there are no real roots. We pass the domain `sympy.S.Reals`
so that we only get real solutions back: the default domain would also
include complex roots, and the marking scheme of this module asks us
only about real roots.

The library is built on the conventions of the `pfm` algebra chapter
[1]: every input is treated symbolically by wrapping it in
`sympy.S(...)` before doing arithmetic, and the answer comes back as a
`sympy` expression rather than a `float`.

## Reference

### List of functionality

A list of functionality in this library is:

- `discriminant(quadratic_coefficient, linear_coefficient,
  constant_coefficient)`: return \(b^2 - 4 a c\).
- `solutions(quadratic_coefficient, linear_coefficient,
  constant_coefficient, variable)`: return the real roots as a
  `sympy.Set`.
- `number_of_real_roots(quadratic_coefficient, linear_coefficient,
  constant_coefficient)`: return 0, 1, or 2.
- `vertex(quadratic_coefficient, linear_coefficient,
  constant_coefficient)`: return the vertex of the parabola.

### Tests

The tests live in `test_quadratic.py` and can be run with:

```sh
python test_quadratic.py
```

They cover the three discriminant cases and check the vertex against
the known parabolas \(y = x^2\) and \(y = (x - 1)^2\).

### Bibliography

[1] Knight, V. *Python for Mathematics*, vknight.org/pfm. Accessed 2026.