index

⚠️ This module is not part of this project and is only included for reference.
It is either part of the 1lab, the cubical library, or a built-in Agda module.

<!--
```
open import 1Lab.Path.IdentitySystem
open import 1Lab.HLevel.Retracts
open import 1Lab.Equiv
open import 1Lab.Path
open import 1Lab.Type

open import Data.Dec.Base
open import Data.Nat.Base
```
-->

```agda
module Data.Int.Base where
```

# The integers {defines=integers}

The familiar [[set]] of integers, in addition to its intuitive
characterisation in terms of positive and negative numbers, can be
specified by a wide variety of universal properties:

- The set of integers, with the operation of addition, is the [[free
group]] on one generator.

- The set of integers, with the operations of addition and
multiplication, is the [[initial ring]].

- The set of integers under addition, considered together with the
embedding $\bN \mono \bZ$ of the positive numbers, is the free group
generated by the _monoid_ of natural numbers.

- The set of integers is the [[loop space of the circle]]. More
generally, it appears (as a group under addition) as the first
non-trivial higher homotopy group of all spheres: $\pi_n(\bS^n) \cong
\bZ$.

- The set of integers, with the number zero and the successor
equivalence, is the [initial pointed type with an
equivalence](Data.Int.Universal.html).

All of these specifications can be turned into code, and regardless of
your choice, it would be provably equivalent to any of the others.
Therefore, there is no _mathematical_ reason to pick one over the
others. However, the real world imposes two constraints on us:
convenience and efficiency.

On the convenience front, it's simply more convenient to formalise
further results if there is a definition of the integers which we take
as _the_ definition. And, since this definition will be ubiquitous, it's
best if it has compact normal forms for numbers, and supports definition
of the relevant structure in a computationally nice way.

For definiteness, we go with the most elementary, inductive
representation:

```agda
data Int : Type where
  pos    : Nat  Int
  negsuc : Nat  Int
```

<!--
```agda
{-# BUILTIN INTEGER       Int    #-}
{-# BUILTIN INTEGERPOS    pos    #-}
{-# BUILTIN INTEGERNEGSUC negsuc #-}

pattern posz     = pos zero
pattern possuc x = pos (suc x)
```
-->

The definition above is isomorphic to a [[sum type]], where both
summands are the natural numbers. However, if we interpret this naïvely,
then we would have a problem: there are now two copies of the number
zero! This is, essentially, a problem of _intent_. We have to choose one
of the two summands to contain the number zero, and the names we choose
for the constructors must reflect this.

The constructor `pos`{.Agda} embeds the positive numbers --- incl. zero!
--- while the constructor `negsuc`{.Agda} constructs the **neg**ation of
a **succ**essor. This means that `negsuc 0`{.Agda} is the representation
of the number $-1$.

Other than these constructors, we can define a difference operation,
between natural numbers, valued in the integers. This difference
correctly reflects, in its sign, whether we tried to subtract a large
quantity from a smaller quantity.

```agda
_ℕ-_ : Nat  Nat  Int
x     ℕ- zero  = pos x
zero  ℕ- suc y = negsuc y
suc x ℕ- suc y = x ℕ- y
```

We can also use this to demonstrate the offsetting built into
`negsuc`{.Agda}:

```agda
_ : 0 ℕ- 20  negsuc 19
_ = refl
```

<!--
```agda
pos-injective :  {x y}  pos x  pos y  x  y
pos-injective = ap (case_of λ { (pos x)  x ; (negsuc _)  zero })

negsuc-injective :  {x y}  negsuc x  negsuc y  x  y
negsuc-injective = ap (case_of λ { (pos x)  0 ; (negsuc x)  x })

pos≠negsuc :  {x y}  pos x  negsuc y  
pos≠negsuc p = subst  { (pos x)   ; (negsuc _)   }) p tt

negsuc≠pos :  {x y}  negsuc x  pos y  
negsuc≠pos p = pos≠negsuc (sym p)

_ = Discrete-Nat
```
-->

## Equality

We mentioned in the introductory paragraph that the type of integers is
a [[set]]. We will show something stronger: it's actually [[discrete]].
This means that we have a procedure that can tell whether two integers
are equal, and produce a refutation when they are not equal.
Intuitively, this is because the natural numbers are discrete, and it's
[[embedded|embedding]] in the integers.

The first thing to do is discriminate between the two constructors. If
they match, we can compare the underlying natural numbers:

```agda
instance
  Discrete-Int : Discrete Int
  Discrete-Int {pos x} {pos y} with x ≡? y
  ... | yes p = yes (ap pos p)
  ... | no ¬p = no λ path  ¬p (pos-injective path)
  Discrete-Int {negsuc x} {negsuc y} with x ≡? y
  ... | yes p = yes (ap negsuc p)
  ... | no ¬p = no λ path  ¬p (negsuc-injective path)
```

If they're mismatched, we have pre-existing refutations.

```agda
  Discrete-Int {pos x} {negsuc y} = no pos≠negsuc
  Discrete-Int {negsuc x} {pos y} = no negsuc≠pos
```

<!--
```agda
  Number-Int : Number Int
  Number-Int .Number.Constraint _ = 
  Number-Int .Number.fromNat n    = pos n

  Negative-Int : Negative Int
  Negative-Int .Negative.Constraint _ = 
  Negative-Int .Negative.fromNeg zero = pos zero
  Negative-Int .Negative.fromNeg (suc x) = negsuc x

  opaque
    H-Level-Int :  {n}  H-Level Int (2 + n)
    H-Level-Int = basic-instance 2 (Discrete→is-set Discrete-Int)
```
-->

## As the universal symmetry

One of the mentioned characterisations of the integers was as the
[[initial|initial object]] type equipped with a point and an
auto-equivalence. This equivalence is the _successor_ function: if we
picture the integers as a number line, the effect of this equivalence is
to "rotate" the line to the right.

```agda
sucℤ : Int  Int
sucℤ (pos n)          = pos (suc n)
sucℤ (negsuc zero)    = 0
sucℤ (negsuc (suc n)) = negsuc n

predℤ : Int  Int
predℤ (pos zero)    = -1
predℤ (pos (suc n)) = pos n
predℤ (negsuc n)    = negsuc (suc n)
```

The definition of the successor and predecessor functions is slightly
complicated by the need to adjust by one when passing between the
summands. The proof that these are inverses is a case bash precisely
mirroring the structure of the functions.

```agda
suc-predℤ : (x : Int)  sucℤ (predℤ x)  x
suc-predℤ (negsuc x)    = refl
suc-predℤ (pos zero)    = refl
suc-predℤ (pos (suc x)) = refl

pred-sucℤ : (x : Int)  predℤ (sucℤ x)  x
pred-sucℤ (pos x)          = refl
pred-sucℤ (negsuc zero)    = refl
pred-sucℤ (negsuc (suc x)) = refl

suc-equiv : Int  Int
suc-equiv = Iso→Equiv (sucℤ , iso predℤ suc-predℤ pred-sucℤ)
```

## As signed numbers

Considering the isomorphism $X + X \cong 2 * X$, we arrive at an
equivalent representation of the integers: as a pair consisting of a
natural number and its _sign_. We have projections $\bZ \to {+,-}$ and
$\bZ \to \bN$ which correspond to this view: given an integer, we can
determine its sign and its **absolute value**.

```agda
data Sign : Type where
  pos neg : Sign

abs : Int  Nat
abs (pos x)    = x
abs (negsuc x) = suc x

sign : Int  Sign
sign (pos x)    = pos
sign (negsuc x) = neg
```

Conversely, if we have a signed number, we can build an integer. Note
that the `assign`{.Agda} function sends the natural number zero to the
integer zero regardless of what sign is specified.

```agda
assign : Sign  Nat  Int
assign s   zero    = 0
assign pos (suc n) = pos (suc n)
assign neg (suc n) = negsuc n
```

## Algebra

We also mentioned two more characterisations of the integers: as the
[[free group]] on one generator, and as the [[initial ring]]. Therefore,
we expect to find operations of addition, multiplication, and negation
(additive inverse) on the set of integers. They are not that hard to
define.

Addition on integers is defined by cases on the sign. If both numbers
are positive (resp. negative), then we can compute their sum in the
natural numbers. If the numbers have mismatched sign, then the addition
function is actually computing a difference, and we already know how to
compute differences.

```agda
_+ℤ_ : Int  Int  Int
pos x +ℤ pos y       = pos (x + y)
pos x +ℤ negsuc y    = x ℕ- suc y
negsuc x +ℤ pos y    = y ℕ- suc x
negsuc x +ℤ negsuc y = negsuc (suc (x + y))
```

The negation function is defined by a short case bash. Subtraction is
defined as addition against the inverse, rather than as an operation in
its own right.

```agda
negℤ : Int  Int
negℤ (pos zero)    = pos zero
negℤ (pos (suc x)) = negsuc x
negℤ (negsuc x)    = pos (suc x)

_-ℤ_ : Int  Int  Int
x -ℤ y = x +ℤ (negℤ y)
```

The implementation of multiplication uses the decomposition of numbers
into their signs and absolute values: The product $xy$ is defined to be

$$
\operatorname{sign}(x) * \operatorname{sign}(y) * |x| * |y|\text{,}
$$

There are actually three different "multiplication" signs in the formula
above. The first is _sign multiplication_, the second is
`assign`{.Agda}, and the last is natural number multiplication.

```agda
sign× : Sign  Sign  Sign
sign× pos pos = pos
sign× neg neg = pos
sign× pos neg = neg
sign× neg pos = neg

_*ℤ_ : Int  Int  Int
i *ℤ j = assign (sign× (sign i) (sign j)) (abs i * abs j)
```

There are actually alternative definitions of addition and
multiplication: as iterated successor/predecessor, and as iterated
addition, respectively. These alternative representations have worse
_performance_, but they behave in a way that is slightly easier to
reason about. When establishing the algebraic properties of the
integers, we'll prove that these functions are equivalent to the
definitions above, and change between them as appropriate.

```agda
rotℤ : Int  Int  Int
rotℤ (pos zero)       y = y
rotℤ (pos (suc x))    y = sucℤ (rotℤ (pos x) y)
rotℤ (negsuc zero)    y = predℤ y
rotℤ (negsuc (suc x)) y = predℤ (rotℤ (negsuc x) y)

dotℤ : Int  Int  Int
dotℤ posz             y = posz
dotℤ (possuc x)       y = y +ℤ (dotℤ (pos x) y)
dotℤ (negsuc zero)    y = negℤ y
dotℤ (negsuc (suc x)) y = negℤ y +ℤ (dotℤ (negsuc x) y)
```

## Additional operations

It is also straightforward to define maximum and minimum operations
for integers:

```agda
maxℤ : Int  Int  Int
maxℤ (pos x)    (pos y)    = pos (max x y)
maxℤ (pos x)    (negsuc _) = pos x
maxℤ (negsuc _) (pos y)    = pos y
maxℤ (negsuc x) (negsuc y) = negsuc (min x y)

minℤ : Int  Int  Int
minℤ (pos x)    (pos y)    = pos (min x y)
minℤ (pos _)    (negsuc y) = negsuc y
minℤ (negsuc x) (pos _)    = negsuc x
minℤ (negsuc x) (negsuc y) = negsuc (max x y)
```