added logic tables
This commit is contained in:
parent
c33c055b29
commit
b93db17806
BIN
gallery/example5.pdf
Normal file
BIN
gallery/example5.pdf
Normal file
Binary file not shown.
27
gallery/example5.typ
Normal file
27
gallery/example5.typ
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#import "/src/logic.typ": *
|
||||||
|
#let F = $((not p -> q) or r) -> ((p and not r) or not q)$
|
||||||
|
#let F = _implies(
|
||||||
|
_or(
|
||||||
|
_implies(
|
||||||
|
_not("p"),
|
||||||
|
"q"
|
||||||
|
),
|
||||||
|
"r"
|
||||||
|
),
|
||||||
|
_or(
|
||||||
|
_and(
|
||||||
|
"p",
|
||||||
|
_not("r")
|
||||||
|
),
|
||||||
|
_not("q")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
#display(F)
|
||||||
|
#get-atoms(F)
|
||||||
|
|
||||||
|
#get-components(F)
|
||||||
|
|
||||||
|
#{
|
||||||
|
set text(size: 0.8em)
|
||||||
|
truth-table(F)
|
||||||
|
}
|
165
src/logic.typ
Normal file
165
src/logic.typ
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#let _and(a, b) = (
|
||||||
|
type: "and",
|
||||||
|
a: a,
|
||||||
|
b: b
|
||||||
|
)
|
||||||
|
#let _or(a, b) = (
|
||||||
|
type: "or",
|
||||||
|
a: a,
|
||||||
|
b: b
|
||||||
|
)
|
||||||
|
#let _implies(a, b) = (
|
||||||
|
type: "implies",
|
||||||
|
a: a,
|
||||||
|
b: b
|
||||||
|
)
|
||||||
|
#let _not(a) = (
|
||||||
|
type: "not",
|
||||||
|
a: a
|
||||||
|
)
|
||||||
|
|
||||||
|
#let display(formula, first: true) = {
|
||||||
|
let display = display.with(first: false)
|
||||||
|
if type(formula) == str {
|
||||||
|
return formula
|
||||||
|
}
|
||||||
|
if type(formula) != dictionary {
|
||||||
|
panic("Invalid type")
|
||||||
|
}
|
||||||
|
let res = none
|
||||||
|
if formula.type == "and" {
|
||||||
|
res = $#display(formula.a) and #display(formula.b)$
|
||||||
|
} else if formula.type == "or" {
|
||||||
|
res = $#display(formula.a) or #display(formula.b)$
|
||||||
|
} else if formula.type == "implies" {
|
||||||
|
res = $#display(formula.a) -> #display(formula.b)$
|
||||||
|
} else if formula.type == "not" {
|
||||||
|
res = $not #display(formula.a)$
|
||||||
|
} else {
|
||||||
|
panic("Invalid type")
|
||||||
|
}
|
||||||
|
if not first and formula.type != "not" {
|
||||||
|
res = $(#res)$
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
#let _walk(formula, callback) = {
|
||||||
|
let result = ()
|
||||||
|
if type(formula) == str {
|
||||||
|
result += callback(formula, result)
|
||||||
|
} else if type(formula) == dictionary {
|
||||||
|
result += callback(formula, result)
|
||||||
|
if formula.type in ("and", "or", "implies") {
|
||||||
|
result += _walk(formula.a, callback)
|
||||||
|
result += _walk(formula.b, callback)
|
||||||
|
} else if formula.type == "not" {
|
||||||
|
result += _walk(formula.a, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
#let evaluate(formula, atoms-values) = {
|
||||||
|
if type(formula) == str {
|
||||||
|
return atoms-values.at(formula)
|
||||||
|
}
|
||||||
|
if type(formula) != dictionary {
|
||||||
|
panic("Invalid type")
|
||||||
|
}
|
||||||
|
if formula.type == "not" {
|
||||||
|
return 1 - evaluate(formula.a, atoms-values)
|
||||||
|
}
|
||||||
|
if not formula.type in ("and", "or", "implies") {
|
||||||
|
panic("Invalid type")
|
||||||
|
}
|
||||||
|
let a = evaluate(formula.a, atoms-values)
|
||||||
|
let b = evaluate(formula.b, atoms-values)
|
||||||
|
let cond = false
|
||||||
|
if formula.type == "and" {
|
||||||
|
cond = (a == 1 and b == 1)
|
||||||
|
} else if formula.type == "or" {
|
||||||
|
cond = (a == 1 or b == 1)
|
||||||
|
} else if formula.type == "implies" {
|
||||||
|
cond = (a == 0 or b == 1)
|
||||||
|
}
|
||||||
|
return if cond {1} else {0}
|
||||||
|
}
|
||||||
|
|
||||||
|
#let get-atoms(formula) = {
|
||||||
|
return _walk(formula, (a, res) => {
|
||||||
|
if type(a) == str {
|
||||||
|
res.push(a)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}).dedup()
|
||||||
|
}
|
||||||
|
|
||||||
|
#let get-components(formula) = {
|
||||||
|
return _walk(formula, (a, res) => {
|
||||||
|
res.push(a)
|
||||||
|
return res
|
||||||
|
}).dedup()
|
||||||
|
}
|
||||||
|
|
||||||
|
#let get-level(formula) = {
|
||||||
|
if type(formula) == str {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if type(formula) != dictionary {
|
||||||
|
panic("Invalid type")
|
||||||
|
}
|
||||||
|
if formula.type in ("and", "or", "implies") {
|
||||||
|
return calc.max(
|
||||||
|
get-level(formula.a),
|
||||||
|
get-level(formula.b)
|
||||||
|
) + 1
|
||||||
|
}
|
||||||
|
if formula.type == "not" {
|
||||||
|
return get-level(formula.a) + 1
|
||||||
|
}
|
||||||
|
panic("Invalid type")
|
||||||
|
}
|
||||||
|
|
||||||
|
#let truth-table(formula) = {
|
||||||
|
let atoms = get-atoms(formula).sorted()
|
||||||
|
let comps = get-components(formula)
|
||||||
|
let comps-lvls = comps.map(c => (c, get-level(c)))
|
||||||
|
let sorted = comps-lvls.sorted(key: cl => cl.last())
|
||||||
|
|
||||||
|
let cells = ()
|
||||||
|
|
||||||
|
let cur-lvl = 0
|
||||||
|
for (i, (comp, lvl)) in sorted.enumerate() {
|
||||||
|
if lvl != cur-lvl {
|
||||||
|
cells.push(table.vline())
|
||||||
|
} else if i != 0 {
|
||||||
|
cells.push(table.vline(stroke: (dash: "dashed")))
|
||||||
|
}
|
||||||
|
cur-lvl = lvl
|
||||||
|
cells.push(display(comp))
|
||||||
|
}
|
||||||
|
cells.push(table.hline())
|
||||||
|
for i in range(calc.pow(2, atoms.len())) {
|
||||||
|
if calc.rem(i, 4) == 0 and i != 0 {
|
||||||
|
cells.push(table.hline())
|
||||||
|
}
|
||||||
|
let atoms-values = (:)
|
||||||
|
for (j, a) in atoms.enumerate() {
|
||||||
|
let bit = i.bit-rshift(atoms.len() - j - 1).bit-and(1)
|
||||||
|
atoms-values.insert(a, bit)
|
||||||
|
}
|
||||||
|
for (comp, lvl) in sorted {
|
||||||
|
let value = evaluate(comp, atoms-values)
|
||||||
|
cells.push($#value$)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table(
|
||||||
|
columns: sorted.len(),
|
||||||
|
stroke: none,
|
||||||
|
align: center + horizon,
|
||||||
|
inset: (left: 0.5em, right: 0.5em, top: 0.4em, bottom: 0.4em),
|
||||||
|
..cells
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user