123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653 |
- # -*- mode: org -*-
- Archived entries from file /home/swflint/Projects/lisp-cas/lisp-cas.org
- * TODO Match Expressions
- :PROPERTIES:
- :ID: 39f69de5-6fcc-4ad4-984f-72fc0f77f11b
- :CREATED: <2016-06-11 Sat 22:20>
- :ARCHIVE_TIME: 2016-06-13 Mon 20:27
- :ARCHIVE_FILE: ~/Projects/lisp-cas/lisp-cas.org
- :ARCHIVE_OLPATH: Symbolic Differentiation/Expansions
- :ARCHIVE_CATEGORY: lisp-cas
- :ARCHIVE_TODO: TODO
- :END:
- To be able to apply an expansion, you need to determine eligibility. To do this, you need an expression that matches on two things, function name and arity. To generate this, it takes an operation name and the arity. Based on the arity type ($=$, $>$, $\leq$), it will construct a simple boolean statement in the format of $(function = operator) \land (argument-count == arity)$, where $==$ is one of the above arity types.
- #+Caption: Match Expressions
- #+Name: derive-match-expressions
- #+BEGIN_SRC lisp
- ;; (defun generate-match-expression (on arity &optional (type '=))
- ;; (check-type on symbol)
- ;; (check-type type (member = > >=))
- ;; (check-type arity (integer 0))
- ;; (case type
- ;; (=
- ;; `(and (eq function ',on)
- ;; (= arg-count ,arity)))
- ;; (>
- ;; `(and (eq function ',on)
- ;; (> arg-count ,arity)))
- ;; (>=
- ;; `(and (eq function ',on)
- ;; (>= arg-count ,arity)))))
- #+END_SRC
- * TODO Match Test
- :PROPERTIES:
- :ID: 9d165cb9-95f2-4006-a8a1-73a0750b2000
- :CREATED: <2016-04-30 Sat 16:19>
- :ARCHIVE_TIME: 2016-06-13 Mon 20:29
- :ARCHIVE_FILE: ~/Projects/lisp-cas/lisp-cas.org
- :ARCHIVE_OLPATH: Conversion from Symbolic Expressions to Typeset Display Formats/Matching And Generating
- :ARCHIVE_CATEGORY: lisp-cas
- :ARCHIVE_TODO: TODO
- :END:
- #+Caption: Generate Match Test
- #+Name: tex-gen-match-test
- #+BEGIN_SRC lisp
- ;; (defun generate-match-expression (op arity &optional (type '=))
- ;; (declare (symbol op type)
- ;; (integer arity))
- ;; (ecase type
- ;; (=
- ;; `(and (eq function ',op)
- ;; (= arg-count ,arity)))
- ;; (>
- ;; `(and (eq function ',op)
- ;; (> arg-count ,arity)))
- ;; (>=
- ;; `(and (eq function ',op)
- ;; (>= arg-count ,arity)))))
- #+END_SRC
- * WORKING Symbolic Differentiation [0/5]
- :PROPERTIES:
- :CREATED: <2016-06-09 Thu 09:21>
- :ID: 360bc5f4-39ac-4161-9326-00c3daaf368c
- :ARCHIVE_TIME: 2016-06-14 Tue 10:57
- :ARCHIVE_FILE: ~/Projects/lisp-cas/lisp-cas.org
- :ARCHIVE_CATEGORY: lisp-cas
- :ARCHIVE_TODO: WORKING
- :END:
- The calculation of derivatives has many uses. However, the calculation of derivatives can often be tedious. To make this faster, I've written the following program to make it faster.
- ** WORKING Expansions [0/3]
- CLOSED: [2016-06-09 Thu 09:22]
- :PROPERTIES:
- :CREATED: <2016-06-09 Thu 09:22>
- :END:
- This program works in terms of expansion functions, and application tests. That is to say, there is a test to see if the expansion is valid for the given expression.
- *** WORKING Definition
- :PROPERTIES:
- :ID: d7430ac9-cc9a-4942-a8c7-4d21c1705ad4
- :CREATED: <2016-06-11 Sat 22:20>
- :END:
- To define an expansion requires just a bit of syntactic sugar in the form of the ~defexpansion~ macro. This macro does 3 things, generate a test function, generate an expansion function and pushes the name of the expansion, the test function and the expansion function on to the rules list.
- To generate the test function, it uses the match-expression generator and wraps it into a function taking two arguments, a function and a list of arguments to the function. The test is then made, acting as predicate function for whether or not the expansion is applicable.
- To generate the expansion function, a series of expressions is used as the body of the function, with the function destructured to form the arguments.
- #+Caption: Expansion Definition
- #+Name: derive-expansion-definition
- #+BEGIN_SRC lisp
- (defmacro defexpansion (name (on arity &optional (type '=)) (&rest arguments) &body expansion)
- (let ((match-expression (generate-match-expression on arity type 'function 'arg-count))
- (test-name (symbolicate name '-test))
- (expansion-name (symbolicate name '-expansion)))
- `(progn
- (defun ,test-name (function &rest arguments &aux (arg-count (length arguments)))
- ,match-expression)
- (defun ,expansion-name (,@arguments)
- ,@expansion)
- (setf (aget *rules* ',name)
- (make-rule :name ',name
- :test-function #',test-name
- :expansion-function #',expansion-name))
- ',name)))
- #+END_SRC
- *** WORKING Retrieval
- :PROPERTIES:
- :ID: 71d8545b-d5d1-4179-a0b1-3539c8e68105
- :CREATED: <2016-06-11 Sat 22:20>
- :END:
- To allow for the use of expansions, you must be able to retrieve the correct one from the expansions list.
- To do so, you need the second element of the list that is the ~(name test expansion)~ for the rule. This is found by removing the expansions for which the test returns false for the given expression.
- #+Caption: Expansion Retrieval
- #+Name: derive-expansion-retrieval
- #+BEGIN_SRC lisp
- (defun get-expansion (expression)
- (rule-expansion-function (rest (first
- (remove-if-not #'(lambda (nte)
- (let ((test (rule-test-function (rest nte))))
- (apply test expression)))
- ,*rules*)))))
- #+END_SRC
- *** TODO Storage
- :PROPERTIES:
- :ID: 0cf2d0ad-cdd1-4a5e-a849-615961c2e869
- :CREATED: <2016-06-11 Sat 22:20>
- :END:
- One of the more important parts of the program is a way to store expansions. This is however, quite boring. It's just a global variable (~*rules*~), containing a list of lists having the form of ~(name test-lambda expander-lambda)~.
- #+Caption: Expansion Storage
- #+Name: derive-expansion-storage
- #+BEGIN_SRC lisp
- (defstruct (rule (:type list))
- name test-function expansion-function)
- (defvar *rules* '())
- #+END_SRC
- ** WORKING Rules [0/5]
- CLOSED: [2016-06-09 Thu 09:22]
- :PROPERTIES:
- :CREATED: <2016-06-09 Thu 09:22>
- :END:
- There are many rules for derivation of equations. These rules allow one to derive equations quickly and easily by matching equations up with relevant rules and applying those rules.
- *** TODO Multiplication
- :PROPERTIES:
- :ID: 15f0ba68-9335-4d97-b3c7-418187895706
- :CREATED: <2016-06-11 Sat 22:21>
- :END:
- The derivatives of multiplication follows two rules, the Constant Multiple rule:
- \[ \frac{d}{dx} cf(x) = c \cdot f^\prime(x) ,\]
- which is a specialized version of the more generalized Product Rule:
- \[ \frac{d}{dx} f(x) \cdot g(x) = f(x) \cdot g^\prime(x) + g(x) \cdot f^\prime(x) .\]
- There are two forms of the Product Rule as implemented, both matching on the ~*~ function, but taking a different number of arguments. The first takes 2 arguments, and is the main driver for derivation, following the two above rules. The second takes 3 or more, and modifies the arguments slightly so as to make it a derivative of two different equations.
- #+Caption: Rules for Multiplication
- #+Name: derive-multiplication
- #+BEGIN_SRC lisp
- (defexpansion mult/2 (* 2) (first second)
- (cond
- ((numberp first)
- `(* ,first ,(derive (ensure-list second))))
- ((numberp second)
- `(* ,second ,(derive (if (listp first) first (list second)))))
- (t
- `(+ (* ,first ,(derive (ensure-list second)))
- (* ,second ,(derive (ensure-list first)))))))
- (defexpansion mult/3+ (* 3 >=) (first &rest rest)
- (derive `(* ,first ,(cons '* rest))))
- #+END_SRC
- *** TODO Division
- :PROPERTIES:
- :ID: 483285d3-f035-4b50-9f3f-4389d01b7504
- :CREATED: <2016-06-11 Sat 22:21>
- :END:
- Division follows the Quotient Rule, which is as follows:
- \[ \frac{d}{dx} \frac{f(x)}{g(x)} = \frac{f^\prime(x) \cdot g(x) - g^\prime(x) \cdot f(x)}{(g(x))^2} .\]
- The rule matches on the ~/~ function, and takes 2 arguments, a numerator and a denominator, its expansion is as above.
- #+Caption: Rules for Division
- #+Name: derive-division
- #+BEGIN_SRC lisp
- (defexpansion div/2 (/ 2) (numerator denominator)
- `(/ (- (* ,numerator ,(derive (ensure-list denominator)))
- (* ,denominator ,(derive (ensure-list numerator))))
- (expt ,denominator 2)))
- #+END_SRC
- *** TODO Addition/Subtraction
- :PROPERTIES:
- :ID: b4f6b80a-0904-491a-a0ca-850dcb6809c5
- :CREATED: <2016-06-11 Sat 22:21>
- :END:
- Addition and subtraction of functions in derivatives is simple, simply add or subtract the derivatives of the functions, as shown here:
- \[ \frac{d}{dx} f_1(x) + f_2(x) + \cdots + f_n(x) = f_1^\prime(x) + f_2^\prime(x) + \cdots + f_n^\prime(x) \]
- and here:
- \[ \frac{d}{dx} f_1(x) - f_2(x) - \cdots - f_n(x) = f_1^\prime(x) - f_2^\prime(x) - \cdots - f_n^\prime(x) .\]
- This is accomplished by matching on either ~+~ or ~-~, and taking 2 or more arguments, deriving all of the passed in equations and applying the respective operation.
- #+Caption: Rules for Addition and Subtraction
- #+Name: derive-addition-subtraction
- #+BEGIN_SRC lisp
- (defexpansion plus/2+ (+ 2 >=) (&rest clauses)
- `(+ ,@(map 'list #'(lambda (clause)
- (if (listp clause)
- (derive clause)
- (derive (list clause))))
- clauses)))
- (defexpansion minus/2+ (- 2 >=) (&rest clauses)
- `(- ,@(map 'list #'(lambda (clause)
- (if (listp clause)
- (derive clause)
- (derive (list clause))))
- clauses)))
- #+END_SRC
- *** TODO Exponentials and Logarithms
- :PROPERTIES:
- :ID: eaed7558-82d0-4300-8e5f-eb48a06d4e64
- :CREATED: <2016-06-11 Sat 22:21>
- :END:
- The derivatives of exponential and logarithmic functions follow several rules. For $e^x$ or $a^x$, the "Xerox" rule is used:
- \[ \frac{d}{dx} e^x = e^x ,\]
- and
- \[ \frac{d}{dx} a^x = a^x \cdot \ln x .\]
- Logarithmic functions follow the forms as shown:
- \[ \frac{d}{dx} \ln x = \frac{x^\prime}{x} ,\]
- and
- \[ \frac{d}{dx} \log_b x = \frac{x^\prime}{\ln b \cdot x} .\]
- However, equations of the form $x^n$ follow this form (The Power Rule):
- \[ \frac{d}{dx} x^n = x^\prime \cdot n \cdot x^{n-1} .\]
- The following rules match based on the appropriate Lisp functions and the number of arguments taken based on whether or not you are performing natural or unnatural operations.
- #+Caption: Rules for Exponentials and Logarithms
- #+Name: derive-exponentials-logarithms
- #+BEGIN_SRC lisp
- (defexpansion exp/1 (exp 1) (expression)
- (if (listp expression)
- `(* (exp ,expression) ,(derive expression))
- (if (numberp expression)
- 0
- `(exp ,expression))))
- (defexpansion expt/2 (expt 2) (base exponent)
- (if (numberp exponent)
- (if (listp base)
- `(* ,exponent (expt ,base ,(1- exponent)) ,(derive base))
- `(* ,exponent (expt ,base ,(1- exponent))))
- `(* (expt ,base ,exponent) (log ,base))))
- (defexpansion log/1 (log 1) (expression)
- `(/ ,(derive (ensure-list expression)) ,expression))
- (defexpansion log/2 (log 2) (number base)
- (declare (ignorable number base))
- `(/ ,(derive (cons 'log number)) (* (log ,base) ,number)))
- #+END_SRC
- *** TODO Trigonometric
- :PROPERTIES:
- :ID: c0f40e80-8a19-4749-bc9b-b1e94ef6949a
- :CREATED: <2016-06-11 Sat 22:21>
- :END:
- The derivation of trigonometric functions is simply the application of the chain rule. As such, each of the trig functions has a different derivative, as shown here:
- \[ \frac{d}{dx} \sin x = x^\prime \cdot \cos x ,\]
- \[ \frac{d}{dx} \cos x = x^\prime \cdot -\sin x ,\]
- \[ \frac{d}{dx} \tan x = x^\prime \cdot \sec^2 x ,\]
- \[ \frac{d}{dx} \csc x = x^\prime \cdot -\csc x \cdot \cot x ,\]
- \[ \frac{d}{dx} \sec x = x^\prime \cdot \sec x \cdot \tan x ,\]
- and
- \[ \frac{d}{dx} \cot x = x^\prime \cdot -\csc^2 x .\]
- These rules all match on their respective trig function and substitute as appropriate.
- #+Caption: Rules for Trigonometric Functions
- #+Name: derive-trigonometrics
- #+BEGIN_SRC lisp
- (defexpansion sin/1 (sin 1) (arg)
- `(* (cos ,arg) ,(derive (ensure-list arg))))
- (defexpansion cos/1 (cos 1) (arg)
- `(* (- (sin ,arg)) ,(derive (ensure-list arg))))
- (defexpansion tan/1 (tan 1) (arg)
- `(* (expt (sec ,arg) 2) ,(derive (ensure-list arg))))
- (defexpansion csc/1 (csc 1) (arg)
- `(* (- (csc ,arg)) (cot ,arg) ,(derive (ensure-list arg))))
- (defexpansion sec/1 (sec 1) (arg)
- `(* (sec ,arg) (tan ,arg) ,(derive (ensure-list arg))))
- (defexpansion cot/1 (cot 1) (arg)
- `(* (- (expt (csc ,arg) 2)) ,(derive (ensure-list arg))))
- #+END_SRC
- ** TODO Derivative Driver
- :PROPERTIES:
- :ID: b03c5070-602a-412e-a6ce-3dda65630153
- :CREATED: <2016-06-09 Thu 09:22>
- :END:
- This function is probably the most important user-facing function in the package.
- Derive takes a list, and based on the first element in the list, and the length of the list, it will do one of the following things:
- - Number :: Return 0, the derivative of a number is 0, except in certain cases listed above.
- - Symbol, and length is 1 :: This is a variable. Return 1, $\frac{d}{dx}x=1$.
- - Expansion Function Available :: There is an expansion rule, use this to derive the equation.
- - No Expansion Rule :: Signal an error, equation was likely malformed.
- #+Caption: Derivative Driver
- #+Name: derive-derivative-driver
- #+BEGIN_SRC lisp
- (defun derive (function)
- (check-type function cons)
- (let ((op (first function)))
- (cond
- ((numberp op)
- 0)
- ((and (symbolp op)
- (= 1 (length function)))
- 1)
- (t
- (let ((expansion-function (get-expansion function)))
- (if (functionp expansion-function)
- (apply expansion-function (rest function))
- (error "Undefined expansion: ~a" op)))))))
- #+END_SRC
- ** TODO Miscellaneous Functions
- :PROPERTIES:
- :ID: 41439f82-466f-46a5-b706-df43e5f23650
- :CREATED: <2016-06-09 Thu 09:22>
- :END:
- As Common Lisp does not have cosecant or secant functions, and they appear in the definitions of the derivatives of some trigonometric functions, I define them here as follows:
- \[ \csc x = \frac{1}{\sin x} \]
- \[ \sec x = \frac{1}{\cos x} \]
- I also take the liberty of defining two macros, a ~define-equation-functions~ macro and ~take-derivative~. The first defines two functions, one that is the original equation, and the second being the derivative of the original equation. The ~take-derivative~ macro does simply that, but allows you to write the equation without having to quote it, providing a little bit of syntactic sugar.
- #+Caption: Miscellaneous Functions
- #+Name: derive-misc-functions
- #+BEGIN_SRC lisp
- (defun csc (x)
- "csc -- (csc x)
- Calculate the cosecant of x"
- (/ (sin x)))
- (defun sec (x)
- "sec -- (sec x)
- Calculate the secant of x"
- (/ (cos x)))
- (defmacro define-equation-functions (name variable equation)
- (let ((derivative-name (symbolicate 'd/d- variable '- name))
- (derivative (derive equation)))
- `(progn
- (defun ,name (,variable)
- ,equation)
- (defun ,derivative-name (,variable)
- ,derivative))))
- (defmacro take-derivative (equation)
- (let ((derivative (derive equation)))
- `',derivative))
- #+END_SRC
- ** TODO Assembly
- :PROPERTIES:
- :ID: e15262d2-23d5-4306-a68b-387a21265b6e
- :CREATED: <2016-06-09 Thu 09:22>
- :END:
- Now that the functions, macros and rules are defined, it's time to put them together into a package. This package has only one dependency, Common Lisp itself, and exports the following five symbols: ~derive~, ~csc~, ~sec~, ~define-equation-functions~ and ~take-derivative~.
- #+Caption: Packaging
- #+Name: derive-packaging
- #+BEGIN_SRC lisp :tangle "larcs-derive.lisp"
- (in-package #:larcs.derive)
- <<derive-expansion-storage>>
- <<derive-expansion-retrieval>>
- <<derive-match-expressions>>
- <<derive-expansion-definition>>
- <<derive-derivative-driver>>
- <<derive-multiplication>>
- <<derive-division>>
- <<derive-addition-subtraction>>
- <<derive-exponentials-logarithms>>
- <<derive-trigonometrics>>
- <<derive-misc-functions>>
- #+END_SRC
- * WORKING Symbolic Form to Typeset [0/5]
- :PROPERTIES:
- :CREATED: <2016-06-09 Thu 09:23>
- :ID: ed9f4311-bf9f-42df-8f46-254658b93c10
- :ARCHIVE_TIME: 2016-06-14 Tue 19:10
- :ARCHIVE_FILE: ~/Projects/lisp-cas/lisp-cas.org
- :ARCHIVE_CATEGORY: lisp-cas
- :ARCHIVE_TODO: WORKING
- :END:
- The goal of this portion of the CAS is to produce \LaTeX{} formulae that can be inserted into a document for whatever reason, and it does so using rewrite rules, this time, rewriting s-expressions (~(+ (* 3 (expt x 3)) (expt x 2) (* 4 x) 22)~) to the \LaTeX{} equivalent, ~${{{{3} \cdot {{x ^ {3}}}}} + {{x ^ {2}}} + {{{4} \cdot {x}}} + {22}}$~ (${{{{3} \cdot {{x ^ {3}}}}} + {{x ^ {2}}} + {{{4} \cdot {x}}} + {22}}$).
- ** WORKING Matching And Generating [0/3]
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 16:19>
- :END:
- *** TODO Define Rule
- :PROPERTIES:
- :ID: d4f77ac3-a059-4fb6-b936-1b9e972646ee
- :CREATED: <2016-04-30 Sat 16:19>
- :END:
- #+Caption: Define Matching Rule
- #+Name: tex-def-match-rule
- #+BEGIN_SRC lisp
- (defmacro defrule (name (on arity &optional type) (&rest arguments) &body rule)
- (let ((match-expression (generate-match-expression on arity type 'function 'arg-count))
- (test-name (symbolicate name '-test))
- (expansion-name (symbolicate name '-expansion)))
- `(progn
- (defun ,test-name (function &rest arguments &aux (arg-count (length arguments)))
- ,match-expression)
- (defun ,expansion-name (,@arguments)
- ,@rule)
- (setf (aget *rules* ',name)
- (make-rule :name ',name
- :test-function #',test-name
- :expansion-function #',expansion-name))
- ',name)))
- #+END_SRC
- *** TODO Store Rules
- :PROPERTIES:
- :ID: 002ea704-4286-429f-9149-0f29fb73c503
- :CREATED: <2016-04-30 Sat 16:19>
- :END:
- #+Caption: Rule Storage
- #+Name: tex-rule-storage
- #+BEGIN_SRC lisp
- (defstruct (rule (:type list))
- name test-function expansion-function)
- (defvar *rules* '())
- #+END_SRC
- *** TODO Retrieve Rule
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 15:25>
- :ID: e3f34100-d0a5-4039-8b9d-115cfcb0804e
- :END:
- #+Caption: Retrieve Rule
- #+Name: tex-retrieve-rule
- #+BEGIN_SRC lisp
- (defun get-expansion (expression)
- (rule-expansion-function (rest
- (first
- (remove-if-not #'(lambda (nte)
- (let ((test (rule-test-function (rest nte))))
- (apply test expression)))
- ,*rules*)))))
- #+END_SRC
- ** WORKING Rules [0/10]
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 16:19>
- :END:
- *** TODO Multiplication
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 16:19>
- :ID: 5417a6bf-f265-418a-984b-6bfd14b79a80
- :END:
- #+Caption: Multiplication Rule
- #+Name: tex-multiplication-rule
- #+BEGIN_SRC lisp
- (defrule multiplication (* 2 >=) (&rest elements)
- (format nil "{~{{~a}~^ \\cdot ~}}"
- (map 'list #'convert-to-tex
- (map 'list #'ensure-list
- elements))))
- #+END_SRC
- *** TODO Division
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 16:19>
- :ID: 056aa99c-f2b9-4ab6-99ba-bfb87e3baed5
- :END:
- #+Caption: Division Rule
- #+Name: tex-division-rule
- #+BEGIN_SRC lisp
- (defrule division (/ 2 =) (a b)
- (format nil "{\\frac{~a}{~a}}"
- (convert-to-tex (ensure-list a))
- (convert-to-tex (ensure-list b))))
- #+END_SRC
- *** TODO Addition
- :PROPERTIES:
- :ID: 68f3dac3-9f0a-4fee-8da6-a39f4491f3ce
- :CREATED: <2016-04-30 Sat 16:19>
- :END:
- #+Caption: Rule for addition
- #+Name: tex-addition-rule
- #+BEGIN_SRC lisp
- (defrule addition (+ 2 >=) (&rest elements)
- (format nil "{~{{~a}~^ + ~}}"
- (map 'list #'convert-to-tex
- (map 'list #'ensure-list
- elements))))
- #+END_SRC
- *** TODO Subtraction
- :PROPERTIES:
- :ID: 9a908130-af5e-4c87-bb07-13bd66c35fcf
- :CREATED: <2016-04-30 Sat 16:19>
- :END:
- #+Caption: Subtraction Rule
- #+Name: tex-subtraction-rule
- #+BEGIN_SRC lisp
- (defrule subtraction (- 2 >=) (&rest elements)
- (format nil "{~{{~a}~^ - ~}}"
- (map 'list #'convert-to-tex
- (map 'list #'ensure-list
- elements))))
- #+END_SRC
- *** TODO Exponentials and Logarithmics
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 16:19>
- :ID: 269dc47f-5062-4081-a08e-d50188af6a57
- :END:
- #+Caption: Exponentials and Logarithms
- #+Name: tex-exponentials-and-logarithms
- #+BEGIN_SRC lisp
- (defrule exp (exp 1 =) (expression)
- (format nil "{e^{~a}}"
- (convert-to-tex (ensure-list expression))))
- (defrule expt (expt 2 =) (base exponent)
- (format nil "{~a ^ {~a}}"
- (convert-to-tex (ensure-list base))
- (convert-to-tex (ensure-list exponent))))
- (defrule natlog (log 1 =) (expression)
- (format nil "{\\ln {~a}}"
- (convert-to-tex (ensure-list expression))))
- (defrule logarithm (log 2 =) (expression base)
- (format nil "{\\log_{~a}~a}"
- (convert-to-tex (ensure-list base))
- (convert-to-tex (ensure-list expression))))
- #+END_SRC
- *** TODO Trigonometrics
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 16:19>
- :ID: 837806c9-7174-43a3-80b2-355b645d46ed
- :END:
- #+Caption: Trigonometric Functions
- #+Name: tex-trigonometrics
- #+BEGIN_SRC lisp
- (defrule sin (sin 1 =) (arg)
- (format nil "{\\sin {~a}}"
- (convert-to-tex (ensure-list arg))))
- (defrule cos (cos 1 =) (arg)
- (format nil "{\\cos {~a}}"
- (convert-to-tex (ensure-list arg))))
- (defrule tan (tan 1 =) (arg)
- (format nil "{\\tan {~a}}"
- (convert-to-tex (ensure-list arg))))
- (defrule csc (csc 1 =) (arg)
- (format nil "{\\csc {~a}}"
- (convert-to-tex (ensure-list arg))))
- (defrule sec (sec 1 =) (arg)
- (format nil "{\\sec {~a}}"
- (convert-to-tex (ensure-list arg))))
- (defrule cot (cot 1 =) (arg)
- (format nil "{\\cot {~a}}"
- (convert-to-tex (ensure-list arg))))
- #+END_SRC
- *** TODO Logic
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 18:29>
- :ID: 74d12931-343f-4982-945d-738a3e38a1db
- :END:
- #+Caption: Logic Rules
- #+Name: tex-logic-rules
- #+BEGIN_SRC lisp
- (defrule and (and 2 >=) (&rest elements)
- (format nil "{~{{~a}~^ \\wedge ~}}"
- (map 'list #'convert-to-tex
- (map 'list #'ensure-list elements))))
- (defrule or (or 2 >=) (&rest elements)
- (format nil "{~{{~a}~^ \\vee ~}}"
- (map 'list #'convert-to-tex
- (map 'list #'ensure-list elements))))
- (defrule not (not 1 =) (&rest elements)
- (format nil "{\\not {~a}}"
- (map 'list #'convert-to-tex
- (map 'list #'ensure-list elements))))
- #+END_SRC
- *** TODO Equality
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 18:29>
- :ID: f75273d2-d523-4404-925b-af6fd01c7520
- :END:
- #+Caption: Equality Rules
- #+Name: tex-equality-rules
- #+BEGIN_SRC lisp
- (defrule = (= 2 =) (lhs rhs)
- (format nil "{{~a} = {~a}}"
- (convert-to-tex (ensure-list lhs))
- (convert-to-tex (ensure-list rhs))))
- #+END_SRC
- *** TODO Summation and Integration
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 18:30>
- :ID: dda2827a-cee5-4efc-bd9a-4dd953829b5c
- :END:
- #+Caption: Summation and Integration
- #+Name: tex-summation-and-integration
- #+BEGIN_SRC lisp
- (defrule sum (sum 3 =) (start stop expression)
- (format nil "{\\sum_{~a}^{~a} {~a}}"
- (convert-to-tex (ensure-list start))
- (convert-to-tex (ensure-list stop))
- (convert-to-tex (ensure-list expression))))
- (defrule integrate (integrate 4 =) (from to expression wrt)
- (format nil "{\\int_{~a}^{~a} ~a\\,\mathrm{d}~a}"
- (convert-to-tex (ensure-list from))
- (convert-to-tex (ensure-list to))
- (convert-to-tex (ensure-list expression))
- (convert-to-tex (ensure-list wrt))))
- #+END_SRC
- *** TODO Specialty
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 18:30>
- :ID: f4e6b309-289d-4b32-bc55-4740ec86a113
- :END:
- #+Caption: Specialty
- #+Name: tex-specialty
- #+BEGIN_SRC lisp
- (defrule parens (parens 2 =) (type inside)
- (let* ((types '((square . ("[" . "]"))
- (curly . ("{" . "}"))
- (smooth . ("(" . ")"))))
- (left (cadr (assoc type types)))
- (right (cddr (assoc type types))))
- (format nil "{\\left~a {~a} \\right~a}"
- left
- (convert-to-tex (ensure-list inside))
- right)))
- #+END_SRC
- ** TODO Conversion Driver
- :PROPERTIES:
- :ID: b395bdb7-7b98-49a1-b6d6-4256fb40d4fa
- :CREATED: <2016-04-30 Sat 16:19>
- :END:
- #+Caption: Conversion Driver
- #+Name: tex-conversion-driver
- #+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)))))
- (defun convert-to-tex (function)
- (check-type function cons)
- (let ((op (first function)))
- (with-tex-output
- (cond
- ((numberp op)
- (format nil "~a" op))
- ((and (symbolp op)
- (= 1 (length function)))
- (let ((symbol-pair (assoc op *special-symbols-to-sequences*)))
- (if (null symbol-pair)
- (string-downcase op)
- (cdr symbol-pair))))
- (t
- (let ((expansion-function (get-expansion function)))
- (if (functionp expansion-function)
- (apply expansion-function (rest function))
- (error "Undefined expansion for operation: ~a." op))))))))
- #+END_SRC
- ** TODO Miscellaneous Functions
- :PROPERTIES:
- :CREATED: <2016-04-30 Sat 16:09>
- :ID: a4ab8a72-0b09-453c-b936-2470d5429c05
- :END:
- #+Caption: Misc Functions
- #+Name: tex-misc-functions
- #+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")))
- #+END_SRC
- ** TODO Assembly
- :PROPERTIES:
- :ID: fdef3016-cb12-43ad-ba5f-14dd6ccd973c
- :CREATED: <2016-04-30 Sat 16:25>
- :END:
- #+Caption: Packaging
- #+Name: tex-packaging
- #+BEGIN_SRC lisp :tangle "larcs-tex.lisp"
- (in-package #:larcs.to-tex)
- <<tex-misc-functions>>
- <<tex-rule-storage>>
- <<tex-gen-match-test>>
- <<tex-def-match-rule>>
- <<tex-retrieve-rule>>
- <<tex-conversion-driver>>
- <<tex-addition-rule>>
- <<tex-subtraction-rule>>
- <<tex-multiplication-rule>>
- <<tex-division-rule>>
- <<tex-exponentials-and-logarithms>>
- <<tex-trigonometrics>>
- <<tex-logic-rules>>
- <<tex-equality-rules>>
- <<tex-summation-and-integration>>
- <<tex-specialty>>
- #+END_SRC
- * TODO Manipulator Miscellaneous Functions
- :PROPERTIES:
- :CREATED: <2016-05-03 Tue 15:38>
- :ID: 20450528-d763-4c14-a085-5ac54d4d4b85
- :ARCHIVE_TIME: 2016-06-27 Mon 18:44
- :ARCHIVE_FILE: ~/Projects/lisp-cas/lisp-cas.org
- :ARCHIVE_OLPATH: Algebraic Manipulation/Expression Manipulators
- :ARCHIVE_CATEGORY: lisp-cas
- :ARCHIVE_TODO: TODO
- :END:
- This defines the ~*manipulator-map*~, where the manipulators for various functions are stored, and defines a function to generate an arguments list given a count of arguments.
- #+Caption: Misc Manipulator Functions
- #+Name: am-misc-manipulator-functions
- #+BEGIN_SRC lisp
- (defvar *manipulator-map* '())
- #+END_SRC
- * TODO Match Expression Generation
- :PROPERTIES:
- :CREATED: <2016-06-13 Mon 17:18>
- :ID: f7876b1d-3b67-48c1-863a-85e1b3026ed6
- :ARCHIVE_TIME: 2016-08-05 Fri 21:47
- :ARCHIVE_FILE: ~/Projects/lisp-cas/lisp-cas.org
- :ARCHIVE_OLPATH: Common Functionality
- :ARCHIVE_CATEGORY: lisp-cas
- :ARCHIVE_TODO: TODO
- :END:
- To be able to apply an expansion, you need to determine eligibility. To do this, you need an expression that matches on two things, function name and arity. To generate this, it takes an operation name and the arity. Based on the arity type ($=$, $>$, $\leq$), it will construct a simple boolean statement in the format of $(function = operator) \land (argument-count == arity)$, where $==$ is one of the above arity types.
- #+Caption: Match Expression Generation
- #+Name: common-match-expression-generation
- #+BEGIN_SRC lisp
- (defun generate-match-expression (on arity &optional (type '=) (function-var 'function) (arg-count-var 'arg-count))
- (check-type on symbol)
- (check-type type (member = > >=))
- (check-type arity (integer 0))
- (case type
- (=
- `(and (eq ,function-var ',on)
- (= ,arg-count-var ,arity)))
- (>
- `(and (eq ,function-var ',on)
- (> ,arg-count-var ,arity)))
- (>=
- `(and (eq ,function-var ',on)
- (>= ,arg-count-var ,arity)))))
- #+END_SRC
- * WORKING Common Functionality [3/6]
- :PROPERTIES:
- :CREATED: <2016-06-11 Sat 22:23>
- :ID: f153a0fe-ec04-47b1-bdc5-290cc62bc985
- :ARCHIVE_TIME: 2019-01-05 Sat 16:55
- :ARCHIVE_FILE: ~/Projects/larcs/larcs.org
- :ARCHIVE_CATEGORY: larcs
- :ARCHIVE_TODO: WORKING
- :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)
- <<common-generate-an-args-list>>
- <<constants-and-greeks>>
- <<aget>>
- <<ensure-list>>
- <<evaluating-bind>>
- #+END_SRC
- * WORKING Symbolic To Typeset Form [0/5]
- :PROPERTIES:
- :CREATED: <2016-06-14 Tue 17:13>
- :ID: 75f65e8a-0cc9-477f-b5e9-3c563fe7ef5c
- :ARCHIVE_TIME: 2019-01-05 Sat 16:56
- :ARCHIVE_FILE: ~/Projects/larcs/larcs.org
- :ARCHIVE_CATEGORY: larcs
- :ARCHIVE_TODO: WORKING
- :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.
- ** WORKING Rule Management [0/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.
- *** TODO Define Rules
- :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
- *** TODO Rule Retrieval
- :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 [0/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
- <<stf-numerics>>
- <<stf-variables>>
- <<stf-polynomial-terms>>
- <<stf-multiplicatives>>
- <<stf-rationals>>
- <<stf-additives>>
- <<stf-subtractives>>
- <<stf-trigonometrics>>
- <<stf-exponentials-logarithmics>>
- #+END_SRC
- *** TODO Numbers
- :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
- *** TODO Variables
- :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
- *** TODO Polynomial Terms
- :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
- *** TODO Multiplicatives
- :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)
- <<stf-and-operator>>
- )
- ((eq operator 'or)
- <<stf-or-operator>>
- )
- ((eq operator 'not)
- <<stf-not-operator>>
- )
- ((eq operator '=)
- <<stf-equality-operator>>
- )
- ((eq operator 'sum)
- <<stf-summation>>
- )
- ((eq operator 'integrate)
- <<stf-integration>>
- )
- ((eq operator 'parens)
- <<stf-parenthesis>>
- )))
- (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
- ** TODO Special Macros
- :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
- ** TODO Assembly
- :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)
- <<stf-special-macros>>
- <<stf-rule-retrieval>>
- <<stf-define-rule>>
- <<stf-conversion-driver>>
- <<stf-rules>>
- #+END_SRC
|