#+Title: LARCS #+Subtitle: The "Lisp Automated Rewrite and Calculation System" #+AUTHOR: Samuel W. Flint #+EMAIL: swflint@flintfam.org #+DATE: \today #+INFOJS_OPT: view:info toc:nil path:http://flintfam.org/org-info.js #+OPTIONS: toc:nil H:5 ':t *:t todo:nil stat:nil d:nil #+PROPERTY: header-args :noweb no-export :comments noweb #+LATEX_HEADER: \usepackage[margins=0.75in]{geometry} #+LATEX_HEADER: \usepackage[compact,sf,bf]{titlesec} #+LATEX_HEADER: \titleformat{\chapter}[hang]{\Huge\sf\bfseries}{\thechapter$\quad$}{0pt}{} #+LATEX_HEADER: \usepackage[nottoc,notlot,notlof]{tocbibind} #+LATEX_HEADER: \usepackage{tocloft} #+LATEX_HEADER: \parskip=5pt #+LATEX_HEADER: \parindent=0pt #+LATEX_HEADER: \lstset{texcl=true,breaklines=true,columns=fullflexible,basicstyle=\ttfamily,frame=lines,literate={<=}{$\leq$}1 {>=}{$\geq$}1} #+LATEX_CLASS: report #+LATEX_CLASS_OPTIONS: [10pt,twoside] #+LATEX_HEADER: \pagestyle{headings} * Export :noexport: :PROPERTIES: :CREATED: <2016-06-09 Thu 12:49> :END: #+Caption: Export Document #+Name: export-document #+BEGIN_SRC emacs-lisp :exports none :results none (save-buffer) (let ((org-confirm-babel-evaluate (lambda (lang body) (declare (ignorable lang body)) nil))) (org-latex-export-to-pdf)) #+END_SRC * Tangle :noexport: :PROPERTIES: :CREATED: <2016-06-09 Thu 12:50> :END: #+Caption: Tangle Document #+Name: tangle-document #+BEGIN_SRC emacs-lisp :exports none :results none (save-buffer) (let ((python-indent-offset 4)) (org-babel-tangle)) #+END_SRC * DONE Introduction CLOSED: [2016-12-14 Wed 14:59] :PROPERTIES: :CREATED: <2016-06-09 Thu 09:19> :UNNUMBERED: t :ID: f3e3cdb9-a661-4598-8be1-e15f587f35bb :END: LARCS is a Computer Algebra System, written from scratch, using the technique of literate programming to accomplish the goal. The purpose of this is threefold: first, as a learning exercise; second, to develop a CAS that is built around a clean, readable and modular design, rather than efficiency; and third, to demonstrate the abilities of Literate Programming in general, and Org-Mode in particular. There is another motive, many CASs are non-free, and those that aren't don't always provide a useful programming interface, and with the goal of a clean, readable and modular design, this can be accomplished. * DONE What's in a name? CLOSED: [2016-12-14 Wed 15:13] :PROPERTIES: :CREATED: <2016-06-09 Thu 12:37> :UNNUMBERED: t :END: While the [[id:f3e3cdb9-a661-4598-8be1-e15f587f35bb][Introduction]] describes the purpose of LARCS, it does not describe the name. LARCS stands for Lisp Automated Rewrite and Calculation System. This name describes the system quite accurately, as LARCS was written in Lisp, provides an automated system for rewriting equations into various forms, and calculating given an equation and values of the various variables, and acts as a coherent grouping of libraries forming a system. * TOC :ignore: :PROPERTIES: :CREATED: <2016-06-09 Thu 09:19> :END: #+TOC: headlines 3 #+TOC: listings * WORKING Common Functionality [3/6] :PROPERTIES: :CREATED: <2016-06-11 Sat 22:23> :ID: f153a0fe-ec04-47b1-bdc5-290cc62bc985 :END: There are several bits of common functions or variables that are required for use. This primarily includes functions that some of the macros rely on, or things that are required for use in other parts of the system, but don't present as specific functionality. ** DONE Generate an Args List CLOSED: [2016-07-30 Sat 16:08] :PROPERTIES: :CREATED: <2016-06-13 Mon 17:19> :ID: 49596957-2fc6-4458-ad85-99cbcf337b42 :END: For some macros, an arguments list must be generated. This is done by generating a list of variables starting with the word ~expression-~ followed by a letter from the alphabet, in turn. #+Caption: Generate an Args List #+Name: common-generate-an-args-list #+BEGIN_SRC lisp (defun gen-args-list (count) (let ((letters '(a b c d e f g h i j k l m n o p q r s t u v w x y z))) (let ((variables-list '())) (dotimes (i count) (pushnew (symbolicate 'expression- (nth i letters)) variables-list)) (reverse variables-list)))) #+END_SRC ** DONE Constants and Greeks CLOSED: [2016-08-05 Fri 21:32] :PROPERTIES: :CREATED: <2016-06-13 Mon 20:57> :ID: 907fcf64-51eb-4a2c-a8bc-29e4f75f1dd3 :END: This is a mapping between the names of constants and the way that they are correctly displayed in TeX. Besides defining the mapping, which is in the form of an alist, it also collects the names of all of the constants, and exports the names themselves. #+Caption: Constants and Greeks #+Name: constants-and-greeks #+BEGIN_SRC lisp (defvar *special-symbols-to-sequences* '((alpha . "\\alpha") (beta . "\\beta") (gamma . "\\gamma") (delta . "\\delta") (epsilon . "\\epsilon") (varepsilon . "\\varepsilon") (zeta . "\\zeta") (eta . "\\eta") (theta . "\\theta") (vartheta . "\\vartheta") (gamma . "\\gamma") (kappa . "\\kappa") (lambda . "\\lambda") (mu . "\\mu") (nu . "\\nu") (xi . "\\xi") (omicron . "\\o") (pi . "\\pi") (varpi . "\\varpi") (rho . "\\rho") (varrho . "\\varrho") (sigma . "\\sigma") (varsigm . "\\varsigm") (tau . "\\tau") (upsilon . "\\upsilon") (phi . "\\phi") (varphi . "\\varphi") (chi . "\\chi") (psi . "\\psi") (omega . "\\omega") (big-gamma . "\\Gamma") (big-delta . "\\Delta") (big-theta . "\\Theta") (big-lambda . "\\Lambda") (big-xi . "\\Xi") (big-pi . "\\Pi") (big-sigma . "\\Sigma") (big-upsilon . "\\Upsilon") (big-phi . "\\Phi") (big-psi . "\\Psi") (big-omega . "\\Omega"))) (defvar *constant-names* (mapcar #'car *special-symbols-to-sequences*)) (mapcar #'export *constant-names*) #+END_SRC ** TODO Aget :PROPERTIES: :CREATED: <2016-10-23 Sun 11:14> :END: #+Caption: Aget #+Name: common-aget #+BEGIN_SRC lisp (defun aget (place indicator &optional default) " RETURN: The value of the entry INDICATOR of the a-list PLACE, or DEFAULT. " (let ((a (assoc indicator place))) (if a (cdr a) default))) (define-setf-expander aget (place indicator &optional default &environment env) (declare (ignore default)) (multiple-value-bind (vars vals store-vars writer-form reader-form) (get-setf-expansion place env) (let* ((vindicator (gensym "INDICATOR")) (vvalue (gensym "VALUE")) (vstore (first store-vars)) (acs (gensym "PAIR"))) (values (list* vindicator vars) (list* indicator vals) (list vvalue) `(let* ((,acs (assoc ,vindicator ,reader-form))) (if ,acs (setf (cdr ,acs) ,vvalue) (let ((,vstore (acons ,vindicator ,vvalue ,reader-form))) ,writer-form)) ,vvalue) `(assoc ,vindicator ,reader-form))))) #+END_SRC ** TODO Ensure List :PROPERTIES: :CREATED: <2016-10-23 Sun 11:17> :ID: 08d8e031-a30f-41b6-9981-caec2f07f2a0 :END: #+Caption: Ensure List #+Name: ensure-list #+BEGIN_SRC lisp (defun ensure-list (object) " RETURN: If OBJECT is a list then OBJECT, otherwise a fresh list containing OBJECT. " (if (listp object) object (list object))) #+END_SRC ** TODO Evaluating Bind :PROPERTIES: :CREATED: <2016-12-14 Wed 15:13> :ID: 390707cd-6a58-404c-b2e5-286f09be977f :END: #+Caption: Evaluating Bind #+Name: evaluating-bind #+BEGIN_SRC lisp (defun evaluating-bind (expression &rest pairs) (let ((vars (mapcar #'first pairs)) (values (mapcar #'second pairs))) (apply (eval `(lambda ,vars ,expression)) values))) #+END_SRC ** DONE Assembly CLOSED: [2016-07-30 Sat 15:43] :PROPERTIES: :CREATED: <2016-06-13 Mon 17:20> :ID: d583d5e4-a2c9-432c-9486-cc6baa4239f4 :END: This is where the common functions and constants are assembled into their own package. Almost all of the functions and variables are exported and available for everything else. #+Caption: Assemble Common Functions #+Name: assemble-common-functions #+BEGIN_SRC lisp :tangle "larcs-common.lisp" (in-package #:larcs.common) <> <> <> <> <> #+END_SRC * DONE Expression Typing [8/8] :PROPERTIES: :CREATED: <2016-04-30 Sat 23:15> :ID: c6921b1e-d269-4243-acff-5a77685c331e :END: To be able to provide various forms of matching and manipulation, the type of an expression must be determined. This is done by analyzing the contents of the expression. To accomplish this, there must be a way to define a classifier, store all possible classifiers, check a classifier and produce a classification. To provide more flexibility in programming, there is also a special version of case, called ~classification-case~ and a when-pattern macro called ~when-classified-as~. ** DONE Define Classification CLOSED: [2016-06-14 Tue 23:00] :PROPERTIES: :CREATED: <2016-05-02 Mon 13:56> :ID: d8826a51-50b8-467a-9e52-158502bd4138 :END: Classifications are defined as ~define-classification~. This macro takes a ~name~, which is the name of the classification, and a body, which is classified within a function. Inside the function, the following are bound: ~expression~, the expression to be classified; and, ~length~, which is the length of the expression if it's a list, otherwise, 0 if it's atomic. A cons cell containing the name of the classification and the name of the classifier is pushed onto classification storage, and the classifier name is exported. #+Caption: Define Classification #+Name: et-define-classification #+BEGIN_SRC lisp (defmacro define-classification (name &body body) (check-type name symbol) (let ((classifier-name (symbolicate name '-classifier))) `(progn (defun ,classifier-name (expression &aux (length (if (listp expression) (length expression) 0))) (declare (ignorable length)) ,@body) (pushnew '(,name . ,classifier-name) *classifications*) (export ',name) ',name))) #+END_SRC ** DONE Check Classification CLOSED: [2016-06-14 Tue 23:10] :PROPERTIES: :CREATED: <2016-05-02 Mon 13:56> :ID: 6505b0b1-ffd8-4dd6-b81a-3e49483d8437 :END: To classify an expression, the expression and name of the possible classification is passed in. If the given name of the classification is ~*~, then ~t~ is returned, as this is a catch all; otherwise the classification is retrieved by name, and the expression is passed to the classifier, which will return either ~t~ or ~nil~. #+Caption: Check Classification #+Name: et-check-classification #+BEGIN_SRC lisp (defun classified-as-p (expression classification) (if (eq '* classification) t (funcall (cdr (assoc classification *classifications*)) expression))) #+END_SRC ** DONE Classify Expression CLOSED: [2016-06-14 Tue 23:23] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:09> :ID: 82d75d54-1d33-400b-86a3-7d16af938ac8 :END: While being able to check if an expression is given a specific classification is vital, for some things, being able to see what all possible classifications for an expression are can be quite useful. To do this, an expression is passed in, and for each possible classification in the classification storage, it is checked to see whether or not the classification is possible. If it is, the classification is pushed on to a list of valid classifications. When the possible classifications are exhausted, the list of valid classifications is reversed and returned. #+Caption: Classify Expression #+Name: et-classify-expression #+BEGIN_SRC lisp (defun classify (expression) (let ((classifications '())) (dolist (possible ,*classifications* (reverse classifications)) (let ((name (car possible)) (checker (cdr possible))) (when (funcall checker expression) (push name classifications)))))) #+END_SRC ** DONE Classification Case CLOSED: [2016-06-14 Tue 23:34] :PROPERTIES: :CREATED: <2016-05-20 Fri 14:15> :ID: 19a4e467-baa0-47eb-9267-93ff3801b1fd :END: Because case is such a useful tool, and because it provides a way to ensure that an expression doesn't fall through when acting on it, I've written the ~classification-case~ macro. It takes an expression, named ~var~ and a list of cases, in the form of ~(classification body-form-1 body-form-2 body-form-n)~. It transforms the cases, converting them to the form ~((classified-as-p expression 'type) body-form-1 body-form-2 body-form-n)~. It finally expands to a ~cond~ in which ~the-classification~ is bound to the full and complete classification of the passed expression. #+Caption: Classification Case #+Name: et-classification-case #+BEGIN_SRC lisp (defmacro classification-case (var &rest cases) (let ((conditions (map 'list #'(lambda (case) (destructuring-bind (type &body body) case (if (eq type 't) `((classified-as-p ,var '*) ,@body) `((classified-as-p ,var ',type) ,@body)))) cases))) `(let ((the-classification (classify ,var))) (declare (ignorable the-classification)) (cond ,@conditions)))) #+END_SRC ** DONE When Classified CLOSED: [2016-06-14 Tue 23:44] :PROPERTIES: :CREATED: <2016-05-30 Mon 18:31> :ID: 5c7c3e0b-9170-48e9-a414-6ac4528f9ac3 :END: Another utility macro is ~when-classified-as~, which takes a ~classification~, an expressiond named ~variable~ and a body. It expands fairly simply to a ~when~ form, with the predicate taking the following form ~(classified-as-p variable 'classification)~, wrapping around the passed in body. #+Caption: When Classified #+Name: et-when-classified #+BEGIN_SRC lisp (defmacro when-classified-as (classification variable &body body) `(when (classified-as-p ,variable ',classification) ,@body)) #+END_SRC ** DONE Classifications [13/13] :PROPERTIES: :CREATED: <2016-05-02 Mon 13:56> :ID: dcce4a6b-1b2d-4638-a82b-0c4917b0698a :END: I define the following classifications: - Numerics :: All numbers - Variables :: Any symbols - Non-atomics :: Anything that isn't simply a number or a variable - Additives :: Expressions that are adding multiple terms - Subtractives :: Expressions subtracting multiple terms - Powers :: Expressions of the form $x^n$, where $x$ is a variable, and $n$ is a numeric. - Exponentials :: Expressions of the form $x^y$ or $e^y$, where $x$ and $y$ are generic expressions, and $e$ is Euler's constant. - Logarithmics :: Expressions of the form of $\ln x$ or $\log_b x$, where $x$ and $b$ are generic expressions. - Rationals :: Expressions of the form $\frac{f(x)}{g(x)}$. - Polynomial Terms :: Any integers, multiplicatives of the form $nx^m$ or powers of the form $x^m$, where $x$ is a variable and $n$ and $m$ are numerics. - Polynomials :: Additives or Subtractives consisting solely of Polynomial Terms. - Trigonometrics :: The trig functions: $\sin$, $\cos$, $\tan$, $\csc$, $\sec$ and $\cot$. #+Caption: Possible Classifications #+Name: et-possible-classifications #+BEGIN_SRC lisp <> <> <> <> <> <> <> <> <> <> <> <> <> #+END_SRC *** DONE Numbers CLOSED: [2016-06-14 Tue 23:58] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:26> :ID: 42081153-7cc5-42ff-a17f-53e171c6d1a7 :END: A number is defined as anything that satisfies the built-in ~numberp~. This includes integers, rationals, floats and complex numbers. #+Caption: Classify Numbers #+Name: et-classify-numbers #+BEGIN_SRC lisp (define-classification numeric (numberp expression)) #+END_SRC *** DONE Variables CLOSED: [2016-06-15 Wed 00:00] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:26> :ID: 4c676754-ef9a-485f-91a2-8f1bd83c7659 :END: Variables are defined as anything that satisfies the Common Lisp predicate, ~symbolp~. #+Caption: Classify Variables #+Name: et-classify-variables #+BEGIN_SRC lisp (define-classification variable (symbolp expression)) #+END_SRC *** DONE Non Atomics CLOSED: [2016-06-15 Wed 00:02] :PROPERTIES: :CREATED: <2016-05-04 Wed 19:52> :ID: 414df063-0be1-4849-8b9f-d71aa828be2a :END: Non-atomic is a classification for anything other than numerics and variables. It is defined as anything that satisfies the predicate ~listp~. #+Caption: Classify Non-Atomics #+Name: et-classify-non-atomics #+BEGIN_SRC lisp (define-classification non-atomic (listp expression)) #+END_SRC *** DONE Additives CLOSED: [2016-06-15 Wed 00:03] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:26> :ID: 736d79dc-f34c-4247-b592-690d7f2fddd9 :END: When an expression is non-atomic, and the first element is the symbol ~+~, it is classified as an additive expression. #+Caption: Classify Additives #+Name: et-classify-additives #+BEGIN_SRC lisp (define-classification additive (when-classified-as non-atomic expression (eq '+ (first expression)))) #+END_SRC *** DONE Subtractive CLOSED: [2016-06-15 Wed 00:06] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:26> :ID: c59d086f-2f49-485a-8f96-57d85e774f60 :END: A non-atomic expression for which the first element is the symbol ~-~ is a subtractive expression. #+Caption: Classify Subtractives #+Name: et-classify-subtractives #+BEGIN_SRC lisp (define-classification subtractive (when-classified-as non-atomic expression (eq '- (first expression)))) #+END_SRC *** DONE Powers CLOSED: [2016-06-15 Wed 00:07] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:27> :ID: cc15dd10-7cc0-4370-9e69-daf903b30ad5 :END: A power is any expression that is non-atomic, the first element is the symbol ~expt~, the second is a variable and the third is a numeric. #+Caption: Classify Powers #+Name: et-classify-powers #+BEGIN_SRC lisp (define-classification power (when-classified-as non-atomic expression (and (eq 'expt (first expression)) (classified-as-p (second expression) 'variable) (classified-as-p (third expression) 'numeric)))) #+END_SRC *** DONE Exponentials CLOSED: [2016-06-15 Wed 00:11] :PROPERTIES: :CREATED: <2016-05-02 Mon 15:04> :ID: a11fdd94-d56c-4749-bb22-dca75159dbcb :END: There are two types of exponentials, natural and non-natural. Natural exponentials are defined as being non-atomic, two elements long, and the first element being ~exp~. Non-natural exponentials are defined similarly, but are three elements long, and the first of which is the symbol ~expt~. #+Caption: Classify Exponentials #+Name: et-classify-exponentials #+BEGIN_SRC lisp (define-classification natural-exponential (when-classified-as non-atomic expression (and (= 2 length) (eq 'exp (first expression))))) (define-classification exponential (when-classified-as non-atomic expression (and (= 3 length) (eq 'expt (first expression))))) #+END_SRC *** DONE Multiplicatives CLOSED: [2016-06-15 Wed 00:12] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:27> :ID: feb85a20-93e3-45a1-be01-9893ecc07c53 :END: A multiplicative expression is non-atomic, of any length, and the first element is the symbol ~*~. #+Caption: Classify Multiplicatives #+Name: et-classify-multiplicatives #+BEGIN_SRC lisp (define-classification multiplicative (when-classified-as non-atomic expression (eq '* (first expression)))) #+END_SRC *** DONE Logarithmics CLOSED: [2016-06-15 Wed 00:14] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:27> :ID: 0b733d75-e1ab-413f-8f8a-6a8a47db409c :END: There are two types of logarithmic classifications, natural and non-natural. Natural logarithmics are non-atomic, two elements long, and the first element is the symbol ~log~. Natural logarithmics are also non-atomic, but they are three elements long, starting with the symbol ~log~. #+Caption: Classify Lograthmics #+Name: et-classify-logarithmics #+BEGIN_SRC lisp (define-classification natural-logarithmic (when-classified-as non-atomic expression (and (= 2 length) (eq 'log (first expression))))) (define-classification logarithmic (when-classified-as non-atomic expression (and (= 3 length) (eq 'log (first expression))))) #+END_SRC *** DONE Rationals CLOSED: [2016-06-15 Wed 00:15] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:28> :ID: a4505a66-c249-4438-a6df-81e21718e23e :END: Rationals are non-atomic, three elements long, and the first element is the symbol ~/~. #+Caption: Classify Rationals #+Name: et-classify-rationals #+BEGIN_SRC lisp (define-classification rational (when-classified-as non-atomic expression (and (= 3 length) (eq '/ (first expression))))) #+END_SRC *** DONE Polynomial Terms CLOSED: [2016-06-15 Wed 00:17] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:28> :ID: 37da52b7-98a0-4a16-8a17-a62fcff2ba59 :END: Polynomials are a compound classification: - Numerics - Variables - Powers - Multiplicatives that are a numeric and a variable - Multiplicatives that are a numeric and a power #+Caption: Classify Polynomial Term #+Name: et-classify-polynomial-term #+BEGIN_SRC lisp (define-classification polynomial-term (or (classified-as-p expression 'numeric) (classified-as-p expression 'variable) (classified-as-p expression 'power) (and (classified-as-p expression 'multiplicative) (= (length (rest expression)) 2) (or (and (classified-as-p (second expression) 'numeric) (or (classified-as-p (third expression) 'power) (classified-as-p (third expression) 'variable))) (and (classified-as-p (third expression) 'numeric) (or (classified-as-p (second expression) 'power) (classified-as-p (second expression) 'variable))))))) #+END_SRC *** DONE Polynomials CLOSED: [2016-06-15 Wed 00:19] :PROPERTIES: :CREATED: <2016-05-02 Mon 14:28> :ID: 8cd9045b-81dd-4571-930a-a852f81969c9 :END: Polynomials are compound classifications that are defined as expressions which are either additive or subtrative, for which each term is a polynomial term. #+Caption: Classify Polynomials #+Name: et-classify-polynomials #+BEGIN_SRC lisp (define-classification polynomial (when-classified-as non-atomic expression (and (or (eq '- (first expression)) (eq '+ (first expression))) (reduce #'(lambda (a b) (and a b)) (map 'list #'(lambda (the-expression) (classified-as-p the-expression 'polynomial-term)) (rest expression)))))) #+END_SRC *** DONE Trigonometrics CLOSED: [2016-06-15 Wed 00:22] :PROPERTIES: :CREATED: <2016-05-04 Wed 13:38> :ID: 6f433cad-4b81-4a6f-ab65-981f4a924812 :END: Trigonometrics are defined as non atomic expressions that are two elements long, for which the first element of the expression is either ~sin~, ~cos~, ~tan~, ~csc~, ~sec~, or ~cot~. For each of these there is a classification seperate from the generic ~trigonometric~ classification. #+Caption: Classify Trigonometrics #+Name: et-classify-trigonometrics #+BEGIN_SRC lisp (define-classification trigonometric (when-classified-as non-atomic expression (member (first expression) '(sin cos tan csc sec cot)))) (define-classification sin (when-classified-as non-atomic expression (eq 'sin (first expression)))) (define-classification cos (when-classified-as non-atomic expression (eq 'cos (first expression)))) (define-classification tan (when-classified-as non-atomic expression (eq 'tan (first expression)))) (define-classification csc (when-classified-as non-atomic expression (eq 'csc (first expression)))) (define-classification sec (when-classified-as non-atomic expression (eq 'sec (first expression)))) (define-classification cot (when (classified-as-p expression 'non-atomic) (eq 'cot (first expression)))) #+END_SRC ** DONE Classification Storage CLOSED: [2016-06-14 Tue 23:48] :PROPERTIES: :CREATED: <2016-05-02 Mon 13:55> :ID: ff35cd33-3c10-4a45-a2c5-32bc3fdc1acc :END: Classifications are stored in an alist, with the key being the name of the classification, and the value being the classifier itself. These cons cells are stored in the ~*classifications*~ variable. #+Caption: Classification Storage #+Name: et-classification-storage #+BEGIN_SRC lisp (defvar *classifications* '()) #+END_SRC ** DONE Assembly CLOSED: [2016-06-15 Wed 00:26] :PROPERTIES: :CREATED: <2016-06-14 Tue 16:59> :ID: bb1d3eb5-b9bf-4378-9716-87ab57dcc8a3 :END: This assembles the classification library, which in the ~#:larcs.classify~ package. It correctly resolves the order of the code, taking it from simple blocks to a complete file. #+Caption: Expression Typing Assembly #+Name: et-assembly #+BEGIN_SRC lisp :tangle "larcs-classify.lisp" (in-package #:larcs.classify) <> <> <> <> <> <> <> #+END_SRC * WORKING Polynomial Related Functions [4/10] :PROPERTIES: :CREATED: <2016-05-01 Sun 12:29> :ID: 984d0f52-4c52-4bfa-a150-f3289d25bdf1 :END: Polynomials, and polynomial terms, are a somewhat common occurence. Because of this, it is important to provide a set of functions that manipulate these structures. These functions include a coefficient retriever, a variable retriever, a power retriever and a couple of order comparators. ** DONE Collect Variables CLOSED: [2016-06-21 Tue 22:10] :PROPERTIES: :CREATED: <2016-05-20 Fri 15:15> :ID: 6333322c-e12f-4ef6-8394-2fe219a72836 :END: The task of collecting all variables in a given expression is fairly important to the task of algebraic manipulation. This is accomplished using a fairly simple recursive algorithm, collecting the elements that are classified as variables. An expression is passed in, and if a variable, it is collected, if non-atomic, all but the first element are passed again to ~collect-variables~, and it happens all over again, this time, with those variables being added to the list, and when all is said and done, a list of all variables in a given expression is returned. See the following figure for a graphical representation. #+Caption: Variable Collection #+Name: variable-collection #+BEGIN_SRC dot :file "imgs/variable-collection.png" :export results :cache yes digraph { start [label = "Start"]; stop [label = "Stop"]; collect [label = "Collect"]; if_var [label = "If Variable", shape = rectangle]; recurse_collect [label = "Iterate, Recurse and Collect Results"]; start -> if_var; if_var -> collect [label = "True"]; collect -> stop; if_var -> recurse_collect [label = "Non-atomic"]; recurse_collect -> start; } #+END_SRC #+Caption: Variable Collection Algorithm #+Name: fig:variable-collection #+ATTR_LATEX: :width 8cm #+RESULTS[e1586dc50921f7ba260f125e7221a978d489bd34]: variable-collection [[file:imgs/variable-collection.png]] #+Caption: Collect Variables #+Name: poly-collect-variables #+BEGIN_SRC lisp (defun collect-variables (expression) (let ((variables '())) (flet ((merge-variables (variable) (pushnew variable variables))) (classification-case expression (variable (merge-variables expression)) (non-atomic (map 'list #'(lambda (expr) (dolist (variable (collect-variables expr)) (merge-variables variable))) (rest expression))))) (reverse variables))) #+END_SRC ** DONE Get Coefficient CLOSED: [2016-06-26 Sun 19:50] :PROPERTIES: :CREATED: <2016-05-31 Tue 19:08> :ID: cbc927fc-ae5e-46bf-a028-2872b5c31831 :END: To get the coefficient of a polynomial term there are three possibilities - Numerics :: The term itself - Multiplicatives :: The second element in the term - All else :: 1 #+Caption: Get Coefficient #+Name: poly-get-coefficient #+BEGIN_SRC lisp (defun coefficient (term) (when (classified-as-p term 'polynomial-term) (classification-case term (numeric term) (multiplicative (second term)) (* 1)))) #+END_SRC ** DONE Get Term Variables CLOSED: [2016-06-27 Mon 18:40] :PROPERTIES: :CREATED: <2016-05-31 Tue 19:08> :ID: 55729698-bd51-48af-ab42-197871c54dbb :END: The ability to retrieve tha variable in a polynomial term is important. This is accomplished by collecting the variables in the term and returning the first. If this is simply a numeric expression, ~nil~ is returned as there are no variables. #+Caption: Get Term Variable #+Name: poly-get-term-variable #+BEGIN_SRC lisp (defun term-variable (term) (when (classified-as-p term 'polynomial-term) (first (collect-variables term)))) #+END_SRC ** DONE Get Power CLOSED: [2017-01-19 Thu 20:59] :PROPERTIES: :CREATED: <2016-05-31 Tue 19:08> :ID: 7d5a10da-bb30-496f-b285-470057a46db0 :END: When dealing with polynomial terms, it is frequently useful to be able to retrieve the power of the term. This is done differently for a few different types of terms: in the case of numerics and variables, it's a constant, 0 and 1 respectively; in the case of powers, it's the third element of the list, and in the case of multiplicatives, it's the power of the third term (which will be either a variable or a power). #+Caption: Get Power #+Name: poly-get-power #+BEGIN_SRC lisp (defun get-power (term) (classification-case term (numeric 0) (variable 1) (power (third term)) (multiplicative (get-power (third term))) (* 0))) #+END_SRC ** TODO Term Order Less Than :PROPERTIES: :CREATED: <2016-06-24 Fri 20:57> :ID: b7fcb056-2494-4142-aad5-7619629b1980 :END: #+Caption: Term Order Less Than #+Name: poly-term-order-less-than #+BEGIN_SRC lisp (defun term-order-< (a b) (< (get-power a) (get-power b))) #+END_SRC ** TODO Same Order :PROPERTIES: :CREATED: <2016-05-31 Tue 19:08> :ID: c56a1496-f4c2-4693-9448-5043570a752f :END: #+Caption: Same Order #+Name: poly-same-order #+BEGIN_SRC lisp (defun term-order-= (term-a term-b) (= (get-power term-a) (get-power term-b))) #+END_SRC ** TODO Term Order Greater Than :PROPERTIES: :CREATED: <2016-06-24 Fri 20:57> :ID: 27f836aa-8522-4a4c-88b3-6f19a505916f :END: #+Caption: Term Order Greater Than #+Name: poly-term-order-greater-than #+BEGIN_SRC lisp (defun term-order-> (a b) (> (get-power a) (get-power b))) #+END_SRC ** TODO Same Variable :PROPERTIES: :CREATED: <2016-05-31 Tue 19:08> :ID: 3806c97a-12fa-4488-b38c-d9ff3570c139 :END: #+Caption: Same Variable #+Name: poly-same-variable #+BEGIN_SRC lisp (defun same-variable-p (term-a term-b) (eq (term-variable term-a) (term-variable term-b))) #+END_SRC ** TODO Is Combinable :PROPERTIES: :CREATED: <2016-05-31 Tue 19:08> :ID: db0410aa-bb12-4933-9be7-1a50d70ae90f :END: #+Caption: Is Combinable #+Name: poly-is-combinable #+BEGIN_SRC lisp (defun single-term-combinable-p (term-a term-b) (and (term-order-= term-a term-b) (same-variable-p term-a term-b))) #+END_SRC ** TODO Assembly :PROPERTIES: :CREATED: <2016-08-21 Sun 11:03> :ID: 0c64cf6f-818d-4d39-9dc3-ab9353a6d66e :END: #+Caption: Polynomial Related Functions #+Name: poly-assembly #+BEGIN_SRC lisp :tangle "larcs-polynomials.lisp" (in-package #:larcs.polynomials) <> <> <> <> <> <> <> <> <> #+END_SRC * WORKING Algebraic Manipulation [3/4] :PROPERTIES: :CREATED: <2016-06-09 Thu 09:20> :ID: b2c1fd45-b631-48f9-a093-66e1a0faa77f :END: One of the most important parts of this system is the "algebraic manipulator", a sub-system that provides utilities for symbolic arithmetic, that is to say addition, subtraction, multiplication and division, along with trigonometric functions and exponential/logarithmic functions. These function, as many other portions of this system, using rewrite rules, implementing a form of specialized generic programming. ** DONE Term Collection CLOSED: [2016-06-24 Fri 20:57] :PROPERTIES: :CREATED: <2016-04-30 Sat 22:59> :ID: c1856735-914b-4f73-8825-3e5a062113d2 :END: To aid in the design and implementation of various sub-systems, from simplification to the basics of algebraic manipulators, the ability to collect terms is extremely important. It is accomplished as follows: 1. Lists for each of the types are initialized as empty. 2. For each term in the given expression, put it into the given list. 3. Return an alist containing the names of the types and the given lists, with the conses removed if the CDR is null. #+Caption: Collect Terms #+Name: am-collect-terms #+BEGIN_SRC lisp (defun collect-terms (expression &aux (terms (rest expression))) (let ((numerics '()) (variables '()) (additives '()) (subtractives '()) (multiplicatives '()) (polynomial-terms '()) (rationals '()) (powers '()) (natural-exponentials '()) (exponentials '()) (natural-logarithmics '()) (trigonometrics '())) (dolist (term terms) (classification-case term (numeric (pushnew term numerics)) (variable (pushnew term variables)) (power (pushnew term powers)) (additive (pushnew term additives)) (subtractive (pushnew term subtractives)) (polynomial-term (pushnew term polynomial-terms)) (multiplicative (pushnew term multiplicatives)) (rational (pushnew term rationals)) (power (pushnew term powers)) (natural-exponential (pushnew term natural-exponentials)) (exponential (pushnew term exponentials)) (natural-logarithmic (pushnew term natural-logarithmics)) (trigonometric (pushnew term trigonometrics)))) (remove-if #'(lambda (expr) (null (cdr expr))) (list (cons :numerics numerics) (cons :variables variables) (cons :powers powers) (cons :additives additives) (cons :subtractives subtractives) (cons :multiplicatives multiplicatives) (cons :polynomial-terms polynomial-terms) (cons :rationals rationals) (cons :powers powers) (cons :natural-exponentials natural-exponentials) (cons :exponentials exponentials) (cons :natural-logarithmics natural-logarithmics) (cons :trigonometrics trigonometrics))))) #+END_SRC ** DONE Define Expression Manipulator [2/2] CLOSED: [2016-09-23 Fri 19:21] :PROPERTIES: :CREATED: <2016-04-30 Sat 22:57> :ID: 63909972-428d-47f3-9dc3-3e1fb213aa70 :END: This is an extremely complicated macro, and as such is quite long. However, to explain it adequately is not hard, especially when it is broken into sections. In the first part, we define ~*manipulator-map*~, which store the names of the manipulators and the short-names. Following that, we define the macro ~define-operation~ which takes three arguments: a name, function arity, and a short name (operation name). It verifies the types of the passed arguments, and then begins the ~let*~ block, binding as seen in [[id:b8c75ae9-137f-42c4-bb54-ee103ada11f1][Variable Bindings]]. To expand this macro, it begins a ~progn~, which starts by pushing the a cons cell in the form of ~(short . long)~ onto the manipulator mapping. From there, a variable is defined with the name bound to ~rules-name~, an applicability predicate is defined, a manipulator finder is also defined, as is a function to properly call the manipulator on a given set of arguments. Following that, it defines the macro used to define manipulators for the specified operation, as explained in [[id:9aa262c7-c536-48e8-a0e7-4504b330bb60][The Inner Macro]]. #+Caption: Define Expression Manipulator #+Name: am-define-expression-manipulator #+BEGIN_SRC lisp (defvar *manipulator-map* '()) (defmacro define-operation (name arity short) (check-type name symbol) (check-type arity (integer 1 26)) (check-type short symbol) (let* ( <> ) `(progn (push '(,short . ,name) *manipulator-map*) (defvar ,rules-name '()) (defun ,is-applicable-name (types ,@args) (and ,@type-check-list)) (defun ,get-operations-name (,@args) (remove-if #'null (map 'list #'(lambda (option) (let ((types (car option)) (name (cdr option))) (if (,is-applicable-name types ,@args) name))) ,rules-name))) (defun ,name (,@args) (funcall (first (,get-operations-name ,@args)) ,@args)) <> ))) #+END_SRC *** DONE Variable Bindings CLOSED: [2016-09-23 Fri 18:12] :PROPERTIES: :CREATED: <2016-09-23 Fri 17:13> :ID: b8c75ae9-137f-42c4-bb54-ee103ada11f1 :END: To accomplish the job of defining a group of manipulators, for the macro expansion to succeed, there must be a few variables bound. These include: - Arguments, types and others: - args :: This is a list of arguments used for a manipulation function's lambda list. - expression-types :: This is a list used to keep the various types for finding the correct manipulator. - type-check-list :: This is a list of expressions used to check whether or not a given argument is of a type. This is specifically used in determining applicability of a manipulator to the given arguments. - Names of things - rules-name :: This is the name of the rules container, where the types-to-manipulator mapping is kept. - base-manipulator-name :: This is the base name of the manipulator, used in the definition of a specific manipulator for a given group of types. - manipulator-define-name :: This is the name of the macro used to define manipulators. - is-applicable-name :: The name of the function used to check whether or not a manipulator is applicable. - get-operations-name :: The name of the function used to retrieve possible manipulators for a given set of arguments. #+Caption: Variable Bindings #+Name: am-variable-bindings #+BEGIN_SRC lisp (args (gen-args-list arity)) (expression-types (map 'list #'(lambda (x) (symbolicate x '-type)) args)) (rules-name (symbolicate '*manipulators- name '*)) (base-manipulator-name (symbolicate name '-manipulator-)) (manipulator-define-name (symbolicate 'define- name '-manipulator)) (is-applicable-name (symbolicate name '-is-applicable-p)) (get-operations-name (symbolicate 'get- name '-manipulators)) (type-check-list (let ((i 0)) (loop for arg in args collect (prog1 `(classified-as-p ,arg (nth ,i types)) (incf i))))) #+END_SRC *** DONE The Inner Macro CLOSED: [2016-09-23 Fri 18:53] :PROPERTIES: :CREATED: <2016-09-23 Fri 17:14> :ID: 9aa262c7-c536-48e8-a0e7-4504b330bb60 :END: This defines a macro, named ~manipulator-define-name~, taking a list of expression types and a body. It generates a name for the manipulator and then adds a mapping for the manipulator to the manipulator map, defining a function with the manipulator name, the pre-defined arguments list and the given body. #+Caption: Manipulation Definition Macro (Inner) #+Name: am-manipulation-definition-macro #+BEGIN_SRC lisp (defmacro ,manipulator-define-name ((,@expression-types) &body body) (let ((manipulator-name (symbolicate ',base-manipulator-name ,@expression-types))) `(progn (setf ,',rules-name (append ,',rules-name '(((,,@expression-types) . ,manipulator-name)))) (defun ,manipulator-name ,',args ,@body)))) #+END_SRC ** TODO External Manipulator :PROPERTIES: :CREATED: <2016-05-01 Sun 14:33> :ID: 6419490c-3cb0-47e4-840a-c20af4bfb3d7 :END: The Expression Manipulators should not be touched outside of this package, as they are not designed to be used outside of it. Instead, they should be used through this simple function. It takes an action and a list of expressions. The function used to perform the action correctly is determined, and used to reduce the expressions. #+Caption: External Manipulator #+Name: am-external-manipulator #+BEGIN_SRC lisp (defun manipulate (action &rest expressions) (let ((the-manipulator (cdr (assoc action *manipulator-map*)))) (reduce the-manipulator expressions))) #+END_SRC ** DONE Assembly CLOSED: [2016-06-18 Sat 13:38] :PROPERTIES: :CREATED: <2016-04-30 Sat 23:07> :ID: d487ed31-295b-4274-aef2-b45e4fa7bec2 :END: This is the assembly of the ~#:larcs.manipulate~ package. It includes, in correct order, all bits of functionality. It places all of this in the ~larcs-manipulation.lisp~ file. #+Caption: Packaging #+Name: am-packaging #+BEGIN_SRC lisp :tangle "larcs-manipulation.lisp" (in-package #:larcs.manipulate) <> <> <> <> <> #+END_SRC * WORKING Manipulators for Addition [0/1] :PROPERTIES: :CREATED: <2016-04-30 Sat 23:08> :ID: b794486c-e493-408f-b80c-a440edae1bc8 :END: To accomplish the goal of providing a system that can manipulate any and all proper algebraic expressions, one of the most basic operations of such is addition. This provides a set of manipulators acting upon proper additive expressions. It declares itself to be a part of the ~#:larcs.manipulate~ package; defines an operation for addition, called ~add~, taking 2 arguments with a short-name of ~+~. It then includes the various manipulators that are defined for addition. #+Caption: Addition Manipulator #+Name: am-addition-manipulator #+BEGIN_SRC lisp :tangle "larcs-manipulators-addition.lisp"" (in-package #:larcs.manipulate) (define-operation add 2 +) <> #+END_SRC ** TODO Numerics :PROPERTIES: :CREATED: <2016-09-23 Fri 16:38> :ID: 3d9c9da7-ab93-48e3-a340-07d4d80f7f47 :END: Find Outer Otter #+Caption: Addition Manipulators for Numerics #+Name: addition-manipulators-for-numerics #+BEGIN_SRC lisp (define-add-manipulator (numeric numeric) (+ expression-a expression-b)) (define-add-manipulator (numeric additive) (let ((total expression-a) (remainder (rest expression-b)) (non-numeric '())) (dolist (element remainder) (if (classified-as-p element 'numeric) (incf total element) (push element non-numeric))) (cond ((null non-numeric) total) ((= 0 total) `(+ ,@non-numeric)) (t `(+ ,total ,@non-numeric))))) (define-add-manipulator (additive additive) (let ((total 0) (elements (append (rest expression-a) (rest expression-b))) (non-numeric '())) (dolist (element elements) (if (classified-as-p element 'numeric) (incf total element) (push element non-numeric))) (cond ((null non-numeric) total) ((= 0 total) `(+ ,@non-numeric)) (t `(+ ,total ,@non-numeric))))) (define-add-manipulator (numeric subtractive) (let ((total expression-a) (the-other (rest expression-b)) (non-numeric '())) (dolist (element the-other) (if (classified-as-p element 'numeric) (decf total element) (push element non-numeric))) (cond ((null non-numeric) total) ((= 0 total) `(+ ,@non-numeric)) (t `(+ ,total (-,@non-numeric)))))) (define-add-manipulator (numeric polynomial-term) `(+ ,expression-a ,expression-b)) (define-add-manipulator (polynomial-term polynomial-term) (if (single-term-combinable-p expression-a expression-b) (let ((new-coefficient (+ (coefficient expression-a) (coefficient expression-b))) (variable (term-variable expression-a)) (power (get-power expression-a))) `(* ,new-coefficient (expt ,variable ,power))) `(+ ,expression-a ,expression-b))) (define-add-manipulator (* numeric) (add expression-b expression-a)) #+END_SRC * TODO Manipulators for Subtraction :PROPERTIES: :CREATED: <2016-04-30 Sat 23:08> :ID: f675fd81-e995-41ee-9570-cc78261d9dc1 :END: Bifurcate All Rectangles #+Caption: Subtraction Manipulator #+Name: am-subtraction-manipulator #+BEGIN_SRC lisp :tangle "larcs-manipulators-subtraction.lisp" (in-package #:larcs.manipulate) (define-operation subtract 2 -) (define-subtract-manipulator (numeric numeric) (- expression-a expression-b)) (define-subtract-manipulator (numeric subtractive) (let ((total expression-a) (elements (rest expression-b)) (non-numeric '())) (dolist (element elements) (if (classified-as-p element 'numeric) (decf total element) (push element non-numeric))) (cond ((null non-numeric) total) ((= 0 total) `(- ,@(reverse non-numeric))) (t `(- ,total ,@(reverse non-numeric)))))) (define-subtract-manipulator (* numeric) (subtract expression-b expression-a)) #+END_SRC * TODO Manipulators for Multiplication :PROPERTIES: :CREATED: <2016-04-30 Sat 23:08> :ID: cddffdaa-10dd-425f-9697-3f0617162953 :END: Quickly Automate Zoos #+Caption: Multiplication Manipulators #+Name: am-multiplication-manipulators #+BEGIN_SRC lisp :tangle "larcs-manipulators-multiplication.lisp" (in-package #:larcs.manipulate) (define-operation multiply 2 *) (define-multiply-manipulator (numeric numeric) (* expression-a expression-b)) (define-multiply-manipulator (numeric polynomial-term) (let ((new-coefficient (* expression-a (coefficient expression-b))) (variable (term-variable expression-b)) (power (get-power expression-b))) (if (= 1 power) `(* ,new-coefficient ,variable) `(* ,new-coefficient (expt ,variable ,power))))) (define-multiply-manipulator (polynomial-term polynomial-term) (let ((new-coefficient (* (coefficient expression-a) (coefficient expression-b))) (variable (term-variable expression-b)) (power (+ (get-power expression-a) (get-power expression-b)))) `(* ,new-coefficient (expt ,variable ,power)))) #+END_SRC * TODO Manipulators for Division :PROPERTIES: :CREATED: <2016-04-30 Sat 23:09> :ID: 4c4f7034-555a-46b0-85b9-56a08cf48f9b :END: Quietly Usurp X-Rays #+Caption: Division Manipulators #+Name: am-division-manipulators #+BEGIN_SRC lisp :tangle "larcs-manipulators-division.lisp" (in-package #:larcs.manipulate) (define-operation division 2 /) (define-division-manipulator (numeric numeric) (/ expression-a expression-b)) (define-division-manipulator (polynomial-term polynomial-term) (let ((new-coefficient (/ (coefficient expression-a) (coefficient expression-b))) (variable (term-variable expression-b)) (power (- (get-power expression-a) (get-power expression-b)))) `(* ,new-coefficient (expt ,variable ,power)))) #+END_SRC * WORKING Manipulators for Trigonometric [0/6] :PROPERTIES: :CREATED: <2016-04-30 Sat 23:09> :ID: ba4acf37-9074-429b-a2c8-a23094e1c86b :END: Foo #+Caption: Trigonometric Manipulators #+Name: am-trigonometric-manipulators #+BEGIN_SRC lisp :tangle "larcs-manipulators-trig.lisp" (in-package #:larcs.manipulate) <> <> <> <> <> <> #+END_SRC ** WORKING Sine :PROPERTIES: :CREATED: <2016-05-08 Sun 16:22> :ID: c733c6b3-a44a-488f-8b6e-38346830b257 :END: Foo #+Caption: Sine Manipulators #+Name: am-sine-manipulators #+BEGIN_SRC lisp (define-operation sine 1 sin) (define-sine-manipulator (numeric) (sin expression-a)) #+END_SRC ** WORKING Cosine :PROPERTIES: :CREATED: <2016-05-08 Sun 16:22> :ID: c2fbd362-6932-4483-8270-e3ad72a308fd :END: Foo #+Caption: Cosine Manipulators #+Name: am-cosine-manipulators #+BEGIN_SRC lisp (define-operation cosine 1 cos) (define-cosine-manipulator (numeric) (cosine expression-a)) #+END_SRC ** WORKING Tangent :PROPERTIES: :CREATED: <2016-05-08 Sun 16:22> :ID: 07222206-1c22-411e-a8ab-13e1a627e9ef :END: Foo #+Caption: Tangent Manipulators #+Name: am-tangent-manipulators #+BEGIN_SRC lisp (define-operation tangent 1 tan) (define-tangent-manipulator (numeric) (tan expression-a)) #+END_SRC ** WORKING Cosecant :PROPERTIES: :CREATED: <2016-05-08 Sun 16:22> :ID: e77c0317-7281-45ff-b86b-8d66fb8c38ef :END: Foo #+Caption: Cosecant Manipulators #+Name: am-cosecant-manipulators #+BEGIN_SRC lisp (define-operation cosecant 1 csc) #+END_SRC ** WORKING Secant :PROPERTIES: :CREATED: <2016-05-08 Sun 16:23> :ID: 6c377c7d-ec84-4fcf-be94-db89b832c2d8 :END: Foo #+Caption: Secant Manipulators #+Name: am-secant-manipulators #+BEGIN_SRC lisp (define-operation secant 1 sec) #+END_SRC ** WORKING Cotangent :PROPERTIES: :CREATED: <2016-05-08 Sun 16:23> :ID: 70a9fb76-7ca7-4c7d-b25b-0fa94d390b6c :END: Foo #+Caption: Cotangent Manipulators #+Name: am-cotangent-manipulators #+BEGIN_SRC lisp (define-operation cotangent 1 cot) #+END_SRC * DONE Symbolic Differentiation [4/4] :PROPERTIES: :CREATED: <2016-06-13 Mon 22:45> :ID: 552f402a-a25d-4f28-94af-17934c38a529 :END: While this isn't exactly /algebra/, differentiation is important mathematically. This is done rather simply using rules to rewrite an initial expression forming the derivative. ** DONE Rule Definition [3/3] CLOSED: [2016-08-16 Tue 22:10] :PROPERTIES: :CREATED: <2016-06-13 Mon 22:51> :END: Rule definition is how this system works. This is done rather simply, and is comprised of definition, retrieval and storage portions. *** DONE Definition CLOSED: [2016-07-19 Tue 20:48] :PROPERTIES: :CREATED: <2016-06-13 Mon 22:51> :ID: de915ee7-47bd-4f7f-ad06-39f0201a4651 :END: Rules are defined using the ~define-derivative~ macro, which takes an expression type, an arguments list, and a body. If the expression type is not already in the expansions map, it pushes the expression type and expansion name onto the the mapping. Following that, it defines a function for the expansion, using the given arguments list as the lambda-list and the given body for the body for the function. #+Caption: Rule Definition #+Name: sd-rule-definition #+BEGIN_SRC lisp (defmacro define-derivative (expression-type (&rest arguments-list) &body body) (let ((expansion-name (symbolicate expression-type '-expansion))) `(progn (when (not (member ',expression-type (mapcar #'car *rules*))) (setq *rules* (append *rules* '((,expression-type . ,expansion-name))))) (defun ,expansion-name (,@arguments-list) ,@body)))) #+END_SRC *** DONE Retrieval CLOSED: [2016-08-16 Tue 22:00] :PROPERTIES: :CREATED: <2016-06-13 Mon 23:08> :ID: 97d8b24e-dd75-4919-a953-cba8035cb691 :END: Rule retrieval works by matching a rewrite rule to an expression by classification. This is done by iterating through the possible classification-rewrite rule pairs, and if the expression matches the classification, returing the rewrite rule to be used. #+Caption: Rule Retrieval #+Name: sd-rule-retrieval #+BEGIN_SRC lisp (defun get-rule (expression) (cdr (first (remove-if #'(lambda (pair) (let ((type (first pair))) (not (classified-as-p expression type)))) ,*rules*)))) #+END_SRC *** DONE Storage CLOSED: [2016-08-16 Tue 22:05] :PROPERTIES: :CREATED: <2016-06-13 Mon 22:52> :ID: 372dc2d7-ee67-4eba-a9f7-3633eaf0996e :END: Rules are stored rather simply, in a list of cons cells, with the ~CAR~ being the classification, and the ~CDR~ being the actualy rewrite function. They are found in the variable ~*rules*~. #+Caption: Rule Storage #+Name: sd-rule-storage #+BEGIN_SRC lisp (defvar *rules* '()) #+END_SRC ** DONE Rules [9/9] :PROPERTIES: :CREATED: <2016-06-13 Mon 22:52> :ID: fdcebadd-b53d-4f59-99a4-4a3782e017a2 :END: The process of symbolic derivation is carried out through rules. These are defined in the following sections, taking apart the equations and putting them back together again as their derivatives. #+Caption: Rules #+Name: sd-rules #+BEGIN_SRC lisp <> <> <> <> <> <> <> <> <> #+END_SRC *** DONE Numbers CLOSED: [2016-08-19 Fri 17:07] :PROPERTIES: :CREATED: <2016-06-13 Mon 23:18> :ID: bb1f9175-2e86-43a3-94b3-9467d233539c :END: Numbers are perhaps one of the simplest rules to define, ignore everything and simply return 0, which is, by definition, the derivative of any bare number. #+Caption: Numbers #+Name: sd-numbers #+BEGIN_SRC lisp (define-derivative numeric (&rest junk) (declare (ignorable junk)) 0) #+END_SRC *** DONE Variables CLOSED: [2016-08-19 Fri 17:19] :PROPERTIES: :CREATED: <2016-06-13 Mon 23:19> :ID: ecc17ca3-2989-4908-aded-4b6e20b1855c :END: As with Numbers, Variables are just as simple, if something is simply a bare variable, the derivative of such is 1. #+Caption: Variables #+Name: sd-variables #+BEGIN_SRC lisp (define-derivative variable (&rest junk) (declare (ignorable junk)) 1) #+END_SRC *** DONE Polynomial Terms CLOSED: [2016-08-19 Fri 17:31] :PROPERTIES: :CREATED: <2016-06-13 Mon 23:33> :ID: 6ca719d7-b584-4ae6-ae44-23bed186c6e9 :END: A Polynomial Term is a bit more complex than the previous two, the rewrite rule has to be able to get the variable, coefficient and current power of the polynomial term. Given this information, there are three possible cases: - The power is equal to 1. :: The coefficient is returned. - The power is equal to 2. :: The coefficient times the variable (in symbolic form) is returned. - The power is greater than 2. :: This comes in the form of $(nm)x^{^}{(n-1)}$. #+Caption: Polynomial Terms #+Name: sd-polynomial-terms #+BEGIN_SRC lisp (define-derivative polynomial-term (&rest term) (let* ((coefficient (coefficient term)) (variable (term-variable term)) (power (get-power term))) (cond ((= 1 power) coefficient) ((= 2 power) `(* ,(* coefficient power) ,variable)) (t `(* ,(* coefficient power) (expt ,variable ,(1- power))))))) #+END_SRC *** DONE Multiplicatives CLOSED: [2016-08-19 Fri 20:21] :PROPERTIES: :CREATED: <2016-06-14 Tue 09:57> :ID: 161906a4-5c14-4a84-bf1d-7fae9e20b14f :END: Differentiation of Multiplicative equations are performed by the product rule. This is defined as $\frac{\mathrm{d}}{\mathrm{d}x} f(x) \cdot g(x) = f(x) \cdot g^{\prime}(x) + f^{\prime}(x) \cdot g(x)$. There are some minor exceptions, if $f(x)$ and $g(x)$ are numeric, then the result is the product of the two; if either $f(x)$ or $g(x)$ is numeric and the other is not, then the numeric is placed in front of the other derivative of the remainder. #+Caption: Multiplicatives #+Name: sd-multiplicatives #+BEGIN_SRC lisp (define-derivative multiplicative (function first &rest rest) (declare (ignore function)) (if (= 1 (length rest)) (let ((second (first rest))) (cond ((and (classified-as-p first 'numeric) (classified-as-p second 'numeric)) (* first second)) ((classified-as-p first 'numeric) `(* ,first ,(differentiate second))) ((classified-as-p second 'numeric) `(* ,second ,(differentiate first))) (t `(+ (* ,first ,(differentiate second)) (* ,second ,(differentiate first)))))) (differentiate `(* ,first (* ,@rest))))) #+END_SRC *** DONE Rationals CLOSED: [2016-08-20 Sat 13:28] :PROPERTIES: :CREATED: <2016-06-14 Tue 10:21> :ID: cd681a61-a143-4e02-a6a9-e7b8f9b9c77d :END: This follows the quotient rule, which is defined as $\frac{\mathrm{d}}{\mathrm{d}x} \frac{f(x)}{g(x)} = \frac{f^{\prime}(x)g(x) - f(x)g^{\prime}(x)}{g(x)^2}$. #+Caption: Rational Derivatives #+Name: sd-rationals #+BEGIN_SRC lisp (define-derivative rational (function numerator denominator) (declare (ignore function)) `(/ (- (* ,numerator ,(differentiate denominator)) (* ,denominator ,(differentiate numerator))) (expt ,denominator 2))) #+END_SRC *** DONE Additives CLOSED: [2016-08-20 Sat 11:20] :PROPERTIES: :CREATED: <2016-06-14 Tue 10:30> :ID: d3a07d51-977c-4b1e-9a63-0eb415977f46 :END: This is quite simple, differentiate each term and add them together. This is accomplished using ~map~. #+Caption: Additives #+Name: sd-additives #+BEGIN_SRC lisp (define-derivative additive (function &rest terms) (declare (ignore function)) `(+ ,@(map 'list #'(lambda (term) (differentiate term)) terms))) #+END_SRC *** DONE Subtractives CLOSED: [2016-08-20 Sat 13:13] :PROPERTIES: :CREATED: <2016-06-14 Tue 10:30> :ID: 063f61ee-6fd9-4286-9008-9c80ef0985a5 :END: Following the same pattern as for additives, subtractives map over, deriving each term and prepending the ~-~ symbol to render the derivative of the originally passed subtractive equation. #+Caption: Subtractives #+Name: sd-subtractives #+BEGIN_SRC lisp (define-derivative subtractive (function &rest terms) (declare (ignore function)) `(- ,@(map 'list #'(lambda (term) (differentiate term)) terms))) #+END_SRC *** DONE Exponentials and Logarithmics CLOSED: [2016-08-20 Sat 13:39] :PROPERTIES: :CREATED: <2016-06-14 Tue 10:37> :END: There are four types of functions that are supported: - Natural Exponentials :: Effectively this returns itself. - Exponentials :: The original function multiplied by the log of the base. - Natural Logarithmics :: The derivative of the function being passed to $\ln$ over the same function. - Logarithmics :: The derivative of the natural log of the expression over the log of the base times the expression. #+Caption: Exponentials and Logarithms #+Name: sd-exponentials-and-logarithms #+BEGIN_SRC lisp (define-derivative natural-exponential (function expression) (declare (ignore function)) `(exp ,expression)) (define-derivative exponential (function base power) (declare (ignore function)) (if (numberp power) (if (listp base) `(* ,power (expt ,base ,(1- power)) ,(differentiate base)) `(* ,power (expt ,base ,(1- power)))) `(* (expt ,base ,power) (log ,base)))) (define-derivative natural-logarithmic (function expression) (declare (ignore function)) `(/ ,(differentiate expression) ,expression)) (define-derivative logarithmic (function number base) (declare (ignore function)) `(/ ,(differentiate (cons 'log number)) (* (log ,base) ,number))) #+END_SRC *** DONE Trigonometric Functions CLOSED: [2016-08-19 Fri 20:36] :PROPERTIES: :CREATED: <2016-06-14 Tue 10:45> :ID: c519d192-5f34-466b-b366-3890208c0928 :END: The following trig functions are supported: - Sine :: $f^{\prime}(x) \cdot \cos(f(x))$ - Cosine :: $^{}f^{\prime}(x) \cdot -\sin(f(x))$ - Tangent :: $f^{\prime}(x) \cdot {\sec(f(x))}^2$ - Cosecant :: $f^{\prime}(x) \cdot \left( \csc(f(x)) - \cot(f(x)) \right)$ - Cotangent :: $f^{\prime}(x) \cdot -{\csc(f(x))}^2$ #+Caption: Trigonometric Functions #+Name: sd-trigonometric-functions #+BEGIN_SRC lisp (define-derivative sin (function expression) (declare (ignore function)) `(* ,(differentiate expression) (cos ,expression))) (define-derivative cos (function expression) (declare (ignore function)) `(* ,(differentiate expression) (- (sin ,expression)))) (define-derivative tan (function expression) (declare (ignore function)) `(* ,(differentiate expression) (expt (sec ,expression) 2))) (define-derivative csc (function expression) (declare (ignore function)) `(* ,(differentiate expression) (- (csc ,expression)) (cot ,expression))) (define-derivative cot (function expression) (declare (ignore function)) `(* ,(differentiate expression) (- (expt (csc ,expression) 2)))) #+END_SRC ** DONE Driver CLOSED: [2016-07-18 Mon 18:31] :PROPERTIES: :CREATED: <2016-06-13 Mon 22:59> :ID: b40ed5ad-2eb7-43b1-bab7-39592894e5be :END: This is the derivative driver, ~differentiate~, which in the end is called recursively. It takes an expression (called function), finds a rule using the ~get-rule~ function, and applies the rule to the function, ensuring that the function is passed as a list. #+Caption: Derivative Driver #+Name: sd-derivative-driver #+BEGIN_SRC lisp (defun differentiate (function) (let ((rule (get-rule function))) (when rule (apply rule (ensure-list function))))) #+END_SRC ** DONE Assembly CLOSED: [2016-07-19 Tue 20:36] :PROPERTIES: :CREATED: <2016-06-13 Mon 22:46> :ID: d87d49e3-8245-4ff0-aaf0-57b9e19edeba :END: This assembles the package, placing the contents in the correct order and puts them in the file ~larcs-differentiate.lisp~. #+Caption: Symbolic Differentiation #+Name: sd-symbolic-differentiation #+BEGIN_SRC lisp :tangle "larcs-differentiate.lisp" (in-package #:larcs.differentiate) <> <> <> <> <> #+END_SRC * WORKING Symbolic To Typeset Form [3/5] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:13> :ID: 75f65e8a-0cc9-477f-b5e9-3c563fe7ef5c :END: One of the less important parts of this system is the format converter, which converts between the internal symbolic form and a format that is capable of being typeset using TeX. This is done using a variant of the common rewrite system, but instead of going between variants of the symbolic format, it converts from a symbolic format to string-based format. ** DONE Rule Management [2/2] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:17> :END: To accomplish the task of conversion from symbolic form to typeset form, rules are necessary. It is done using three main things, rule definition, rule retrieval and rule storage. *** DONE Define Rules CLOSED: [2016-06-24 Fri 22:28] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:18> :ID: ec6fdb0d-546e-41fc-a7b7-5fbbfe4b7931 :END: Rule definitions are built using the ~define-converter~ macro, which takes an expression type, a lambda list and a body. It creates a function using the body and the given arguments list, and if it hasn't been pushed onto the storage system, the converter function is pushed into storage. #+Caption: Rule Definition #+Name: stf-define-rule #+BEGIN_SRC lisp (defvar *rules* '()) (defmacro define-converter (expression-type (&rest arguments-list) &body body) (let ((expansion-name (symbolicate expression-type '-conversion))) `(progn (when (not (member ',expression-type (mapcar #'car *rules*))) (setq *rules* (append *rules* '((,expression-type . ,expansion-name))))) (defun ,expansion-name (,@arguments-list) ,@body)))) #+END_SRC *** DONE Rule Retrieval CLOSED: [2016-06-24 Fri 22:36] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:18> :ID: 0c34c744-7847-46c2-bdef-228feee7c84e :END: Rule retrieval is done by taking an expression, comparing it against given classifications, and from the first classification, returning the second element of the ~(classification . converter)~ pair. #+Caption: Rule Retrieval #+Name: stf-rule-retrieval #+BEGIN_SRC lisp (defun get-rule (expression) (cdr (first (remove-if #'(lambda (pair) (let ((type (first pair))) (not (classified-as-p expression type)))) ,*rules*)))) #+END_SRC ** WORKING Rules [4/9] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:18> :ID: 90accad9-81d0-4aaf-9c7f-2418e36e1f3c :END: The following contains all of the defined rules, which are as follows: - Numerics - Variables - Polynomial Terms - Multiplicatives - Rationals - Additives - Subtractives - Trigonometrics - Exponentials & Logarithmics #+Caption: Rules #+Name: stf-rules #+BEGIN_SRC lisp <> <> <> <> <> <> <> <> <> #+END_SRC *** DONE Numbers CLOSED: [2016-08-02 Tue 22:09] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:22> :ID: fbc3e5ac-3276-4f54-b53e-9d4cc0263405 :END: Numbers are formatted fairly simply, as they are simply surrounded by curly braces, and formatted as to be normal read syntax, which is generally correct. #+Caption: Numerics #+Name: stf-numerics #+BEGIN_SRC lisp (define-converter numeric (number) (with-tex-output (format nil "{~A}" number))) #+END_SRC *** DONE Variables CLOSED: [2016-08-02 Tue 22:20] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:22> :ID: 8ec363f7-da0f-4023-90bb-e08a85623f55 :END: As with numbers, variables are a relatively simple thing to format. If the variable passed is in the ~*constant-names*~ list, then it must be a formattable constant for which there is a known TeX command. If there is, it is looked up in the ~*special-symbols-to-sequences*~ alist, otherwise, the given variable is downcased and output as a string. Either way, they are surrounded by, as usual, curly braces. #+Caption: Variables #+Name: stf-variables #+BEGIN_SRC lisp (define-converter variable (var) (if (member var *constant-names*) (with-tex-output (format nil "{~A}" (cdr (assoc var *special-symbols-to-sequences*)))) (with-tex-output (format nil "{~A}" (string-downcase var))))) #+END_SRC *** DONE Polynomial Terms CLOSED: [2017-01-19 Thu 20:13] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:23> :ID: ac2283d0-da70-4672-90cb-08511bd9105e :END: Polynomial Terms are a specific classification, defined as follows: - A variable, raised to a numeric power. - A number, followed by a single variable. - A number, followed by a variable raised to a numeric power. These are typeset as a single unit, ensuring readability. #+Caption: Polynomial Terms #+Name: stf-polynomial-terms #+BEGIN_SRC lisp (define-converter polynomial-term (&rest term) (let ((variable (term-variable term)) (coefficient (coefficient term)) (power (get-power term))) (cond ((= 1 power) (with-tex-output (format nil "{~A}{~A}" (convert-for-display coefficient) (convert-for-display power)))) ((= 0 coefficient) (with-tex-output (format nil "{~A}^{~A}" (convert-for-display variable) (convert-for-display power)))) (t (with-tex-output (format nil "{~A}{~A}^{~A}" (convert-for-display coefficient) (convert-for-display variable) (convert-for-display power))))))) #+END_SRC *** DONE Multiplicatives CLOSED: [2017-05-12 Fri 15:15] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:23> :ID: 87a7e236-072e-4c19-9f09-c458e5b50397 :END: In the case of multiplicatives, which are variadic, a $\cdot$ or ~\cdot~ is placed in between each term, individually converted itself. #+Caption: Multiplicatives #+Name: stf-multiplicatives #+BEGIN_SRC lisp (define-converter multiplicative (op &rest elements) (declare (ignore op)) (with-tex-output (format nil "{~{~A~^ \\cdot ~}}" (mapcar #'convert-for-display elements)))) #+END_SRC *** TODO Rationals :PROPERTIES: :CREATED: <2016-06-14 Tue 17:23> :ID: 4f8f984f-e567-4efb-ba15-8a98e15915fe :END: #+Caption: Rationals #+Name: stf-rationals #+BEGIN_SRC lisp (define-converter rational (op numerator denominator) (declare (ignore op)) (with-tex-output (format nil "{\\frac{~A}{~A}}" (convert-for-display numerator) (convert-for-display denominator)))) #+END_SRC *** TODO Additives :PROPERTIES: :CREATED: <2016-06-14 Tue 17:23> :ID: 10ec8596-094a-4900-aba0-22b958ffdc9a :END: #+Caption: Additives #+Name: stf-additives #+BEGIN_SRC lisp (define-converter additive (op &rest terms) (declare (ignore op)) (with-tex-output (format nil "{~{~A~^ + ~}}" (mapcar #'convert-for-display terms)))) #+END_SRC *** TODO Subtractives :PROPERTIES: :CREATED: <2016-06-14 Tue 17:23> :ID: 1037cb8e-f127-4c87-9312-2817bc2cfc25 :END: #+Caption: Subtractives #+Name: stf-subtractives #+BEGIN_SRC lisp (define-converter subtractive (op &rest terms) (declare (ignore op)) (with-tex-output (format nil "{~{~A~^ - ~}}" (mapcar #'convert-for-display terms)))) #+END_SRC *** TODO Trigonometrics :PROPERTIES: :CREATED: <2016-06-14 Tue 18:38> :ID: 742d303a-dcea-4bb2-9553-19b968a70272 :END: #+Caption: Trigonometrics #+Name: stf-trigonometrics #+BEGIN_SRC lisp (define-converter sin (op term) (declare (ignore op)) (with-tex-output (format nil "{\\sin {~A}}" (convert-for-display term)))) (define-converter cos (op term) (declare (ignore op)) (with-tex-output (format nil "{\\cos {~A}}" (convert-for-display term)))) (define-converter tan (op term) (declare (ignore op)) (with-tex-output (format nil "{\\tan {~A}}" (convert-for-display term)))) (define-converter csc (op term) (declare (ignore op)) (with-tex-output (format nil "{\\csc {~A}}" (convert-for-display term)))) (define-converter sec (op term) (declare (ignore op)) (with-tex-output (format nil "{\\sec {~A}}" (convert-for-display term)))) (define-converter cot (op term) (declare (ignore op)) (with-tex-output (format nil "{\\cot {~A}}" (convert-for-display term)))) #+END_SRC *** TODO Exponentials and Logarithmics :PROPERTIES: :CREATED: <2016-06-14 Tue 17:24> :ID: 24dc527f-0b9d-44b0-ae0f-4515f0c1d119 :END: #+Caption: Exponentials and Logarithmics #+Name: stf-exponentials-logarithmics #+BEGIN_SRC lisp (define-converter natural-exponential (op term) (declare (ignore op)) (with-tex-output (format nil "{e^~A}" (convert-for-display term)))) (define-converter exponential (op base power) (declare (ignore op)) (with-tex-output (format nil "{~A^~A}" (convert-for-display base) (convert-for-display power)))) (define-converter natural-logarithmic (op term) (declare (ignore op)) (with-tex-output (format nil "{\\ln ~A}" (convert-for-display term)))) (define-converter logarithmic (op term base) (declare (ignore op)) (with-tex-output (format nil "{\\log_~a ~a}" (convert-for-display base) (convert-for-display term)))) #+END_SRC ** WORKING Converter [2/7] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:18> :ID: 88d433ad-e381-4747-8a29-2d78bc759fbf :END: The ~convert-for-display~ function is the driver for this portion of the application, and, in general, uses the previously defined rules, save for the logical functions ~and~, ~or~, ~not~, and the equality operation, summation with big-Sigma, integration and parenthesis. #+Caption: Conversion Driver #+Name: stf-conversion-driver #+BEGIN_SRC lisp (defun convert-for-display (function) (if (and (listp function) (member (first function) '(and or not = sum integrate parens))) (let ((operator (first function))) (cond ((eq operator 'and) <> ) ((eq operator 'or) <> ) ((eq operator 'not) <> ) ((eq operator '=) <> ) ((eq operator 'sum) <> ) ((eq operator 'integrate) <> ) ((eq operator 'parens) <> ))) (let ((rule (get-rule function))) (when rule (apply rule (ensure-list function)))))) #+END_SRC *** DONE And CLOSED: [2016-12-09 Fri 15:20] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:38> :ID: 733b98a1-90f1-4d13-abe8-cb86a5608aee :END: Like other rules, this formats a list of other sub-equations, with the symbol $\land$ (~\land~) between each term. #+Caption: And Operator #+Name: stf-and-operator #+BEGIN_SRC lisp (destructuring-bind (op &rest terms) function (declare (ignore op)) (with-tex-output (format nil "{~{~A~^ \\wedge ~}}" (mapcar #'convert-for-display terms)))) #+END_SRC *** DONE Or CLOSED: [2016-12-09 Fri 15:22] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:38> :ID: 276de305-32c4-4f79-96e7-d0a99ff24f78 :END: This does the same thing as "And", replacing the symbol with $\lor$ (~\lor~). #+Caption: Or Operator #+Name: stf-or-operator #+BEGIN_SRC lisp (destructuring-bind (op &rest terms) function (declare (ignore op)) (with-tex-output (format nil "{~{~A~^ \\vee ~}}" (mapcar #'convert-for-display terms)))) #+END_SRC *** TODO Not :PROPERTIES: :CREATED: <2016-06-14 Tue 17:38> :ID: 1b0a28a4-744d-44d1-a328-7b2bb10bd0c7 :END: Foo #+Caption: Not Operator #+Name: stf-not-operator #+BEGIN_SRC lisp (destructuring-bind (op term) function (with-tex-output (format nil "{\\not ~A}" (convert-for-display term)))) #+END_SRC *** TODO Equality :PROPERTIES: :CREATED: <2016-06-14 Tue 17:41> :ID: 4ce4835c-e196-4494-ab4b-591690e4164c :END: Foo #+Caption: Equality Operator #+Name: stf-equality-operator #+BEGIN_SRC lisp (destructuring-bind (op lhs rhs) function (declare (ignore op)) (format nil "{~A = ~A}" (convert-for-display lhs) (convert-for-display rhs))) #+END_SRC *** TODO Summation :PROPERTIES: :CREATED: <2016-06-14 Tue 17:24> :ID: 98404213-b8b8-410f-b660-23b701518cea :END: #+Caption: Summation #+Name: stf-summation #+BEGIN_SRC lisp (destructuring-bind (op start stop expression) function (declare (ignore op)) (format nil "{\sum_~A^~A ~A}" (convert-for-display start) (convert-for-display stop) (convert-for-display expression))) #+END_SRC *** TODO Integration :PROPERTIES: :CREATED: <2016-06-14 Tue 17:39> :ID: 60c16d30-2bb3-497c-aaa0-4529ecfc523c :END: #+Caption: Integration #+Name: stf-integration #+BEGIN_SRC lisp (destructuring-bind (op from to expression wrt) function (declare (ignore op)) (with-tex-output (format nil "{\\int_~A^~A ~A\\,\\mathrm{d}~A}" (convert-for-display from) (convert-for-display to) (convert-for-display expression) (convert-for-display wrt)))) #+END_SRC *** TODO Parenthesis :PROPERTIES: :CREATED: <2016-06-14 Tue 17:24> :ID: 93d643d6-2219-4c49-bba5-190520a6ff29 :END: #+Caption: Parenthesis #+Name: stf-parenthesis #+BEGIN_SRC lisp (destructuring-bind (op type expression) function (declare (ignore op)) (let* ((types '((square . ("[" . "]")) (curly . ("{" . "}")) (smooth . ("(" . ")")))) (left (cadr (assoc type types))) (right (cddr (assoc type types)))) (with-tex-output (format nil "{\\left~a {~a} \\right~a}" left (convert-for-display expression) right)))) #+END_SRC ** DONE Special Macros CLOSED: [2016-06-25 Sat 16:27] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:20> :ID: 56ca6afe-912a-4530-91e4-a63123dc6d9d :END: There is one specialty macro, ~with-tex-output~, which is used to ensure that an expression is wrapped to be a part of correct (La)TeX output. It works by checking to see whether or not the variable ~*tex-outputp*~ is true, if so, it simply pass through the given body, and if not, it binds the variable to ~t~, and makes sure that the given body is wrapped in ~$~, allowing the expression to be typeset correctly. #+Caption: Special Macros #+Name: stf-special-macros #+BEGIN_SRC lisp (defvar *tex-outputp* nil) (declaim (special *tex-outputp*)) (defmacro with-tex-output (&body body) `(if *tex-outputp* (progn ,@body) (let ((*tex-outputp* t)) (format nil "$~a$" (progn ,@body))))) #+END_SRC ** DONE Assembly CLOSED: [2016-06-24 Fri 21:34] :PROPERTIES: :CREATED: <2016-06-14 Tue 17:15> :ID: bbd15b88-8256-4b5b-abcc-4783fc096c29 :END: The final assembly of this portion of the system is as simple as the rest, resolving dependencies and placing everything in a single file. As normal, this is done using NoWeb syntax, with everything tangled to the file ~larcs-typeset.lisp~. #+Caption: Assemble Symbolic to Typeset Form #+Name: stf-assemble #+BEGIN_SRC lisp :tangle "larcs-typeset.lisp" (in-package #:larcs.typeset) <> <> <> <> <> #+END_SRC * WORKING Symbolic Solver [0/3] :noexport: :PROPERTIES: :CREATED: <2016-06-11 Sat 17:55> :ID: ffa664b6-e147-471c-9e97-f49c4619fc99 :END: ** TODO Techniques :PROPERTIES: :CREATED: <2016-06-11 Sat 17:55> :END: ** TODO Rules :PROPERTIES: :CREATED: <2016-06-11 Sat 17:56> :END: ** TODO Assembly :PROPERTIES: :CREATED: <2016-06-11 Sat 17:56> :END: * WORKING Symbolic Trigonometry [0/2] :noexport: :PROPERTIES: :CREATED: <2016-06-11 Sat 17:58> :ID: b0259b8c-e285-48ca-bda0-4f04e3bc6ef2 :END: ** TODO Rules :PROPERTIES: :CREATED: <2016-06-11 Sat 17:58> :END: ** TODO Assembly :PROPERTIES: :CREATED: <2016-06-11 Sat 17:58> :END: * WORKING Symbolic Evaluation of Limits [0/2] :noexport: :PROPERTIES: :CREATED: <2016-07-18 Mon 18:15> :END: ** TODO Rules :PROPERTIES: :CREATED: <2016-07-18 Mon 18:19> :END: ** TODO Assembly :PROPERTIES: :CREATED: <2016-07-18 Mon 18:20> :END: * WORKING Symbolic Integration [0/3] :noexport: :PROPERTIES: :CREATED: <2016-06-11 Sat 18:02> :ID: 61add971-a129-40d0-be13-24f8a4afc522 :END: ** TODO Rules :PROPERTIES: :CREATED: <2016-06-11 Sat 18:02> :END: ** TODO Techniques :PROPERTIES: :CREATED: <2016-06-11 Sat 18:02> :END: ** TODO Assembly :PROPERTIES: :CREATED: <2016-06-11 Sat 18:02> :END: * DONE Library Assembly [2/2] :PROPERTIES: :CREATED: <2016-06-11 Sat 22:30> :ID: 89370949-8f58-41cf-8c4f-92f81d48ac23 :END: LARCS is primarily a library, and as such, the formal interface for the library, and a way to load it must be provided. This is done here by defining packages centrally and defining an ASDF system to load the library quickly and easily. ** DONE Package Definitions [6/6] :PROPERTIES: :CREATED: <2016-06-13 Mon 15:00> :ID: 573a8352-8cbe-408c-8c27-3cf0b66da885 :END: As all of the packages are defined centrally, this makes resolving inter-package dependencies much easier and convenient. #+Caption: LARCS Packages #+Name: larcs-packages #+BEGIN_SRC lisp :tangle "larcs-packages.lisp" <> <> <> <> <> <> #+END_SRC *** DONE Common CLOSED: [2016-08-21 Sun 11:53] :PROPERTIES: :CREATED: <2016-08-05 Fri 22:07> :ID: 84845974-c272-4007-a490-6bc328a8d22d :END: This defines the common package, which keeps a few macros and variables that are used by all other packages. It exports a function to generate arguments lists, a list of special symbols to TeX sequences and a list of constant names. #+Caption: Common Package Definition #+Name: common-package-def #+BEGIN_SRC lisp (defpackage #:larcs.common (:use #:cl) (:import-from #:alexandria #:symbolicate) (:export #:gen-args-list #:*special-symbols-to-sequences* #:*constant-names* #:aget #:ensure-list #:evaluating-bind) (:nicknames #:common)) #+END_SRC *** DONE Classification CLOSED: [2016-08-21 Sun 12:03] :PROPERTIES: :CREATED: <2016-08-05 Fri 22:07> :ID: f68d9d69-3cca-4767-8204-8077ae8ac2b2 :END: Classification is another system that is used by just as many packages as the common packages. In this case, it exports two functions (one to get classification and one to check whether something is classified as a given classification) and a macro (the case pattern for classification). #+Caption: Classification Package Definition #+Name: classification-package-def #+BEGIN_SRC lisp (defpackage #:larcs.classify (:use #:cl #:larcs.common) (:import-from #:alexandria #:symbolicate) (:export #:classify #:classified-as-p #:classification-case) (:nicknames #:classify)) #+END_SRC *** DONE Polynomial Functions CLOSED: [2016-08-21 Sun 12:09] :PROPERTIES: :CREATED: <2016-08-21 Sun 10:58> :ID: c97b187c-22c8-4332-902e-3be2247b277e :END: Polynomial Functions are used in several of the other packages, and provide a way of comparing and retrieving information about specific terms, or providing a way to collect information about variables. #+Caption: Polynomial Package Definition #+Name: polynomial-package-def #+BEGIN_SRC lisp (defpackage #:larcs.polynomials (:use #:cl #:larcs.common #:larcs.classify) (:export #:collect-variables #:coefficient #:term-variable #:get-power #:term-order-< #:term-order-= #:term-order-> #:save-variable-p #:single-term-combinable-p) (:nicknames #:polynomials)) #+END_SRC *** DONE Manipulation CLOSED: [2016-08-21 Sun 12:21] :PROPERTIES: :CREATED: <2016-08-05 Fri 22:07> :ID: 07a9d8fc-5bdc-4c03-9df3-3e3d46d1b704 :END: This package provides for a method to manipulate and perform algebra symbolically. In a way, this is the core of the library, upon which nearly everything else is built. #+Caption: Manipulation Package Definition #+Name: manipulation-package-def #+BEGIN_SRC lisp (defpackage #:larcs.manipulate (:use #:cl #:larcs.common #:larcs.classify #:larcs.polynomials) (:import-from #:alexandria #:symbolicate) (:export #:manipulate #:collect-terms) (:nicknames #:manipulate)) #+END_SRC *** DONE Differentiation CLOSED: [2016-08-21 Sun 13:19] :PROPERTIES: :CREATED: <2016-08-05 Fri 22:07> :ID: 53a94c2e-3fb1-4cc1-9b3a-0e53657c3b91 :END: This is a rather simple package, providing a way to differentiate equations for use in a variety of functions. #+Caption: Differentiation Package Definition #+Name: differentiation-package-def #+BEGIN_SRC lisp (defpackage #:larcs.differentiate (:use #:cl #:larcs.common #:larcs.classify #:larcs.manipulate #:larcs.polynomials) (:import-from #:alexandria #:symbolicate) (:export :differentiate) (:nicknames :diff)) #+END_SRC *** DONE Typesetting CLOSED: [2016-08-21 Sun 13:35] :PROPERTIES: :CREATED: <2016-08-05 Fri 22:07> :ID: f3ae4f48-7fc9-4f4c-a128-642cd3babaf1 :END: Again, this is a relatively simple package definition, providing a way to convert symbolic equations to a form that can be more easily read by most humans. #+Caption: Typesetting Package Definition #+Name: typesetting-package-def #+BEGIN_SRC lisp (defpackage #:larcs.typeset (:use #:cl #:larcs.common #:larcs.classify #:larcs.manipulate #:larcs.polynomials) (:import-from #:alexandria #:symbolicate) (:export #:convert-for-display) (:nicknames #:typeset)) #+END_SRC ** DONE System Definition CLOSED: [2016-08-21 Sun 11:23] :PROPERTIES: :CREATED: <2016-06-13 Mon 15:00> :ID: 35b2ec01-a933-4b5b-af73-b6b7f1c45cb6 :END: This defines the LARCS Library system, allowing the functionality to be loaded by other systems or to provide a way to make development quickly and easily. #+Caption: Library System Definition #+Name: library-system-definition #+BEGIN_SRC lisp :tangle "larcs-lib.asd" (asdf:defsystem #:larcs-lib :description "A CAS Library for use within Lisp Software." :author "Samuel Flint " :license "GNU GPLv3 or Later" :depends-on (#:alexandria) :serial t :components ((:file "larcs-packages") (:file "larcs-common") (:file "larcs-classify") (:file "larcs-polynomials") (:file "larcs-manipulation") (:file "larcs-manipulators-addition") (:file "larcs-manipulators-subtraction") (:file "larcs-manipulators-multiplication") (:file "larcs-manipulators-division") (:file "larcs-manipulators-trig") (:file "larcs-differentiate") (:file "larcs-typeset"))) #+END_SRC * Push to bottom :ignore: :PROPERTIES: :CREATED: <2016-07-17 Sun 13:58> :END: #+LATEX: \newpage * Version Information :PROPERTIES: :CREATED: <2016-07-17 Sun 13:58> :UNNUMBERED: t :END: This document is version src_sh{git describe --always --long --dirty --abbrev=10 --tags}.