aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-09-22 15:03:02 +0200
committerMattias EngdegÄrd2019-09-29 13:41:21 +0200
commit19405291aa5b1f7de7e44cc2efe384840b144236 (patch)
treede07f6ca665f86881ffa7628a165c719fc3b7a11
parentab2a8f70775ff1c51e3b3b5f7b337c3fe5132db2 (diff)
downloademacs-19405291aa5b1f7de7e44cc2efe384840b144236.tar.gz
emacs-19405291aa5b1f7de7e44cc2efe384840b144236.zip
Fix linear equation system solving in Calc (bug#35374)
* lisp/calc/calcalg2.el (math-try-solve-for): To solve Ax^n=0 where A is a nonzero constant and x the variable to solve for, solve x^n=0 instead of solving A=0 (which obviously fails) or something equally stupid. * test/lisp/calc/calc-tests.el (calc-test-solve-linear-system): New.
-rw-r--r--lisp/calc/calcalg2.el6
-rw-r--r--test/lisp/calc/calc-tests.el103
2 files changed, 109 insertions, 0 deletions
diff --git a/lisp/calc/calcalg2.el b/lisp/calc/calcalg2.el
index 18243bfc749..2a716633ae6 100644
--- a/lisp/calc/calcalg2.el
+++ b/lisp/calc/calcalg2.el
@@ -2417,6 +2417,12 @@
2417 ((= (length math-t1) 2) 2417 ((= (length math-t1) 2)
2418 (apply 'math-solve-linear 2418 (apply 'math-solve-linear
2419 (car math-t2) math-try-solve-sign math-t1)) 2419 (car math-t2) math-try-solve-sign math-t1))
2420 ((= (length math-t1) 1)
2421 ;; Constant polynomial.
2422 (if (eql (nth 2 math-t2) 1)
2423 nil ; No possible solution.
2424 ;; Root of the factor, if any.
2425 (math-try-solve-for (nth 2 math-t2) 0 nil t)))
2420 (math-solve-full 2426 (math-solve-full
2421 (math-poly-all-roots (car math-t2) math-t1)) 2427 (math-poly-all-roots (car math-t2) math-t1))
2422 (calc-symbolic-mode nil) 2428 (calc-symbolic-mode nil)
diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el
index e1ee20b5d2d..36a81dc2b71 100644
--- a/test/lisp/calc/calc-tests.el
+++ b/test/lisp/calc/calc-tests.el
@@ -215,6 +215,109 @@ An existing calc stack is reused, otherwise a new one is created."
215 (should (equal (math-absolute-from-julian-dt -101 3 1) -36832)) 215 (should (equal (math-absolute-from-julian-dt -101 3 1) -36832))
216 (should (equal (math-absolute-from-julian-dt -4713 1 1) -1721425))) 216 (should (equal (math-absolute-from-julian-dt -4713 1 1) -1721425)))
217 217
218(ert-deftest calc-test-solve-linear-system ()
219 "Test linear system solving (bug#35374)."
220 ;; x + y = 3
221 ;; 2x - 3y = -4
222 ;; with the unique solution x=1, y=2
223 (should (equal
224 (calcFunc-solve
225 '(vec
226 (calcFunc-eq (+ (var x var-x) (var y var-y)) 3)
227 (calcFunc-eq (- (* 2 (var x var-x)) (* 3 (var y var-y))) -4))
228 '(vec (var x var-x) (var y var-y)))
229 '(vec (calcFunc-eq (var x var-x) 1)
230 (calcFunc-eq (var y var-y) 2))))
231
232 ;; x + y = 1
233 ;; x + y = 2
234 ;; has no solution
235 (should (equal
236 (calcFunc-solve
237 '(vec
238 (calcFunc-eq (+ (var x var-x) (var y var-y)) 1)
239 (calcFunc-eq (+ (var x var-x) (var y var-y)) 2))
240 '(vec (var x var-x) (var y var-y)))
241 '(calcFunc-solve
242 (vec
243 (calcFunc-eq (+ (var x var-x) (var y var-y)) 1)
244 (calcFunc-eq (+ (var x var-x) (var y var-y)) 2))
245 (vec (var x var-x) (var y var-y)))))
246 ;; x - y = 1
247 ;; x + y = 1
248 ;; with the unique solution x=1, y=0
249 (should (equal
250 (calcFunc-solve
251 '(vec
252 (calcFunc-eq (- (var x var-x) (var y var-y)) 1)
253 (calcFunc-eq (+ (var x var-x) (var y var-y)) 1))
254 '(vec (var x var-x) (var y var-y)))
255 '(vec (calcFunc-eq (var x var-x) 1)
256 (calcFunc-eq (var y var-y) 0))))
257 ;; 2x - 3y + z = 5
258 ;; x + y - 2z = 0
259 ;; -x + 2y + 3z = -3
260 ;; with the unique solution x=1, y=-1, z=0
261 (should (equal
262 (calcFunc-solve
263 '(vec
264 (calcFunc-eq
265 (+ (- (* 2 (var x var-x)) (* 3 (var y var-y))) (var z var-z))
266 5)
267 (calcFunc-eq
268 (- (+ (var x var-x) (var y var-y)) (* 2 (var z var-z)))
269 0)
270 (calcFunc-eq
271 (+ (- (* 2 (var y var-y)) (var x var-x)) (* 3 (var z var-z)))
272 -3))
273 '(vec (var x var-x) (var y var-y) (var z var-z)))
274 ;; The `float' forms in the result are just artefacts of Calc's
275 ;; current solver; it should be fixed to produce exact (integral)
276 ;; results in this case.
277 '(vec (calcFunc-eq (var x var-x) (float 1 0))
278 (calcFunc-eq (var y var-y) (float -1 0))
279 (calcFunc-eq (var z var-z) 0))))
280 ;; x = y + 1
281 ;; x = y
282 ;; has no solution
283 (should (equal
284 (calcFunc-solve
285 '(vec
286 (calcFunc-eq (var x var-x) (+ (var y var-y) 1))
287 (calcFunc-eq (var x var-x) (var y var-y)))
288 '(vec (var x var-x) (var y var-y)))
289 '(calcFunc-solve
290 (vec
291 (calcFunc-eq (var x var-x) (+ (var y var-y) 1))
292 (calcFunc-eq (var x var-x) (var y var-y)))
293 (vec (var x var-x) (var y var-y)))))
294 ;; x + y + z = 6
295 ;; x + y = 3
296 ;; x - y = 1
297 ;; with the unique solution x=2, y=1, z=3
298 (should (equal
299 (calcFunc-solve
300 '(vec
301 (calcFunc-eq (+ (+ (var x var-x) (var y var-y)) (var z var-z)) 6)
302 (calcFunc-eq (+ (var x var-x) (var y var-y)) 3)
303 (calcFunc-eq (- (var x var-x) (var y var-y)) 1))
304 '(vec (var x var-x) (var y var-y) (var z var-z)))
305 '(vec
306 (calcFunc-eq (var x var-x) 2)
307 (calcFunc-eq (var y var-y) 1)
308 (calcFunc-eq (var z var-z) 3))))
309 ;; x = 3
310 ;; x + 4y^2 = 3 (ok, so this one isn't linear)
311 ;; with the unique (double) solution x=3, y=0
312 (should (equal
313 (calcFunc-solve
314 '(vec
315 (calcFunc-eq (var x var-x) 3)
316 (calcFunc-eq (+ (var x var-x) (* 4 (^ (var y var-y) 2))) 3))
317 '(vec (var x var-x) (var y var-y)))
318 '(vec (calcFunc-eq (var x var-x) 3)
319 (calcFunc-eq (var y var-y) 0)))))
320
218(provide 'calc-tests) 321(provide 'calc-tests)
219;;; calc-tests.el ends here 322;;; calc-tests.el ends here
220 323