added polynomials
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								gallery/example4.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gallery/example4.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										34
									
								
								gallery/example4.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								gallery/example4.typ
									
									
									
									
									
										Normal 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)], | ||||||
|  | )) | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| #import "mat.typ" | #import "mat.typ" | ||||||
|  | #import "poly.typ" | ||||||
| #import "vec.typ" | #import "vec.typ" | ||||||
|  |  | ||||||
| #import "gauss.typ" | #import "gauss.typ" | ||||||
							
								
								
									
										233
									
								
								src/poly.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								src/poly.typ
									
									
									
									
									
										Normal 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 | ||||||
|  |   ) | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user