*** /home/rubey/tmp/combfunc.spad.pamphlet	2005-10-04 16:53:11.000000000 +0200
--- combfunc.spad.pamphlet	2005-10-04 16:56:59.000000000 +0200
***************
*** 130,150 ****
      idsum     : List F -> F
      iprod     : List F -> F
      idprod    : List F -> F
      ddsum     : List F -> O
      ddprod    : List F -> O
      fourth    : List F -> F
      dvpow1    : List F -> F
      dvpow2    : List F -> F
      summand   : List F -> F
      dvsum     : (List F, SE) -> F
      dvdsum    : (List F, SE) -> F
      facts     : (F, List SE) -> F
      K2fact    : (K, List SE) -> F
      smpfact   : (SMP, List SE) -> F
  
      dummy == new()$SE :: F
  @
- 
  This macro will be used in [[product]] and [[summation]], both the $5$ and $3$
  argument forms. It is used to introduce a dummy variable in place of the
  summation index within the summands. This in turn is necessary to keep the
--- 130,155 ----
      idsum     : List F -> F
      iprod     : List F -> F
      idprod    : List F -> F
+     dsum      : List F -> O
      ddsum     : List F -> O
+     dprod     : List F -> O
      ddprod    : List F -> O
+     equalsumprod  : (K, K) -> Boolean 
+     equaldsumprod : (K, K) -> Boolean 
      fourth    : List F -> F
      dvpow1    : List F -> F
      dvpow2    : List F -> F
      summand   : List F -> F
      dvsum     : (List F, SE) -> F
      dvdsum    : (List F, SE) -> F
+     dvprod    : (List F, SE) -> F
+     dvdprod   : (List F, SE) -> F
      facts     : (F, List SE) -> F
      K2fact    : (K, List SE) -> F
      smpfact   : (SMP, List SE) -> F
  
      dummy == new()$SE :: F
  @
  This macro will be used in [[product]] and [[summation]], both the $5$ and $3$
  argument forms. It is used to introduce a dummy variable in place of the
  summation index within the summands. This in turn is necessary to keep the
***************
*** 155,167 ****
  product.
  
  Note that up to [[patch--25]] this used to read
- 
  \begin{verbatim}
      dummy := new()$SE :: F
  \end{verbatim}
- 
  thus introducing the same dummy variable for all products and summations, which
! caused nested products and summations fail. (Issue~\#72)
  
  <<package COMBF CombinatorialFunction>>=
      opfact  := operator("factorial"::Symbol)$CommonOperators
--- 160,170 ----
  product.
  
  Note that up to [[patch--25]] this used to read
  \begin{verbatim}
      dummy := new()$SE :: F
  \end{verbatim}
  thus introducing the same dummy variable for all products and summations, which
! caused nested products and summations to fail. (Issue~\#72)
  
  <<package COMBF CombinatorialFunction>>=
      opfact  := operator("factorial"::Symbol)$CommonOperators
***************
*** 219,233 ****
        opsum [eval(x, k := kernel(i)$K, dm), dm, k::F]
  
  @
- 
  These two operations return the product or the sum as unevaluated operators. A
  dummy variable is introduced to make the indexing variable \lq local\rq.
  
  <<package COMBF CombinatorialFunction>>=
      dvsum(l, x) ==
!       k  := retract(second l)@K
!       differentiate(third l, x) * summand l
!           + opsum [differentiate(first l, x), second l, third l]
  
      dvdsum(l, x) ==
        x = retract(y := third l)@SE => 0
--- 222,233 ----
        opsum [eval(x, k := kernel(i)$K, dm), dm, k::F]
  
  @
  These two operations return the product or the sum as unevaluated operators. A
  dummy variable is introduced to make the indexing variable \lq local\rq.
  
  <<package COMBF CombinatorialFunction>>=
      dvsum(l, x) ==
!       opsum [differentiate(first l, x), second l, third l]
  
      dvdsum(l, x) ==
        x = retract(y := third l)@SE => 0
***************
*** 238,249 ****
          opdsum [differentiate(first l, x), second l, y, g, h]
  
  @
! 
! The above operation implements differentiation of sums with bounds. Note that
! the function
! 
  $$n\mapsto\sum_{k=1}^n f(k,n)$$
- 
  is well defined only for integral values of $n$ greater than or equal to zero.
  There is not even consensus how to define this function for $n<0$. Thus, it is
  not differentiable. Therefore, we need to check whether we erroneously are
--- 238,246 ----
          opdsum [differentiate(first l, x), second l, y, g, h]
  
  @
! The above two operations implement differentiation of sums with and without
! bounds. Note that the function
  $$n\mapsto\sum_{k=1}^n f(k,n)$$
  is well defined only for integral values of $n$ greater than or equal to zero.
  There is not even consensus how to define this function for $n<0$. Thus, it is
  not differentiable. Therefore, we need to check whether we erroneously are
***************
*** 275,287 ****
--- 272,379 ----
               + opdsum [differentiate(f, x), d, y, g, h]
  \end{verbatim}
  
+ Up to [[patch--45]] a similar mistake could be found in the code for
+ differentiation of formal sums, which read
+ \begin{verbatim}
+     dvsum(l, x) ==
+       k  := retract(second l)@K
+       differentiate(third l, x) * summand l
+           + opsum [differentiate(first l, x), second l, third l]
+ \end{verbatim}
+ 
  <<package COMBF CombinatorialFunction>>=
+     dvprod(l, x) ==
+       dm := retract(dummy)@SE
+       f := eval(first l, retract(second l)@K, dm::F)
+       p := product(f, dm)
+ 
+       opsum [differentiate(first l, x)/first l * p, second l, third l]
+ 
+ 
+     dvdprod(l, x) ==
+       x = retract(y := third l)@SE => 0
+       if member?(x, variables(h := third rest rest l)) or 
+          member?(x, variables(g := third rest l)) then
+         error "a product cannot be differentiated with respect to a bound"
+       else
+         opdsum cons(differentiate(first l, x)/first l, rest l) * opdprod l 
+ 
+ @ 
+ The above two operations implement differentiation of products with and without
+ bounds. Note again, that we cannot even properly define products with bounds
+ that are not integral.
+ 
+ To differentiate the product, we use Leibniz rule:
+ $$\frac{d}{dx}\prod_{i=a}^b f(i,x) = 
+   \sum_{i=a}^b \frac{\frac{d}{dx} f(i,x)}{f(i,x)}\prod_{i=a}^b f(i,x)
+ $$
+ 
+ There is one situation where this definition might produce wrong results,
+ namely when the product is zero, but axiom failed to recognize it: in this
+ case,
+ $$
+   \frac{d}{dx} f(i,x)/f(i,x)  
+ $$
+ is undefined for some $i$. However, I was not able to come up with an
+ example. The alternative definition
+ $$
+   \frac{d}{dx}\prod_{i=a}^b f(i,x) = 
+   \sum_{i=a}^b \left(\frac{d}{dx} f(i,x)\right)\prod_{j=a,j\neq i}^b f(j,x)
+ $$
+ has the slight (display) problem that we would have to come up with a new index
+ variable, which looks very ugly. Furthermore, it seems to me that more
+ simplifications will occur with the first definition.
+ 
+ <<TEST COMBF>>=
+   f := operator 'f
+   D(product(f(i,x),i=1..m),x)
+ @
+ 
+ Note that up to [[patch--45]] these functions did not exist and products were
+ differentiated according to the usual chain rule, which gave incorrect
+ results. (Issue~\#211)
+ 
+ <<package COMBF CombinatorialFunction>>=
+     dprod l ==
+       prod(summand(l)::O, third(l)::O)
+ 
      ddprod l ==
        prod(summand(l)::O, third(l)::O = fourth(l)::O, fourth(rest l)::O)
  
+     dsum l ==
+       sum(summand(l)::O, third(l)::O)
+ 
      ddsum l ==
        sum(summand(l)::O, third(l)::O = fourth(l)::O, fourth(rest l)::O)
  
+ @ 
+ These four operations handle the conversion of sums and products to
+ [[OutputForm]]. Note that up to [[patch--45]] the definitions for sums and
+ products without bounds were missing and output was illegible.
+ 
+ <<package COMBF CombinatorialFunction>>=
+     equalsumprod(s1, s2) ==
+       l1 := argument s1
+       l2 := argument s2
+ 
+       (eval(first l1, retract(second l1)@K, second l2) = first l2)
+ 
+     equaldsumprod(s1, s2) ==
+       l1 := argument s1
+       l2 := argument s2
+ 
+       ((third rest l1 = third rest l2) and
+        (third rest rest l1 = third rest rest l2) and
+        (eval(first l1, retract(second l1)@K, second l2) = first l2))
+ 
+ @ 
+ The preceding two operations handle the testing for equality of sums and
+ products. This functionality was missing up to [[patch--45]]. (Issue~\#213)
+ The corresponding property [[%specialEqual]] set below is checked in
+ [[Kernel]]. Note that we can assume that the operators are equal, since this
+ is checked in [[Kernel]] itself.
+
+ <<package COMBF CombinatorialFunction>>=
      product(x:F, s:SegmentBinding F) ==
        k := kernel(variable s)$K
        dm := dummy
***************
*** 293,299 ****
        opdsum [eval(x,k,dm), dm, k::F, lo segment s, hi segment s]
  
  @
- 
  These two operations return the product or the sum as unevaluated operators. A
  dummy variable is introduced to make the indexing variable \lq local\rq.
  
--- 385,390 ----
***************
*** 466,488 ****
                      log(first l) * first(l) ** second(l)
  
  @
- 
  This operation implements the differentiation of the power operator [[%power]]
  with respect to its second argument, i.e., the exponent. It uses the formula
! 
! $$\frac{d}{dx} g(y)^x = \frac{d}{dx} e^{x\log g(y)} = \log g(y) g(y)^x$$.
  
  If $g(y)$ equals zero, this formula is not valid, since the logarithm is not
  defined there. Although strictly speaking $0^x$ is not differentiable at zero,
  we return zero for convenience. 
  
  Note that up to [[patch--25]] this used to read
- 
  \begin{verbatim}
      if F has ElementaryFunctionCategory then
        dvpow2 l == log(first l) * first(l) ** second(l)
  \end{verbatim}
- 
  which caused differentiating $0^x$ to fail. (Issue~\#19)
  
  <<package COMBF CombinatorialFunction>>=
--- 557,575 ----
                      log(first l) * first(l) ** second(l)
  
  @
  This operation implements the differentiation of the power operator [[%power]]
  with respect to its second argument, i.e., the exponent. It uses the formula
! $$\frac{d}{dx} g(y)^x = \frac{d}{dx} e^{x\log g(y)} = \log g(y) g(y)^x.$$
  
  If $g(y)$ equals zero, this formula is not valid, since the logarithm is not
  defined there. Although strictly speaking $0^x$ is not differentiable at zero,
  we return zero for convenience. 
  
  Note that up to [[patch--25]] this used to read
  \begin{verbatim}
      if F has ElementaryFunctionCategory then
        dvpow2 l == log(first l) * first(l) ** second(l)
  \end{verbatim}
  which caused differentiating $0^x$ to fail. (Issue~\#19)
  
  <<package COMBF CombinatorialFunction>>=
***************
*** 495,506 ****
      evaluate(opprod, iprod)
      evaluate(opdprod, iidprod)
      derivative(oppow, [dvpow1, dvpow2])
!     setProperty(opsum,SPECIALDIFF,dvsum@((List F,SE) -> F) pretend None)
!     setProperty(opdsum,SPECIALDIFF,dvdsum@((List F,SE)->F) pretend None)
!     setProperty(opdsum,  SPECIALDISP,  ddsum@(List F -> O) pretend None)
      setProperty(opdprod, SPECIALDISP, ddprod@(List F -> O) pretend None)
  
- @
  \section{package FSPECF FunctionalSpecialFunction}
  <<package FSPECF FunctionalSpecialFunction>>=
  )abbrev package FSPECF FunctionalSpecialFunction
--- 582,612 ----
      evaluate(opprod, iprod)
      evaluate(opdprod, iidprod)
      derivative(oppow, [dvpow1, dvpow2])
!     setProperty(opsum,   SPECIALDIFF, dvsum@((List F, SE) -> F) pretend None)
!     setProperty(opdsum,  SPECIALDIFF, dvdsum@((List F, SE)->F) pretend None)
!     setProperty(opprod,  SPECIALDIFF, dvprod@((List F, SE)->F) pretend None)
!     setProperty(opdprod, SPECIALDIFF, dvdprod@((List F, SE)->F) pretend None)
! @
! The last four properties define special differentiation rules for sums and
! products. Note that up to [[patch--45]] the rules for products were missing.
! Thus products were differentiated according the usual chain-rule, which gave
! incorrect results.
! 
! <<package COMBF CombinatorialFunction>>=
!     setProperty(opsum,   SPECIALDISP, dsum@(List F -> O) pretend None)
!     setProperty(opdsum,  SPECIALDISP, ddsum@(List F -> O) pretend None)
!     setProperty(opprod,  SPECIALDISP, dprod@(List F -> O) pretend None)
      setProperty(opdprod, SPECIALDISP, ddprod@(List F -> O) pretend None)
+     setProperty(opsum,   SPECIALEQUAL, equalsumprod@((K,K) -> Boolean) pretend None)
+     setProperty(opdsum,  SPECIALEQUAL, equaldsumprod@((K,K) -> Boolean) pretend None)
+     setProperty(opprod,  SPECIALEQUAL, equalsumprod@((K,K) -> Boolean) pretend None)
+     setProperty(opdprod, SPECIALEQUAL, equaldsumprod@((K,K) -> Boolean) pretend None)
+ 
+ @ 
+ Finally, we set the properties for displaying sums and products and testing for
+ equality.
+ 
  
  \section{package FSPECF FunctionalSpecialFunction}
  <<package FSPECF FunctionalSpecialFunction>>=
  )abbrev package FSPECF FunctionalSpecialFunction
