added polynomials

This commit is contained in:
Louis Heredero 2024-06-25 18:50:29 +02:00
parent cfda844ebc
commit c4bb53ccf7
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
5 changed files with 268 additions and 0 deletions

Binary file not shown.

BIN
gallery/example4.pdf Normal file

Binary file not shown.

34
gallery/example4.typ Normal file
View File

@ -0,0 +1,34 @@
#import "/src/lib.typ": *
#let p = poly.poly(0,1,2,3,4)
#let q = poly.poly(5,6,7)
#let a = poly.add(p, q)
#let b = poly.sub(p, q)
$
p = #poly.display(p) quad q = #poly.display(q)\
p + q = #poly.display(a)\
p - q = #poly.display(b)\
$
#let P = poly.poly(7, -3, -3, 1, 1)
#let Q = poly.poly(-2, 1, 1)
$
P = #poly.display(P) quad Q = #poly.display(Q)\
P / Q = #poly.display(P) / #poly.display(Q)
$
#let div = poly.div(P, Q)
#align(center, grid(
columns: 2,
align: left,
column-gutter: 2em,
row-gutter: 1em,
[dividend: #poly.display(div.dividend)],
grid.cell(rowspan: 4, (div.display)()),
[divisor: #poly.display(div.divisor)],
[quotient: #poly.display(div.quotient)],
[rest: #poly.display(div.rest)],
))

View File

@ -1,4 +1,5 @@
#import "mat.typ"
#import "poly.typ"
#import "vec.typ"
#import "gauss.typ"

233
src/poly.typ Normal file
View File

@ -0,0 +1,233 @@
#let is-poly(poly) = {
if type(poly) != dictionary {return false}
if poly.at("type", default: none) != "polynomial" {return false}
return true
}
#let _check(poly) = {
if not is-poly(poly) {
panic("Argument is not a polynomial")
}
}
#let poly(..args, trim-zeros: true) = {
let coefs = args.pos()
if trim-zeros {
let last-i = coefs.rev().position(c => c != 0)
if last-i == none {
last-i = -1
}
coefs = coefs.slice(0, calc.min(coefs.len(), coefs.len() - last-i))
}
if coefs.len() == 0 {
coefs.push(0)
}
return (
type: "polynomial",
coefs: coefs,
deg: coefs.len() - 1
)
}
#let copy(original) = {
_check(original)
return poly(..original.coefs)
}
#let display(poly) = {
_check(poly)
let fractions = (2, 3, 4, 5, 6)
let beautify-frac(value) = {
if calc.round(value) == value {
return str(value)
}
for den in fractions {
for num in range(1, 2 * den) {
if value == num / den {
return str(num) + "/" + str(den)
}
}
}
return str(value)
}
let res = ""
for (i, coef) in poly.coefs.rev().enumerate() {
if coef == 0 and poly.deg > 0 {
continue
}
if i != 0 {
res += " "
if coef < 0 { res += "-" }
else { res += "+" }
} else if coef < 0 {
res += "-"
}
if calc.abs(coef) != 1 or poly.deg - i == 0 {
res += str(beautify-frac(calc.abs(coef)))
}
if poly.deg - i > 0 {
res += "x"
}
if poly.deg - i > 1 {
res += "^" + str(poly.deg - i)
}
}
return eval("$" + res + "$")
}
#let pad(poly1, deg) = {
let coefs = poly1.coefs
coefs += (0,) * calc.max(0, (deg - poly1.deg))
return poly(..coefs, trim-zeros: false)
}
#let shift(poly1, deg) = {
let coefs = (0,) * calc.max(0, (deg - poly1.deg))
coefs += poly1.coefs
return poly(..coefs)
}
#let add(poly1, poly2) = {
let deg = calc.max(poly1.deg, poly2.deg)
let poly1 = pad(poly1, deg)
let poly2 = pad(poly2, deg)
let coefs = poly1.coefs.zip(poly2.coefs).map(p => p.sum())
return poly(..coefs)
}
#let sub(poly1, poly2) = {
let deg = calc.max(poly1.deg, poly2.deg)
let poly1 = pad(poly1, deg)
let poly2 = pad(poly2, deg)
let coefs = poly1.coefs.zip(poly2.coefs).map(p => p.at(0) - p.at(1))
return poly(..coefs)
}
#let mul(poly1, f) = {
let coefs = poly1.coefs.map(c => c * f)
return poly(..coefs)
}
#let to-cells(poly) = {
let cells = ()
let first = true
for (i, coef) in poly.coefs.rev().enumerate() {
if coef == 0 and poly.deg > 0 {
cells.push("")
continue
}
let cell = ""
if i != 0 {
if coef < 0 { cell += "-" }
else if not first { cell += "+" }
} else if coef < 0 {
cell += "-"
}
if calc.abs(coef) != 1 or poly.deg - i == 0 {
cell += str(calc.abs(coef))
}
if poly.deg - i > 0 {
cell += "x"
}
if poly.deg - i > 1 {
cell += "^" + str(poly.deg - i)
}
cells.push(eval("$" + cell + "$"))
first = false
}
if poly.coefs.position(c => c != 0) == none {
cells.last() = "0"
}
return cells
}
#let div(
poly1,
poly2,
max-steps: 10
) = {
let P = poly1
let Q = poly2
let p = P
let rows = ()
let steps = ()
let D = poly()
let count = 0
while p.deg >= Q.deg and p.coefs.position(c => c != 0) != none {
let f = p.coefs.at(p.deg) / Q.coefs.at(Q.deg)
let sub = shift(mul(Q, -f), p.deg)
let rem = add(p, sub)
let d = shift(poly(f), p.deg - Q.deg)
steps.push((
p: p,
sub: sub,
rem: rem,
f: f,
d: d
))
D = add(D, d)
p = rem
if count >= max-steps {
panic("Exceeded maximum number of steps")
break
}
count += 1
}
let make-table(
vpad: 5pt,
hpad: 5pt,
stroke: black + 1pt,
debug-grid: false
) = {
let cells = ()
cells += to-cells(P)
cells.push(table.vline(stroke: stroke))
cells.push(display(Q))
cells.push(table.hline(start: P.deg + 1, stroke: stroke))
for (i, step) in steps.enumerate() {
cells += to-cells(pad(step.sub, P.deg))
if i == 0 {
cells.push(display(D))
} else {
cells.push("")
}
cells.push(table.hline(start: P.deg - step.sub.deg, end: P.deg - step.sub.deg + Q.deg + 1, stroke: stroke))
cells += to-cells(pad(step.rem, P.deg))
cells.push("")
}
table(
columns: P.deg + 2,
stroke: if debug-grid {gray + 1pt} else {none},
fill: none,
align: (x, _) => if x == P.deg + 1 {left} else {right},
inset: (left: hpad, right: hpad, top: vpad, bottom: vpad),
..cells
)
}
return (
dividend: P,
divisor: Q,
quotient: D,
rest: p,
steps: steps,
display: make-table
)
}