Predicates

Posted on 2018-01-07 by nbloomf
Tags: arithmetic-made-difficult, literate-haskell

This page is part of a series on Arithmetic Made Difficult.

This post is literate Haskell; you can load the source into GHCi and play along.


{-# LANGUAGE NoImplicitPrelude #-}
module Predicates (
  pnot, pand, por, ptrue, pfalse, _test_predicate, main_predicate
) where

import Testing
import Booleans
import Not
import And
import Or

In the last post we defined the algebra of boolean values, true and false. Today we’ll look at predicates – functions from some set \(A\) to \(\bool\). It turns out the algebra on \(\bool\) can be lifted to predicates, and is useful enough to collect some definitions and properties in one place.

Let \(A\) be a set. A predicate on \(A\) is just a function \(p : A \rightarrow \bool\). We define two special predicates, \(\ptrue = \const(\btrue)\) and \(\pfalse = \const(\bfalse)\).

In Haskell:

First, the basic logic operators lift.

Let \(A\) be a set. We define \(\pnot : \bool^A \rightarrow \bool^A\) by \[\pnot(p)(a) = \bnot(p(a)).\]

In Haskell:

\(\pnot\) is an involution.

Let \(A\) be a set. For all \(p : A \rightarrow \bool\), we have \[\pnot(\pnot(p)) = p.\]

Let \(a \in A\). Then we have \[\begin{eqnarray*} & & \pnot(\pnot(p))(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bnot(\pnot(p)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bnot(\bnot(p(a))) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-involution} = & p(a) \end{eqnarray*}\] as needed.

Special cases.

Let \(A\) be a set. Then we have the following.

  1. \(\pnot(\ptrue) = \pfalse\).
  2. \(\pnot(\pfalse) = \ptrue\).
  3. \(\compose(\bnot)(\ptrue) = \pfalse\).
  4. \(\compose(\bnot)(\pfalse) = \ptrue\).
  1. If \(a \in A\), we have \[\begin{eqnarray*} & & \pnot(\ptrue)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bnot(\ptrue(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-ptrue} = & \bnot(\const(\btrue)(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \bnot(\btrue) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-true} = & \bfalse \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \const(\bfalse)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pfalse} = & \pfalse(a) \end{eqnarray*}\] as needed.
  2. If \(a \in A\), we have \[\begin{eqnarray*} & & \pnot(\pfalse)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bnot(\pfalse(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pfalse} = & \bnot(\const(\bfalse)(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \bnot(\bfalse) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-false} = & \btrue \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \const(\btrue)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-ptrue} = & \ptrue(a) \end{eqnarray*}\] as needed.
  3. If \(a \in A\), we have \[\begin{eqnarray*} & & \compose(\bnot)(\ptrue)(a) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-compose} = & \bnot(\ptrue(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-ptrue} = & \bnot(\const(\btrue)(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \bnot(\btrue) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-true} = & \bfalse \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \const(\bfalse)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pfalse} = & \pfalse(a) \end{eqnarray*}\] as needed.
  4. If \(a \in A\), we have \[\begin{eqnarray*} & & \compose(\bnot)(\pfalse)(a) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-compose} = & \bnot(\pfalse(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pfalse} = & \bnot(\const(\bfalse)(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \bnot(\bfalse) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-false} = & \btrue \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \const(\btrue)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-ptrue} = & \ptrue(a) \end{eqnarray*}\]

Next, \(\pand\).

Let \(A\) be a set. We define \(\pand : \bool^A \times \bool^A \rightarrow \bool^A\) by \[\pand(p,q)(a) = \band(p(a),q(a)).\]

In Haskell:

The usual properties of \(\band\) lift to \(\pand\).

Let \(A\) be a set. The following hold for all p,q,r ^A$.

  1. \(\pand(\pfalse,p) = \pand(p,\pfalse) = \pfalse\).
  2. \(\pand(\ptrue,p) = \pand(p,\ptrue) = p\).
  3. \(\pand(p,p) = p\).
  4. \(\pand(p,q) = \pand(q,p)\).
  5. \(\pand(\pand(p,q),r) = \pand(p,\pand(q,r))\).
  1. For all \(a \in A\) we have \[\begin{eqnarray*} & & \pand(\pfalse,p)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(\pfalse(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pfalse} = & \band(\const(\bfalse)(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \band(\bfalse,p(a)) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-false-left} = & \bfalse \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \const(\bfalse)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pfalse} = & \pfalse(a) \end{eqnarray*}\] as needed; similarly for the other equality.
  2. For all \(a \in A\), we have \[\begin{eqnarray*} & & \pand(\ptrue,p)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(\ptrue(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-ptrue} = & \band(\const(\btrue)(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \band(\btrue,p(a)) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-true-left} = & p(a) \end{eqnarray*}\] as needed.
  3. For all \(a \in A\), we have \[\begin{eqnarray*} & & \pand(p,p)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(p(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-idempotent} = & p(a) \end{eqnarray*}\] as needed.
  4. For all \(a \in A\), we have \[\begin{eqnarray*} & & \pand(p,q)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(p(a),q(a)) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-commutative} = & \band(q(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \pand(q,p)(a) \end{eqnarray*}\] as needed.
  5. For all \(a \in A\), we have \[\begin{eqnarray*} & & \pand(\pand(p,q),r)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(\pand(p,q)(a),r(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(\band(p(a),q(a)),r(a)) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-associative} = & \band(p(a),\band(q(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(p(a),\pand(q,r)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \pand(p,\pand(q,r))(a) \end{eqnarray*}\] as needed.

Then \(\por\).

Let \(A\) be a set. We define \(\por : \bool^A \times \bool^A \rightarrow \bool^A\) by \[\por(p,q)(a) = \bor(p(a),q(a)).\]

In Haskell:

The usual properties of \(\bor\) lift to \(\por\).

Let \(A\) be a set. The following hold for all \(p,q,r \in \bool^A\).

  1. \(\por(\ptrue,p) = \por(p,\ptrue) = \ptrue\).
  2. \(\por(\pfalse,p) = \por(p,\pfalse) = p\).
  3. \(\por(p,p) = p\).
  4. \(\por(p,q) = \por(q,p)\).
  5. \(\por(\por(p,q),r) = \por(p,\por(q,r))\).
  1. For all \(a \in A\), we have \[\begin{eqnarray*} & & \por(\ptrue,p)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(\ptrue(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-ptrue} = & \bor(\const(\btrue)(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \bor(\btrue,p(a)) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-or-true-left} = & \btrue \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \const(\btrue)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-ptrue} = & \ptrue(a) \end{eqnarray*}\] as needed; the other equality is similar.
  2. For all \(a \in A\), we have \[\begin{eqnarray*} & & \por(\pfalse,p)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(\pfalse(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pfalse} = & \bor(\const(\bfalse)(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Functions.html#def-const} = & \bor(\bfalse,p(a)) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-or-false-left} = & p(a) \end{eqnarray*}\] as needed; the other equality is similar.
  3. For all \(a \in A\), we have \[\begin{eqnarray*} & & \por(p,p)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(p(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-or-idempotent} = & p(a) \end{eqnarray*}\] as needed.
  4. For all \(a \in A\), we have \[\begin{eqnarray*} & & \por(p,q)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(p(a),q(a)) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-or-commutative} = & \bor(q(a),p(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \por(q,p)(a) \end{eqnarray*}\] as needed.
  5. For all \(a \in A\), we have \[\begin{eqnarray*} & & \por(\por(p,q),r)(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(\por(p,q)(a),r(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(\bor(p(a),q(a)),r(a)) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-or-associative} = & \bor(p(a),\bor(q(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(p(a),\por(q,r)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \por(p,\por(q,r))(a) \end{eqnarray*}\] as needed.

And \(\pnot\), \(\pand\), and \(\por\) interact.

Let \(A\) be a set. The following hold for all \(p,q,r \in \bool^A\).

  1. \(\pnot(\pand(p,q)) = \por(\pnot(p),\pnot(q))\).
  2. \(\pnot(\por(p,q)) = \pand(\pnot(p),\pnot(q))\).
  3. \(\pand(p,\por(q,r)) = \por(\pand(p,q),\pand(p,r))\).
  4. \(\bor(p,\pand(q,r)) = \pand(\por(p,q),\por(p,r))\).
  1. For all \(a \in A\), we have \[\begin{eqnarray*} & & \pnot(\pand(p,q))(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bnot(\pand(p,q)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \bnot(\band(p(a),q(a))) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-demorgan-not-and} = & \bor(\bnot(p(a)),\bnot(q(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bor(\pnot(p)(a),\bnot(q(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bor(\pnot(p)(a),\pnot(q)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \por(\pnot(p),\pnot(q))(a) \end{eqnarray*}\] as needed.
  2. For all \(a \in A\), we have \[\begin{eqnarray*} & & \pnot(\por(p,q))(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \bnot(\por(p,q)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bnot(\bor(p(a),q(a))) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-demorgan-not-or} = & \band(\bnot(p(a)),\bnot(q(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \band(\pnot(p)(a),\bnot(q(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pnot} = & \band(\pnot(p)(a),\pnot(q)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \pand(\pnot(p),\pnot(q))(a) \end{eqnarray*}\] as needed.
  3. For all \(a \in A\), we have \[\begin{eqnarray*} & & \pand(p,\por(q,r))(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \band(p(a),\por(q,r)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \band(p(a),\bor(q(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-and-or-distribute} = & \bor(\band(p(a),q(a)),\band(p(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \bor(\pand(p,q)(a),\band(p(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \bor(\pand(p,q)(a),\pand(p,r)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \por(\pand(p,q),\pand(p,r))(a) \end{eqnarray*}\] as needed.
  4. For all \(a \in A\), we have \[\begin{eqnarray*} & & \por(p,\pand(q,r))(a) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \bor(p(a),\pand(q,r)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \bor(p(a),\band(q(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Or.html#thm-or-and-distribute} = & \band(\bor(p(a),q(a)),\bor(p(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \band(\por(p,q)(a),\bor(p(a),r(a))) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-por} = & \band(\por(p,q)(a),\por(p,r)(a)) \\ & \href{/posts/arithmetic-made-difficult/Predicates.html#def-pand} = & \pand(\por(p,q),\por(p,r))(a) \end{eqnarray*}\] as needed.

Implication lifts to predicates.

Let \(A\) be a set. We define \(\pimpl : \bool^A \times \bool^A \rightarrow \bool^A\) by \[\pimpl(p,q)(a) = \bimpl(p(a),q(a)).\]

Testing

Suite:

_test_predicate ::
  ( Equal a, Arbitrary a, CoArbitrary a, Show a, TypeName a
  , TypeName b, Boolean b, Equal b, Arbitrary b
  ) => a -> b -> Int -> Int -> IO ()
_test_predicate x p size cases = do
  testLabel1 "predicate" x

  let args = testArgs size cases

  runTest args (_test_pnot_involutive x p)
  runTest args (_test_pnot_ptrue x p)
  runTest args (_test_pnot_pfalse x p)
  runTest args (_test_not_ptrue x p)
  runTest args (_test_not_pfalse x p)

  runTest args (_test_pand_pfalse x)
  runTest args (_test_pand_ptrue x)
  runTest args (_test_pand_idempotent x)
  runTest args (_test_pand_commutative x)
  runTest args (_test_pand_associative x)

  runTest args (_test_por_ptrue x p)
  runTest args (_test_por_pfalse x p)
  runTest args (_test_por_idempotent x p)
  runTest args (_test_por_commutative x)
  runTest args (_test_por_associative x)

  runTest args (_test_pnot_pand x)
  runTest args (_test_pnot_por x)
  runTest args (_test_pand_por x)
  runTest args (_test_por_pand x)

Main:

main_predicate :: IO ()
main_predicate = _test_predicate (true :: Bool) (true :: Bool) 20 100