From: "Mattias Engdegård" <mattiase@acm.org>
To: 35374@debbugs.gnu.org
Cc: Christopher Howard <christopher.howard@qlfiles.net>
Subject: bug#35374: Calc; Div by 0 in solving system
Date: Sun, 22 Sep 2019 19:34:45 +0200 [thread overview]
Message-ID: <2C5B66F6-D2BC-4A7E-B27A-BB0F6A80A1A3@acm.org> (raw)
In-Reply-To: <1555910400.14181.1.camel@qlfiles.net>
[-- Attachment #1: Type: text/plain, Size: 343 bytes --]
tags 35374 patch
stop
> Maybe someone more knowledgeable about Calc can help further.
Much to our surprise, very few people volunteered their service. Now, despite being grossly under-qualified for the task, I did give it a go. After all, we can't have it fail on simple linear equation systems now can we.
Please try this patch.
[-- Attachment #2: 0001-Fix-linear-equation-system-solving-in-Calc-bug-35374.patch --]
[-- Type: application/octet-stream, Size: 6111 bytes --]
From 980a1f0b73d2aa58335a47ad4a68005a28307a4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Sun, 22 Sep 2019 15:03:02 +0200
Subject: [PATCH] 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.
---
lisp/calc/calcalg2.el | 6 ++
test/lisp/calc/calc-tests.el | 103 +++++++++++++++++++++++++++++++++++
2 files changed, 109 insertions(+)
diff --git a/lisp/calc/calcalg2.el b/lisp/calc/calcalg2.el
index 18243bfc74..2a716633ae 100644
--- a/lisp/calc/calcalg2.el
+++ b/lisp/calc/calcalg2.el
@@ -2417,6 +2417,12 @@ math-try-solve-for
((= (length math-t1) 2)
(apply 'math-solve-linear
(car math-t2) math-try-solve-sign math-t1))
+ ((= (length math-t1) 1)
+ ;; Constant polynomial.
+ (if (eql (nth 2 math-t2) 1)
+ nil ; No possible solution.
+ ;; Root of the factor, if any.
+ (math-try-solve-for (nth 2 math-t2) 0 nil t)))
(math-solve-full
(math-poly-all-roots (car math-t2) math-t1))
(calc-symbolic-mode nil)
diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el
index e1ee20b5d2..36a81dc2b7 100644
--- a/test/lisp/calc/calc-tests.el
+++ b/test/lisp/calc/calc-tests.el
@@ -215,6 +215,109 @@ calc-test-calendar
(should (equal (math-absolute-from-julian-dt -101 3 1) -36832))
(should (equal (math-absolute-from-julian-dt -4713 1 1) -1721425)))
+(ert-deftest calc-test-solve-linear-system ()
+ "Test linear system solving (bug#35374)."
+ ;; x + y = 3
+ ;; 2x - 3y = -4
+ ;; with the unique solution x=1, y=2
+ (should (equal
+ (calcFunc-solve
+ '(vec
+ (calcFunc-eq (+ (var x var-x) (var y var-y)) 3)
+ (calcFunc-eq (- (* 2 (var x var-x)) (* 3 (var y var-y))) -4))
+ '(vec (var x var-x) (var y var-y)))
+ '(vec (calcFunc-eq (var x var-x) 1)
+ (calcFunc-eq (var y var-y) 2))))
+
+ ;; x + y = 1
+ ;; x + y = 2
+ ;; has no solution
+ (should (equal
+ (calcFunc-solve
+ '(vec
+ (calcFunc-eq (+ (var x var-x) (var y var-y)) 1)
+ (calcFunc-eq (+ (var x var-x) (var y var-y)) 2))
+ '(vec (var x var-x) (var y var-y)))
+ '(calcFunc-solve
+ (vec
+ (calcFunc-eq (+ (var x var-x) (var y var-y)) 1)
+ (calcFunc-eq (+ (var x var-x) (var y var-y)) 2))
+ (vec (var x var-x) (var y var-y)))))
+ ;; x - y = 1
+ ;; x + y = 1
+ ;; with the unique solution x=1, y=0
+ (should (equal
+ (calcFunc-solve
+ '(vec
+ (calcFunc-eq (- (var x var-x) (var y var-y)) 1)
+ (calcFunc-eq (+ (var x var-x) (var y var-y)) 1))
+ '(vec (var x var-x) (var y var-y)))
+ '(vec (calcFunc-eq (var x var-x) 1)
+ (calcFunc-eq (var y var-y) 0))))
+ ;; 2x - 3y + z = 5
+ ;; x + y - 2z = 0
+ ;; -x + 2y + 3z = -3
+ ;; with the unique solution x=1, y=-1, z=0
+ (should (equal
+ (calcFunc-solve
+ '(vec
+ (calcFunc-eq
+ (+ (- (* 2 (var x var-x)) (* 3 (var y var-y))) (var z var-z))
+ 5)
+ (calcFunc-eq
+ (- (+ (var x var-x) (var y var-y)) (* 2 (var z var-z)))
+ 0)
+ (calcFunc-eq
+ (+ (- (* 2 (var y var-y)) (var x var-x)) (* 3 (var z var-z)))
+ -3))
+ '(vec (var x var-x) (var y var-y) (var z var-z)))
+ ;; The `float' forms in the result are just artefacts of Calc's
+ ;; current solver; it should be fixed to produce exact (integral)
+ ;; results in this case.
+ '(vec (calcFunc-eq (var x var-x) (float 1 0))
+ (calcFunc-eq (var y var-y) (float -1 0))
+ (calcFunc-eq (var z var-z) 0))))
+ ;; x = y + 1
+ ;; x = y
+ ;; has no solution
+ (should (equal
+ (calcFunc-solve
+ '(vec
+ (calcFunc-eq (var x var-x) (+ (var y var-y) 1))
+ (calcFunc-eq (var x var-x) (var y var-y)))
+ '(vec (var x var-x) (var y var-y)))
+ '(calcFunc-solve
+ (vec
+ (calcFunc-eq (var x var-x) (+ (var y var-y) 1))
+ (calcFunc-eq (var x var-x) (var y var-y)))
+ (vec (var x var-x) (var y var-y)))))
+ ;; x + y + z = 6
+ ;; x + y = 3
+ ;; x - y = 1
+ ;; with the unique solution x=2, y=1, z=3
+ (should (equal
+ (calcFunc-solve
+ '(vec
+ (calcFunc-eq (+ (+ (var x var-x) (var y var-y)) (var z var-z)) 6)
+ (calcFunc-eq (+ (var x var-x) (var y var-y)) 3)
+ (calcFunc-eq (- (var x var-x) (var y var-y)) 1))
+ '(vec (var x var-x) (var y var-y) (var z var-z)))
+ '(vec
+ (calcFunc-eq (var x var-x) 2)
+ (calcFunc-eq (var y var-y) 1)
+ (calcFunc-eq (var z var-z) 3))))
+ ;; x = 3
+ ;; x + 4y^2 = 3 (ok, so this one isn't linear)
+ ;; with the unique (double) solution x=3, y=0
+ (should (equal
+ (calcFunc-solve
+ '(vec
+ (calcFunc-eq (var x var-x) 3)
+ (calcFunc-eq (+ (var x var-x) (* 4 (^ (var y var-y) 2))) 3))
+ '(vec (var x var-x) (var y var-y)))
+ '(vec (calcFunc-eq (var x var-x) 3)
+ (calcFunc-eq (var y var-y) 0)))))
+
(provide 'calc-tests)
;;; calc-tests.el ends here
--
2.21.0 (Apple Git-122)
next prev parent reply other threads:[~2019-09-22 17:34 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-22 5:20 bug#35374: Calc; Div by 0 in solving system Christopher Howard
2019-09-22 17:34 ` Mattias Engdegård [this message]
2019-09-23 5:28 ` Christopher Howard
2019-09-23 10:11 ` Mattias Engdegård
[not found] <1555861067.5469.3.camel@qlfiles.net>
2019-04-23 14:34 ` Mattias Engdegård
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2C5B66F6-D2BC-4A7E-B27A-BB0F6A80A1A3@acm.org \
--to=mattiase@acm.org \
--cc=35374@debbugs.gnu.org \
--cc=christopher.howard@qlfiles.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).