12 Note that you probably want to use reduceratfunc liberally. As is,
13 this won't even simplify "x^2 / (x - 1)" + "-1 / (x - 1)" for you.
14 This is because our groebner implementation is so damn slow.
21 reduced : bool /* For saving work */
23 impl disposable ratfunc#
24 impl division_struct ratfunc#
25 impl group_struct ratfunc#
26 impl field_struct ratfunc#
27 impl ring_struct ratfunc#
28 impl std.equatable ratfunc#
29 impl t.dupable ratfunc#
31 const ratfuncfrompoly : (p : polynomial# -> ratfunc#)
32 const ratfuncfromQ : (Q : Q# -> ratfunc#)
33 const ratfuncfromS : (n : byte[:], d : byte[:] -> std.result(ratfunc#, byte[:]))
34 const reduceratfunc : (rf : ratfunc# -> void)
36 const polynomialfromratfunc : (rf : ratfunc# -> std.option(polynomial#))
42 std.fmtinstall(std.typeof(rf), ratfuncfmt)
45 const ratfuncfmt = {sb, ap, opts
46 var rf : ratfunc# = std.vanext(ap)
50 var den_is_one = rf.den.terms.len == 1 && rf.den.terms[0].vars.len == 0 && std.eq(rf.den.terms[0].coeff, one)
52 if rf.num.terms.len == 0
55 elif rf.num.terms.len == 1 || den_is_one
56 std.sbfmt(sb, "{}", rf.num)
58 std.sbfmt(sb, "({})", rf.num)
61 if rf.den.terms.len == 1
62 if rf.den.terms[0].vars.len == 0
63 if std.eq(rf.den.terms[0].coeff, one)
66 if std.bigeqi(rf.den.terms[0].coeff.q, 1)
67 std.sbfmt(sb, " / {}", rf.den.terms[0].coeff.p)
72 std.sbfmt(sb, " / ({})", rf.den)
75 impl disposable ratfunc# =
76 __dispose__ = {x : ratfunc#
79 std.bytefree((x : byte#), sizeof(ratfunc))
83 impl division_struct ratfunc# =
85 if b.num.terms.len == 0
88 var fake_bi : ratfunc = [ .num = b.den, .den = b.num ]
90 -> `std.Some rmul(a, &fake_bi)
94 impl group_struct ratfunc# =
96 var num : polynomial# = gid()
97 var den : polynomial# = rid()
98 var base : ratfunc = [ .num = num, .den = den, .reduced = true ]
103 var summand : polynomial# = rmul(b.num, a.den)
105 rmul_ip(a.den, b.den)
106 rmul_ip(a.num, b.den)
107 gadd_ip(a.num, summand)
132 impl field_struct ratfunc# =
134 if a.num.terms.len == 0
138 var base = [ .num = t.dup(a.den), .den = t.dup(a.num), .reduced = a.reduced ]
139 reduce_numeric_fractions(&base)
140 -> `std.Some std.mk(base)
144 impl ring_struct ratfunc# =
146 var num : polynomial# = rid()
147 var den : polynomial# = rid()
148 var base : ratfunc = [ .num = num, .den = den ]
153 rmul_ip(a.num, b.num)
154 rmul_ip(a.den, b.den)
165 impl std.equatable ratfunc# =
167 var lhs : polynomial# = rmul(a.num, b.den)
169 var rhs : polynomial# = rmul(b.num, a.den)
176 impl t.dupable ratfunc# =
178 var dnum = t.dup(a.num)
179 var dden = t.dup(a.den)
180 var base = [ .num = dnum, .den = dden, .reduced = a.reduced ]
185 const ratfuncfrompoly = {p : polynomial#
188 var base = [ .num = num, .den = den, .reduced = true ]
189 reduce_numeric_fractions(&base)
190 reduce_variable_fractions(&base)
194 const ratfuncfromQ = {q : Q#
195 var num : polynomial# = polynomialfromQ(q)
196 var den : polynomial# = rid()
197 var base : ratfunc = [ .num = num, .den = den ]
201 const ratfuncfromS = {n : byte[:], d : byte[:]
202 match polynomialfromS(n)
204 auto (e : t.doomed_str)
205 -> `std.Err std.fmt("cannot parse numerator: {}", e)
207 match polynomialfromS(d)
209 auto (e : t.doomed_str)
210 -> `std.Err std.fmt("cannot parse denominator: {}", e)
212 if den.terms.len == 0
213 -> `std.Err std.fmt("division by zero")
215 var rfbase = [ .num = num, .den = den, .reduced = false ]
216 reduceratfunc(&rfbase)
217 -> `std.Ok std.mk(rfbase)
222 const reduceratfunc = {x
224 LCM takes a really fucking long time, so be a little clever
225 about not doing work.
231 if x.num.terms.len == 0
237 reduce_numeric_fractions(x)
238 reduce_variable_fractions(x)
241 This is polynomial lcm, so it always returns something monic.
242 This may screw up the coefficients again.
244 var d = lcm(x.num, x.den)
245 var leading_coeff = x.num.terms[x.num.terms.len - 1].coeff
246 for var j = 0; j < d.terms.len; ++j
247 rmul_ip(d.terms[j].coeff, leading_coeff)
250 match div_maybe(d, x.num)
253 match div_maybe(d, x.den)
268 const reduce_numeric_fractions = {x
270 Collect (integer) denominators of numerator and denominator,
271 multiply through, hope to cancel some things.
273 var one = std.mkbigint(1)
274 for var j = 0; j < x.num.terms.len; ++j
275 if !std.bigeqi(x.num.terms[j].coeff.q, 1)
276 var p = std.bigdup(x.num.terms[j].coeff.q)
277 var factor : Q = [ .p = p, .q = one ]
278 multiply_by_oneQ(x, &factor)
282 for var j = 0; j < x.den.terms.len; ++j
283 if !std.bigeqi(x.den.terms[j].coeff.q, 1)
284 var p = std.bigdup(x.den.terms[j].coeff.q)
285 var factor : Q = [ .p = p, .q = one ]
286 multiply_by_oneQ(x, &factor)
291 /* Maybe we've got (-ax + b) / (-cx + d) */
292 if x.num.terms.len > 0 && x.num.terms[0].coeff.p.sign < 0
293 var mone = std.mkbigint(-1)
294 var factor : Q = [ .p = mone, .q = one ]
295 multiply_by_oneQ(x, &factor)
299 /* Maybe we've got (ax + b) / (-1) */
300 if x.den.terms.len == 1 && x.den.terms[0].vars.len == 0
301 var factor : Q = [ .p = x.den.terms[0].coeff.q, .q = x.den.terms[0].coeff.p ]
302 multiply_by_oneQ(x, &factor)
307 const reduce_variable_fractions = {x
308 /* As above, but now with variables */
311 if x.num.terms.len < 1
318 for var j = 0; j < x.num.terms.len; ++j
319 for var k = 0; k < x.num.terms[j].vars.len; ++k
320 if x.num.terms[j].vars[k].power.sign < 0
322 var p = t.dup(x.num.terms[j].vars[k].power)
324 var v = std.sldup(x.num.terms[j].vars[k].variable)
325 var vp = [ .variable = v, .power = p ]
326 var mon = [ .coeff = rid(), .vars = std.sldup([ vp ][:]) ]
327 multiply_by_onemono(x, &mon)
335 Perhaps the opposite has happened: both num and den are
336 multiples of x^2 y or something.
338 if x.num.terms[0].vars.len < 1
342 var oneQ : Q# = rid()
344 for var j = 0; j < x.num.terms[0].vars.len; ++j
345 var vp : var_power# = &x.num.terms[0].vars[j]
346 var min_power = t.dup(vp.power)
347 var this_var_divides_all = true
348 for var k = 1; k < x.num.terms.len; ++k
349 var cur_mon : monomial# = &x.num.terms[k]
350 var seen_this_var = false
351 for var l = 0; l < cur_mon.vars.len; ++l
352 var cur_vp : var_power# = &cur_mon.vars[l]
353 match t.cmp(vp.variable, cur_vp.variable)
358 match t.cmp(min_power, cur_vp.power)
360 __dispose__(min_power)
361 min_power = t.dup(cur_vp.power)
367 this_var_divides_all = false
372 if !this_var_divides_all
373 __dispose__(min_power)
377 for var k = 0; k < x.den.terms.len; ++k
378 var cur_mon : monomial# = &x.den.terms[k]
379 var seen_this_var = false
380 for var l = 0; l < cur_mon.vars.len; ++l
381 var cur_vp : var_power# = &cur_mon.vars[l]
382 match t.cmp(vp.variable, cur_vp.variable)
387 match t.cmp(min_power, cur_vp.power)
389 __dispose__(min_power)
390 min_power = t.dup(cur_vp.power)
396 this_var_divides_all = false
401 if !this_var_divides_all
402 __dispose__(min_power)
406 /* We've found that x^min_power is contained in everything */
408 var dup_name = std.sldup(vp.variable)
410 .variable = dup_name,
413 var killer_monomial = [
415 .vars = [ killer_vp ][:],
417 mul_poly_mon_ip(x.num, &killer_monomial)
418 mul_poly_mon_ip(x.den, &killer_monomial)
419 __dispose__(min_power)
425 const multiply_by_oneQ = {rf : ratfunc#, factor : Q#
426 for var j = 0; j < rf.num.terms.len; ++j
427 rmul_ip(rf.num.terms[j].coeff, factor)
429 for var j = 0; j < rf.den.terms.len; ++j
430 rmul_ip(rf.den.terms[j].coeff, factor)
434 const multiply_by_onemono = {rf : ratfunc#, factor : monomial#
435 mul_poly_mon_ip(rf.num, factor)
436 mul_poly_mon_ip(rf.den, factor)
440 const polynomialfromratfunc = {rf
441 if rf.den.terms.len > 1
442 /* 1 / (x + 1) is not a polynomial - it's not finite */
446 var m = &rf.den.terms[0]
449 | `std.None: -> `std.None
451 var p = t.dup(rf.num)
452 for var j = 0; j < p.terms.len; ++j
453 rmul_ip(p.terms[j].coeff, yi)
455 for var k = 0; k < m.vars.len; ++k
456 std.slpush(&p.terms[j].vars, [
457 .variable = std.sldup(m.vars[k].variable),
458 .power = gneg(m.vars[k].power)
461 reducemonomial(&p.terms[j])