From 29962bc3ec33e1e25f83f153b681d49182368592 Mon Sep 17 00:00:00 2001 From: Visuwesh Date: Sat, 16 Mar 2024 17:04:14 +0530 Subject: [PATCH] ob-calc.el: Add support for tables in Calc source block :var A table with MxN dimensions is converted to a MxN matrix when given in :var to a Calc source block. A table with a single row is converted to a vector (i.e., row vector). * lisp/ob-calc.el (org-babel-execute-src-block:calc): Construct the right data structure to pass tables as matrices to Calc. * testing/lisp/test-ob-calc.el: Add tests for ob-calc, and this new feature. * etc/ORG-NEWS: Announce the feature. --- etc/ORG-NEWS | 7 +++ lisp/ob-calc.el | 14 ++++- testing/lisp/test-ob-calc.el | 115 +++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 testing/lisp/test-ob-calc.el diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index ca73f06e7..197d7503d 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -1121,6 +1121,13 @@ Maxima's graphics packages (~draw~ or ~plot~); the default remains ~plot~. The graphics terminal is now determined from the file-ending of the file-name set in the ~:file~ header argument. +*** =ob-calc.el=: Support for tables in ~:var~ + +=ob-calc= now supports tables in ~:var~. They are converted to a +matrix or a vector depending on the dimensionality of the table. A +table with a single row is converted to a vector, the rest are +converted to a matrix. + *** Images and files in clipboard can be pasted Org asks the user what must be done when pasting images and files diff --git a/lisp/ob-calc.el b/lisp/ob-calc.el index f36df77ff..810ed1735 100644 --- a/lisp/ob-calc.el +++ b/lisp/ob-calc.el @@ -64,7 +64,19 @@ (var-names (mapcar #'symbol-name org--var-syms))) (mapc (lambda (pair) - (calc-push-list (list (cdr pair))) + (let ((val (cdr pair))) + (calc-push-list + ;; For a vector, Calc follows the format (vec 1 2 3 ...) so + ;; a matrix becomes (vec (vec 1 2 3) (vec 4 5 6) ...). See + ;; the comments in "Arithmetic routines." section of + ;; calc.el. + (list (if (listp val) + (cons 'vec + (if (null (cdr val)) + (car val) + (mapcar (lambda (x) (if (listp x) (cons 'vec x) x)) + val))) + val)))) (calc-store-into (car pair))) vars) (mapc diff --git a/testing/lisp/test-ob-calc.el b/testing/lisp/test-ob-calc.el new file mode 100644 index 000000000..6d6ca104d --- /dev/null +++ b/testing/lisp/test-ob-calc.el @@ -0,0 +1,115 @@ +;;; test-ob-calc.el --- tests for ob-calc.el -*- lexical-binding: t; -*- + +;; Copyright (C) 2024 Visuwesh + +;; Author: Visuwesh + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Code: +(require 'ob-calc) + +(unless (featurep 'ob-calc) + (signal 'missing-test-dependency "Support for Calc code blocks")) + +(ert-deftest ob-calc/simple-program-mult () + "Test of simple multiplication." + (org-test-with-temp-text "\ +#+BEGIN_SRC calc :results silent + 1 * 2 +#+END_SRC" + (should (equal "2" (org-babel-execute-src-block))))) + +(ert-deftest ob-calc/simple-program-arith () + "Test of simple arithmetic." + (org-test-with-temp-text "\ +#+BEGIN_SRC calc :results silent + 12 + 16 - 1 +#+END_SRC" + (should (equal "27" (org-babel-execute-src-block))))) + +(ert-deftest ob-calc/simple-program-symbolic () + "Test of simple symbolic algebra." + (org-test-with-temp-text "\ +#+BEGIN_SRC calc :results silent + inv(a) +#+END_SRC" + (should (equal "1 / a" (org-babel-execute-src-block))))) + +(ert-deftest ob-calc/matrix-inversion () + "Test of a matrix inversion." + (org-test-with-temp-text "\ +#+NAME: ob-calc-table-1 +| 1 | 2 | 3 | +| 5 | 6 | 7 | +| 9 | 14 | 11 | + +#+BEGIN_SRC calc :results silent :var a=ob-calc-table-1 + inv(a) +#+END_SRC " + (should (equal "[[-1, 0.625, -0.125], [0.25, -0.5, 0.25], [0.5, 0.125, -0.125]]" + (org-babel-execute-src-block))))) + +(ert-deftest ob-calc/matrix-algebra () + "Test of simple matrix algebra." + (org-test-with-temp-text "\ +#+NAME: ob-calc-table-2 +| 1 | 2 | 3 | 4 | 5 | + +#+BEGIN_SRC calc :results silent :var a=ob-calc-table-2 + a*2 - 2 +#+END_SRC" + (should (equal "[0, 2, 4, 6, 8]" + (org-babel-execute-src-block))))) + +(ert-deftest ob-calc/matrix-mean () + "Test of simple mean of a vector." + (org-test-with-temp-text "\ +#+NAME: ob-calc-table-2 +| 1 | 2 | 3 | 4 | 5 | + +#+BEGIN_SRC calc :results silent :var a=ob-calc-table-2 + vmean(a) +#+END_SRC" + (should (equal "3" + (org-babel-execute-src-block))))) + +(ert-deftest ob-calc/matrix-correct-conv-column () + "Test of conversion of column table to Calc format." + (org-test-with-temp-text "\ +#+NAME: ob-calc-table-3 +| 1 | +| 2 | +| 3 | + +#+BEGIN_SRC calc :results silent :var a=ob-calc-table-3 + a +#+END_SRC" + (should (equal "[[1], [2], [3]]" + (org-babel-execute-src-block))))) + +(ert-deftest ob-calc/matrix-correct-conv-row () + "Test of conversion of row table to Calc format." + (org-test-with-temp-text "\ +#+NAME: ob-calc-table-2 +| 1 | 2 | 3 | 4 | 5 | + +#+BEGIN_SRC calc :results silent :var a=ob-calc-table-2 + a +#+END_SRC" + (should (equal "[1, 2, 3, 4, 5]" + (org-babel-execute-src-block))))) + +(provide 'test-ob-calc) +;;; test-ob-calc.el ends here -- 2.43.0