Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'src/current/include/calc-display.xsl')
-rw-r--r--src/current/include/calc-display.xsl702
1 files changed, 702 insertions, 0 deletions
diff --git a/src/current/include/calc-display.xsl b/src/current/include/calc-display.xsl
new file mode 100644
index 0000000..4f9f0fa
--- /dev/null
+++ b/src/current/include/calc-display.xsl
@@ -0,0 +1,702 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Handles calculation output in LaTeX format for styling by Mathjax
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:lv="http://www.lovullo.com/rater"
+ xmlns:c="http://www.lovullo.com/calc"
+ xmlns:preproc="http://www.lovullo.com/rater/preproc">
+
+
+<!--
+ Recursively apply any child equations and then do the same in calc-after mode
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:*" mode="calc-recurse">
+ <xsl:apply-templates select="./c:*" />
+
+ <!-- invoke `after' templates, which allows inserting data for display after
+ the initial equation -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style sum of values as a LaTeX equation
+
+ Note that this does not deal with the summation of a series; that's left to
+ the handling of the @of attribute.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:sum">
+ <xsl:apply-templates select="." mode="sum-body" />
+</xsl:template>
+
+<xsl:template match="c:sum" mode="sum-body">
+ <xsl:for-each select="./c:*">
+ <!-- get value to display -->
+ <xsl:variable name="display">
+ <xsl:apply-templates select="." />
+ </xsl:variable>
+
+ <!-- delimit with +s if not first; if we're adding a negative, omit the
+ addition symbol as well (unless we're displaying a product, since
+ multiplying by a negative would otherwise appear to be subtraction) -->
+ <xsl:if test="
+ ( position() > 1 )
+ and (
+ not( substring( $display, 1, 1 ) = '-' )
+ or ( local-name() = 'product' )
+ )
+ ">
+
+ <xsl:text> + </xsl:text>
+ </xsl:if>
+
+ <!-- the only reason we would have a sum within a sum (that doesn't use
+ sigma-notation) is for grouping -->
+ <xsl:if test="( local-name() = 'sum' ) and not( @of )">
+ <xsl:text>\left(</xsl:text>
+ </xsl:if>
+
+ <xsl:copy-of select="$display" />
+
+ <xsl:if test="( local-name() = 'sum' ) and not( @of )">
+ <xsl:text>\right)</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+
+ <!-- since we looped manually, we must also invoke `after' templates
+ manually -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style summation of a set as a LaTeX equation
+
+ Note that @of deals witht summation of sets only (rather, using the index of a
+ set to sum over the provided calculation). See the other template(s) for
+ summing values without a set.
+
+ An index may optionally be provided via an @index attribute; otherwise, one
+ will be chosen for you. The index is used for the lower limit; the upper limit
+ is omitted. The child nodes are then used to generate the equation to be
+ applied by the summation.
+
+ If no child nodes are provided, then the summation is meant to imply that each
+ value in the set should be summed. Adding child nodes overrides this behavior.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:sum[@of]">
+ <xsl:variable name="of" select="@of" />
+
+ <!-- if no index is provided, simply use its symbol to indicate all values
+ within its domain -->
+ <xsl:variable name="index">
+ <xsl:choose>
+ <xsl:when test="@index">
+ <xsl:value-of select="@index" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- TODO: Determine an index that is not in use -->
+ <xsl:text>k</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:variable name="ref">
+ <xsl:value-of select="@of" />
+ </xsl:variable>
+
+ <!-- retrieve the symbol associated with this value (no index) -->
+ <xsl:variable name="symbol">
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="$ref" />
+ <xsl:with-param name="search" select="/" />
+ </xsl:call-template>
+ </xsl:variable>
+
+ <!-- also retrieve the symbol without its index -->
+
+ <!-- if an index was provided, set the lower limit to 0 (we do this in a
+ separate variable so that we can display the symbol on its own elsewhere)
+ -->
+ <xsl:variable name="index-limit">
+ <xsl:value-of select="$index" />
+
+ <!-- we only need the explicit notation if we are summing more than the
+ set -->
+ <xsl:if test="./c:*">
+ <xsl:text>=0</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:text>\sum \limits_{</xsl:text>
+ <xsl:value-of select="$index-limit" />
+ <xsl:text>}</xsl:text>
+
+ <!-- upper limit is only necessary for clarification if they have provided a
+ more complex expression; if we're only summing over a single set, then
+ the extra notation is unnecessary and will just clutter -->
+ <xsl:if test="./c:*">
+ <!-- the upper limit of the summation will be denoted by #S, where S is the
+ symbol for a given set -->
+ <xsl:text>^{\grave\#</xsl:text>
+ <xsl:copy-of select="$symbol" />
+ <xsl:text>}</xsl:text>
+ </xsl:if>
+
+ <!-- if no children are provided, just sum @of -->
+ <xsl:if test="not(./c:*)">
+ <!-- output the symbol followed by its index, only if an index was provided
+ (and is therefore necessary) -->
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="$ref" />
+ <xsl:with-param name="index-symbol" select="$index" />
+ <xsl:with-param name="search" select="/" />
+ </xsl:call-template>
+ </xsl:if>
+
+ <!-- output any additional expressions, if any -->
+ <xsl:apply-templates select="." mode="sum-body" />
+</xsl:template>
+
+
+<!--
+ Style product of values as a LaTeX equation
+
+ Note that this does not deal with the product of a series; that's left to
+ the handling of the @of attribute (TODO: @of not yet implemented for
+ products).
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:product">
+ <xsl:variable name="enclose" select="
+ @dot='true'
+ and (
+ preceding-sibling::c:*
+ or following-sibling::c:*
+ )
+ " />
+
+ <xsl:if test="$enclose">
+ <xsl:text>(</xsl:text>
+ </xsl:if>
+
+ <xsl:for-each select="./c:*">
+ <!-- Function symbols can have multiple chars, so we'll need to add the
+ multiplication symbol. Adjacent constants should also be separated by a
+ dot, otherwise it'll look like one giant number. -->
+ <xsl:if test="
+ (
+ local-name() = 'apply'
+ or ../@dot = 'true'
+ or (
+ ( local-name() = 'const' )
+ and ( local-name( preceding-sibling::*[1] ) = 'const' )
+ )
+ )
+ and ( position() > 1 )
+ ">
+ <xsl:text> \,\cdot\, </xsl:text>
+ </xsl:if>
+
+ <!-- if precedence of this operation is lower, we will need to include
+ parenthesis -->
+ <!-- XXX: Relies on hard-coded precedence rules in multiple locations;
+ refactor! -->
+ <xsl:if test="
+ ( local-name() = 'sum' )
+ or ( ( local-name() = 'product' ) and not( @of ) )
+ ">
+ <xsl:text>\left(</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="." />
+
+ <!-- close parenthesis -->
+ <xsl:if test="
+ ( local-name() = 'sum' )
+ or ( ( local-name() = 'product' ) and not( @of ) )
+ ">
+ <xsl:text>\right)</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+
+ <xsl:if test="$enclose">
+ <xsl:text>)</xsl:text>
+ </xsl:if>
+
+ <!-- since we looped manually, we must also invoke `after' templates
+ manually -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style quotient of two values as a LaTeX equation
+
+ This is used to divide two values and will be styled as a fraction. The
+ numerator should be the first calculation node and the denominator the second;
+ there should be no additional nodes.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:quotient">
+ <!-- numerator (first child) -->
+ <xsl:text>\frac{</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+
+ <!-- denominator (second child) -->
+ <xsl:text>}{</xsl:text>
+ <xsl:apply-templates select="./c:*[2]" />
+ <xsl:text>}</xsl:text>
+
+ <!-- since we processed manually, we must also invoke `after' templates
+ manually -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<xsl:template match="c:let">
+ <!-- process the body of the let expression (the variables should have been
+ processed separately) -->
+ <xsl:apply-templates select="c:*" />
+</xsl:template>
+
+
+<!--
+ Style a value for display within a LaTeX equation
+
+ Forwards to calc-get-value template.
+-->
+<xsl:template match="c:value-of">
+ <xsl:apply-templates select="." mode="calc-get-value" />
+</xsl:template>
+
+
+<!--
+ Values from a c:let must have their names altered before looking up the symbol
+-->
+<xsl:template match="c:*[ @name=ancestor::c:let/c:values/c:value/@name ]" mode="calc-get-value">
+ <xsl:call-template name="calc-get-value">
+ <!-- :<let-name>:<our-name> -->
+ <xsl:with-param name="name" select="
+ concat( ':', ancestor::c:let[1]/@name, ':', @name )
+ " />
+ </xsl:call-template>
+</xsl:template>
+
+
+<!--
+ Style a value for display within a LaTeX equation
+
+ By default, the symbol for the given value (variable) will be rendered in
+ place of this node.
+
+ This element is not expected to have any children.
+
+ XXX: Refactor me; there are more clear and less convoluted ways to accomplish
+ this.
+
+ @return LaTeX equation
+-->
+<xsl:template name="calc-get-value" match="c:*" mode="calc-get-value">
+ <xsl:param name="name" select="@name" />
+
+ <xsl:variable name="index-symbol">
+ <xsl:if test="./c:index">
+ <xsl:for-each select="./c:index">
+ <!-- separate multiple indexes with commas -->
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="./c:*[1]" />
+ </xsl:for-each>
+ </xsl:if>
+ </xsl:variable>
+
+ <xsl:variable name="sym" select="
+ /lv:*/preproc:symtable/preproc:sym[
+ @name=$name
+ ]
+ " />
+
+
+ <xsl:variable name="value">
+ <xsl:choose>
+ <!-- for scalar constants that do not have a symbol, simply inline their
+ value (if they have a symbol, then it is assumed that their symbolic
+ meaning is more meaningful than its value) -->
+ <xsl:when test="
+ $sym[
+ @type='const'
+ and @dim='0'
+ and ( not( @text ) or @tex='' )
+ ]
+ ">
+ <xsl:value-of select="$sym/@value" />
+ </xsl:when>
+
+ <!-- local index (generated with @of) -->
+ <xsl:when test="ancestor::c:*[ @of and @index=$name ]">
+ <xsl:value-of select="$name" />
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="$name" />
+ <xsl:with-param name="index" select="@index" />
+ <xsl:with-param name="index-symbol" select="$index-symbol" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
+ <xsl:copy-of select="$value" />
+
+ <!-- yes, a value still may have things to appear after it -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Style a constant value for use in a LaTeX equation
+
+ Constant values are not treated as variables; instead, their value (rather
+ than their symbol) is immediately rendered.
+
+ Use this only if the value itself makes more sense (and is more clear) than a
+ variable.
+
+ This element is not expected to have any children.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:const">
+ <!-- a constant value of 1 with Iverson's brackets is redundant -->
+ <xsl:if test="not( ( @value = '1' ) and ./c:when )">
+ <!-- display constant value -->
+ <xsl:value-of select="@value" />
+ </xsl:if>
+
+ <!-- a constant may still have things to appear after it -->
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<xsl:template match="c:ceil|c:floor">
+ <xsl:text>\left\l</xsl:text>
+ <xsl:value-of select="local-name()" />
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates select="." mode="calc-recurse" />
+ <xsl:text>\right\r</xsl:text>
+ <xsl:value-of select="local-name()" />
+</xsl:template>
+
+
+<!--
+ Styles a function application for display in a LaTeX equation
+
+ Indicates a function application. A call to the function, with each of its
+ arguments in parenthesis, will be rendered.
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:apply">
+ <xsl:variable name="self" select="." />
+ <xsl:variable name="name" select="@name" />
+ <xsl:variable name="fsym" select="//lv:function[@name=$name]/@sym" />
+
+ <xsl:call-template name="get-symbol">
+ <xsl:with-param name="name" select="@name" />
+ <xsl:with-param name="search" select="/" />
+ </xsl:call-template>
+
+ <!-- if a symbol is provided, then omit the parenthesis -->
+ <xsl:if test="not( $fsym )">
+ <xsl:text>\left(</xsl:text>
+ </xsl:if>
+
+ <!-- output the symbol associated with the value of each argument -->
+ <xsl:for-each select="./c:arg">
+ <!-- delimit params with a comma -->
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:variable name="valname" select="./c:*[1]/@name" />
+
+ <xsl:choose>
+ <!-- if this variable has been defined as an index, then simply output
+ it -->
+ <xsl:when test="ancestor::c:*[ @of and @index=$valname ]">
+ <xsl:value-of select="$valname" />
+ </xsl:when>
+
+ <!-- display the value of constants -->
+ <xsl:when test="local-name( ./c:*[1] ) = 'const'">
+ <xsl:value-of select="./c:*[1]/@value" />
+ </xsl:when>
+
+ <!-- otherwise, it's some other variable and we must look up its
+ symbol -->
+ <xsl:otherwise>
+ <xsl:apply-templates select="./c:*[1]" />
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- we may have c:when, etc (args are their own sub-equations) -->
+ <xsl:apply-templates select="./c:*[1]/c:*" mode="calc-after" />
+ </xsl:for-each>
+
+ <xsl:if test="not( $fsym )">
+ <xsl:text>\right)</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="./c:*" mode="calc-after" />
+</xsl:template>
+
+
+<!--
+ Outputs Iverson's brackets only if forced; see calc-after mode
+
+ This is hidden by default until calc-after to ensure that this is display
+ *after* the equation is output.
+
+ @param boolean force-show optionally force the display of the notation
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:when">
+ <xsl:param name="force-show" select="false()" />
+ <xsl:param name="standalone" select="false()" />
+
+ <!-- by default, we want to defer showing this until after the equation has
+ been output; however, the caller can force it to be displayed if needed -->
+ <xsl:if test="$force-show = true()">
+ <xsl:apply-templates select="." mode="calc-after">
+ <xsl:with-param name="standalone" select="$standalone" />
+ </xsl:apply-templates>
+ </xsl:if>
+</xsl:template>
+
+
+<!--
+ Outputs Iverson's brackets
+
+ This is called *after* the equation is output
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:when" mode="calc-after" priority="5">
+ <xsl:param name="brackets" select="true()" />
+ <xsl:param name="standalone" select="false()" />
+
+ <xsl:variable name="preceding" select="preceding-sibling::c:when" />
+
+ <!-- output bracket only if (a) requested and (b) first in set -->
+ <xsl:if test="$brackets and ( $standalone or not( $preceding ) )">
+ <xsl:text>\left[</xsl:text>
+ </xsl:if>
+
+ <!-- if we do have a preceding sibling, prefix with "and" -->
+ <xsl:if test="not( $standalone ) and $preceding">
+ <xsl:text>\text{ and }</xsl:text>
+ </xsl:if>
+
+ <!-- output the symbol for the variable we are comparing against -->
+ <xsl:apply-templates select="." mode="calc-get-value" />
+
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates select="./c:*" mode="calc-iversons" />
+
+ <!-- output bracket only if (a) requested and (b) last in set -->
+ <xsl:if test="
+ $brackets and ( $standalone or not( following-sibling::c:when ) )
+ ">
+
+ <xsl:text>\right]</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="c:cases">
+ <xsl:text>\begin{cases}</xsl:text>
+ <xsl:apply-templates select="./c:case|./c:otherwise" />
+ <xsl:text>\end{cases}</xsl:text>
+
+ <!-- if any equations immediately follow, add some extra space so as not to
+ confuse the reader -->
+ <xsl:if test="following-sibling::c:*">
+ <xsl:text>\;\;\;</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+
+<!--
+ Generate a case
+
+ When $force-show is provided, as it is when displaying only small portions of
+ an equation, it will display the line using Iverson's brackets.
+-->
+<xsl:template match="c:cases/c:case|c:cases/c:otherwise">
+ <xsl:param name="force-show" select="false()" />
+
+ <!-- generate value -->
+ <xsl:apply-templates select="./c:*[ not( local-name() = 'when' ) ][1]" />
+
+ <xsl:choose>
+ <xsl:when test="not( $force-show )">
+ <xsl:text> &amp; </xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text> [</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="local-name() != 'otherwise'">
+ <xsl:if test="not( $force-show )">
+ <xsl:text>\text{if } </xsl:text>
+ </xsl:if>
+
+ <!-- generate condition under which this value will apply -->
+ <xsl:apply-templates select="./c:when" mode="calc-after">
+ <xsl:with-param name="brackets" select="false()" />
+ </xsl:apply-templates>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>\text{otherwise}</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- determine how we end the line (more cases or end?) -->
+ <xsl:choose>
+ <xsl:when test="$force-show">
+ <xsl:text>]</xsl:text>
+ </xsl:when>
+
+ <xsl:when test="following-sibling::c:case|following-sibling::c:otherwise">
+ <xsl:text>; \\</xsl:text>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:text>.</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+<!--
+ Do nothing with calc-after for any unmatched calculations
+-->
+<xsl:template match="c:*" mode="calc-after" priority="1">
+ <!-- make sure nothing is done for all other nodes with calc-after -->
+</xsl:template>
+
+
+<!--
+ Display a notation intended for use within Iverson's brackets
+
+ @return LaTeX equation
+-->
+<xsl:template match="c:eq|c:ne|c:gt|c:lt|c:gte|c:lte" mode="calc-iversons">
+ <xsl:variable name="name" select="local-name()" />
+
+ <!-- map to LaTeX equivalent -->
+ <xsl:variable name="map">
+ <c id="eq">=</c>
+ <c id="ne">\not=\;</c>
+ <c id="gt">\gt</c>
+ <c id="lt">\lt</c>
+ <c id="gte">\geq</c>
+ <c id="lte">\leq</c>
+ </xsl:variable>
+
+ <xsl:value-of select="$map/*[ @id=$name ]" />
+ <xsl:text> </xsl:text>
+
+ <xsl:apply-templates select="." mode="calc-recurse" />
+</xsl:template>
+
+
+<!--
+ TODO: Technically this is incorrect; sets cannot have duplicate values. This
+ would be best styled as a vector/matrix/etc.
+-->
+<xsl:template match="c:set" priority="1">
+ <xsl:text>\left[</xsl:text>
+ <xsl:for-each select="./c:*">
+ <xsl:if test="position() > 1">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+
+ <xsl:apply-templates select="." />
+ </xsl:for-each>
+ <xsl:text>\right]^T</xsl:text>
+</xsl:template>
+
+<!-- style subsets as matrices (easier to read) -->
+<xsl:template match="c:set[ ./c:set ]" priority="5">
+ <xsl:text>\left[\begin{array}\\</xsl:text>
+
+ <xsl:for-each select="./c:set">
+ <xsl:if test="position() > 1">
+ <xsl:text>\\</xsl:text>
+ </xsl:if>
+
+ <xsl:for-each select="./c:*">
+ <xsl:if test="position() > 1">
+ <xsl:text disable-output-escaping="yes"> &amp; </xsl:text>
+ </xsl:if>
+
+ <xsl:text>{</xsl:text>
+ <xsl:apply-templates select="." />
+ <xsl:text>}</xsl:text>
+ </xsl:for-each>
+ </xsl:for-each>
+
+ <xsl:text>\end{array}\right]</xsl:text>
+</xsl:template>
+
+
+<xsl:template match="c:length-of">
+ <xsl:text>\#\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>\right)</xsl:text>
+</xsl:template>
+
+<xsl:template match="c:cons">
+ <xsl:text>\textrm{cons}\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>,</xsl:text>
+ <xsl:apply-templates select="./c:*[2]" />
+ <xsl:text>\right)</xsl:text>
+</xsl:template>
+
+<xsl:template match="c:car">
+ <xsl:text>\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>\right)_0</xsl:text>
+</xsl:template>
+
+<xsl:template match="c:cdr">
+ <xsl:text>\textrm{cdr}\left(</xsl:text>
+ <xsl:apply-templates select="./c:*[1]" />
+ <xsl:text>\right)</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>