Unification Examples

View Source
Mix.install([{:hol, "1.0.1"}])

Setup

import HOL.Data
import HOL.Terms
import HOL.ChurchNumerals
import HOL.Unification
import PrettyPrint

LoggerHelper.set_logger_warning()

Here we setup the types we need to construct the following examples

type_i = mk_type(:i)
type_ii = mk_type(type_i, [type_i])
type_ii_ii = mk_type(type_ii, [type_ii])
type_iii = mk_type(type_i, [type_i, type_i])

Example: x * 5 = 30

t_x = mk_free_var_term("x", type_ii_ii)

x_times_5 = mult_term() |> mk_appl_term(t_x) |> mk_appl_term(mk_num(5))
input = {x_times_5, mk_num(30)}

result = unify(input)
pp_res(result, true)

This finds one substitution that replaces x with the church numeral 6

x = 6: x <- λ 2 1. 2 (2 (2 (2 (2 (2 1)))))

Example: x * 10 = 1000

t_x = mk_free_var_term("x", type_ii_ii)

x_times_10 = mult_term() |> mk_appl_term(t_x) |> mk_appl_term(mk_num(10))

input = [
  {x_times_10, mk_num(1000)}
]

result = unify(input, true, 1000)
pp_res(result, true)

This finds one substitution that replaces x with the church numeral 100

x = 100: x <- (2 1. 2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 1) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

Example: x * y = 4

t_x = mk_free_var_term("x", type_ii_ii)
t_y = mk_free_var_term("y", type_ii_ii)

x_times_y = mult_term() |> mk_appl_term(t_x) |> mk_appl_term(t_y)
input = {x_times_y, mk_num(4)}

result = unify(input, true, 40)
pp_res(result, true)

# 1*4=4 & 4*1=4 & 2*2=4

This finds three solutions:

y = 1, x = 4: y <- λ 2 1. 2 1 | x <- λ 2 1. 2 (2 (2 (2 1)))

y = 2, x = 2: y <- λ 2 1. 2 (2 1) | x <- λ 2 1. 2 (2 1)

y = 4, x = 1: y <- λ 2 1. 2 (2 (2 (2 1))) | x <- λ 2 1. 2 1

Example: xaa = faa

t_x = mk_free_var_term("x", type_iii)
t_a = mk_const_term("a", type_i)
t_f = mk_const_term("f", type_iii)

xaa = mk_appl_term(mk_appl_term(t_x, t_a), t_a)
faa = mk_appl_term(mk_appl_term(t_f, t_a), t_a)

input = {xaa, faa}

result = unify(input)
pp_res(result)

Finds nine possible substitutions for unification:

x <- λ 2 1. f 1 1

x <- λ 2 1. f 1 2

x <- λ 2 1. f 1 a

x <- λ 2 1. f 2 1

x <- λ 2 1. f 2 2

x <- λ 2 1. f 2 a

x <- λ 2 1. f a 1

x <- λ 2 1. f a 2

x <- λ 2 1. f a a

Example: x(fa) = f(xa)

t_x = mk_free_var_term("x", type_ii)
t_f = mk_const_term("f", type_ii)
t_a = mk_const_term("a", type_i)

xfa = mk_appl_term(t_x, mk_appl_term(t_f, t_a))
fxa = mk_appl_term(t_f, mk_appl_term(t_x, t_a))

depth = 5
input = {xfa, fxa}

result = unify(input, true, depth)
pp_res(result)

This finds four solutions:

x <- λ 1. 1

x <- λ 1. f 1

x <- λ 1. f (f 1)

x <- λ 1. f (f (f 1))

However the maximum search depth was also reached twice. This means that it might not have found all solutions. Try changing the depth value and see what other solutions can be found!

Example: Multiple Equations

  • xy+z=21
  • x+y+z=10
  • xz+y=9
t_x = mk_free_var_term("x", type_ii_ii)
t_y = mk_free_var_term("y", type_ii_ii)
t_z = mk_free_var_term("z", type_ii_ii)

input = [
  {plus(mult(t_x, t_y), t_z), mk_num(21)},
  {plus(plus(t_x, t_y), t_z), mk_num(10)},
  {plus(mult(t_x, t_z), t_y), mk_num(9)}
]

depth = 50
result = unify(input, true, depth)
pp_res(result, true)

Two Solutions are found here:

z = 1, y = 4, x = 5: z <- λ 2 1. 2 1 | y <- λ 2 1. 2 (2 (2 (2 1))) | x <- λ 2 1. 2 (2 (2 (2 (2 1))))

z = 1, y = 5, x = 4: z <- λ 2 1. 2 1 | y <- λ 2 1. 2 (2 (2 (2 (2 1)))) | x <- λ 2 1. 2 (2 (2 (2 1)))

Once again the maximum search depth was reached multiple times. However increasing the search depth will not yield more solutions here. Unification doesn't always terminate even when no more solutions can be found!

Example: x = zc

t_x = mk_free_var_term("x", type_i)
t_z = mk_free_var_term("z", type_ii)
t_c = mk_const_term("c", type_i)
appl_zc = mk_appl_term(t_z, t_c)

input = {t_x, appl_zc}
result = unify(input)
pp_res(result)

Here the only given result is the tuple {x,(z c)} on the flexlist. The tuples on the flexlist are not resolved, since this algorithm only does pre-unification. Many (often infinite) substitutions can be created from these tuples. This functionality is not currently present in this module.