Subject: Re: [xsl] Using divide-and-conquer recursion to create a cumulative sequence From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Sat, 12 Dec 2009 07:59:54 -0800 |
The FXSL function f:scanl($pFun, $pQ0, $pList) where $pList is a sequence of item() $pFun is a function (actually a node -- matched by a template) that takes wo items of the type of the $pList items and produces another item of the same type $pQ0 is an "initial item" so that $pFun($pQ0, $pList[1]) can be calculated, and if$pList is empty, then the result of f:scanl(...) is $pQ0 does exactly this. Just call it like this: f:scanl(f:add(), 0, $pList) Here is a complete example: <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://fxsl.sf.net/" exclude-result-prefixes="f" > <xsl:import href="../f/func-scanlDVC.xsl"/> <xsl:import href="../f/func-Operators.xsl"/> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/"> <xsl:for-each select="f:scanl(f:add(), 0, 1 to 100000)"> <xsl:value-of select="concat(.,',')"/> </xsl:for-each> </xsl:template> </xsl:stylesheet> This transformation produces the sequence of running totals of the sequence of the numbers 1 to 100 000 (100 thousand numbers), and the result is: 0,1,3,6,10,15,21,28,36,45,55,66,78,91,105,120,136, ..., 4999650006,4999750003,4999850001,4999950000,5000050000, Not only this transformation doesn't crash due to any reason (stack overflow was expected :) ), but its transformation time with Saxon was only 601 milliseconds: Saxon 9.1.0.7J from Saxonica Java version 1.6.0_17 Stylesheet compilation time: 520 milliseconds Processing file:/C:\CVS-DDN\fxsl-xslt2\data\numList.xml Building tree for file:/C:\CVS-DDN\fxsl-xslt2\data\numList.xml using class net.sf.saxon.tinytree.TinyBuilder Tree built in 1 milliseconds Tree size: 35 nodes, 20 characters, 0 attributes Loading net.sf.saxon.event.MessageEmitter Execution time: 601 milliseconds Memory used: 342403488 NamePool contents: 97 entries in 91 chains. 9 prefixes, 10 URIs To return to the original question: How to write a DVC transformation when the calculations of the "right half" depend on the result of the calculations of the "left half"? The answer is simple: use the result of calculating the function over the "left half" as argument to the calculation of the function over the "right half". In particular, below is a snippet from ../f/func-scanlDVC.xsl (the DVC implementation of f:scanl() imported by the above stylesheet. As we can see, the result of calculating the function over the "left half" is produced in the variable $vResult1, whose last item is then used as an argument in producing the result over the "right half": <xsl:sequence select= "($vResult1, int:scanl($pFun, $vResult1[last()], $pList[position() > $vHalf], 0) )" /> Here is the complete snippet from the code of f:scanl(): <xsl:import href="func-apply.xsl"/> <xsl:function name="f:scanl" as="item()*"> <xsl:param name="pFun" as="element()"/> <xsl:param name="pQ0"/> <xsl:param name="pList" as="item()*"/> <xsl:sequence select="int:scanl($pFun, $pQ0, $pList, 1)"/> </xsl:function> <xsl:function name="int:scanl" as="item()*"> <xsl:param name="pFun" as="element()"/> <xsl:param name="pQ0"/> <xsl:param name="pList" as="item()*"/> <xsl:param name="pStarting" as="xs:integer"/> <xsl:variable name="vLength" select="count($pList)"/> <xsl:choose> <xsl:when test="$vLength > 1"> <xsl:variable name="vHalf" select="$vLength idiv 2"/> <xsl:variable name="vResult1" select="int:scanl($pFun, $pQ0, $pList[position() <= $vHalf], $pStarting )"/> <xsl:sequence select= "($vResult1, int:scanl($pFun, $vResult1[last()], $pList[position() > $vHalf], 0) )" /> </xsl:when> <xsl:otherwise> <xsl:if test="$pStarting"> <xsl:sequence select="$pQ0"/> </xsl:if> <xsl:if test="exists($pList)"> <xsl:sequence select="f:apply($pFun, $pQ0, $pList[1])"/> </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:function> -- Cheers, Dimitre Novatchev --------------------------------------- Truly great madness cannot be achieved without significant intelligence. --------------------------------------- To invent, you need a good imagination and a pile of junk ------------------------------------- Never fight an inanimate object ------------------------------------- You've achieved success in your field when you don't know whether what you're doing is work or play ------------------------------------- I enjoy the massacre of ads. This sentence will slaughter ads without a messy bloodbath. On Fri, Dec 11, 2009 at 1:39 PM, Costello, Roger L. <costello@xxxxxxxxx> wrote: > > Hi Folks, > > I wish to convert a sequence of N numbers: > > B (23, 41, 70, 103, 99, 6) > > Into a cumulative sequence, in which each number is the sum of the previous numbers: > > B (23, 64, 134, 237, 336, 342) > > > One approach to solving this is to iterate through the N numbers and sum the preceding numbers: > > B for i=1 to N > B B B sum(for j=1 to i return numbers[j]) > > > However, that approach has a time complexity of: > > B 1 + 2 + 3 + ... + N = N**2/2 > > For large N, that will be very expensive. > > An alternative approach is to create a recursive function that does a single pass through the sequence, carrying along (and adding) the accumulated total on each recursive call. This has a time complexity of N. Nice. > > ********************************************************************* > The above (paraphrases) from Michael Kay's book, XSLT 2.0 and XPath 2.0, p. 993. > The below is from me. > ********************************************************************* > > However, that sequential recursive approach will entail N recursive calls, which will result in running out of memory for large N (let's assume that the XSLT processor does not do tail recursive optimization). > > I would like a way of solving the problem using divide-and-conquer recursion. Can you provide a solution? > > /Roger
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Using divide-and-conquer , Andrew Welch | Thread | Re: [xsl] Using divide-and-conquer , Hermann Stamm-Wilbra |
Re: [xsl] Recursive evaluation of e, Florent Georges | Date | [xsl] problem with fn:contains usin, Piotr Dobrogost |
Month |