diff options
| author | Mattias EngdegÄrd | 2019-09-22 15:03:02 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2019-09-29 13:41:21 +0200 |
| commit | 19405291aa5b1f7de7e44cc2efe384840b144236 (patch) | |
| tree | de07f6ca665f86881ffa7628a165c719fc3b7a11 | |
| parent | ab2a8f70775ff1c51e3b3b5f7b337c3fe5132db2 (diff) | |
| download | emacs-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.el | 6 | ||||
| -rw-r--r-- | test/lisp/calc/calc-tests.el | 103 |
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 | ||