|
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 |