This file is indexed.

/usr/share/axiom-20170501/src/algebra/GOSPER.spad is in axiom-source 20170501-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
)abbrev package GOSPER GosperSummationMethod
++ Author: SMW
++ Date Last Updated: 19 August 1991
++ Description: 
++ Gosper's summation algorithm.

GosperSummationMethod(E, V, R, P, Q) : SIG == CODE where
  E : OrderedAbelianMonoidSup
  V : OrderedSet
  R : IntegralDomain
  P : PolynomialCategory(R, E, V)
  Q : Join(RetractableTo Fraction Integer, Field with
            (coerce: P -> %; numer : % -> P; denom : % -> P))

  I   ==> Integer
  RN  ==> Fraction I
  PQ  ==> SparseMultivariatePolynomial(RN, V)
  RQ  ==> Fraction PQ

  SIG ==> with

    GospersMethod : (Q, V, () -> V) -> Union(Q, "failed")
      ++ GospersMethod(b, n, new) returns a rational function
      ++ \spad{rf(n)} such that \spad{a(n) * rf(n)} is the indefinite
      ++ sum of \spad{a(n)}
      ++ with respect to upward difference on \spad{n},
      ++ \spad{a(n+1) * rf(n+1) - a(n) * rf(n) = a(n)},
      ++ where \spad{b(n) = a(n)/a(n-1)} is a rational function.
      ++ Returns "failed" if no such rational function \spad{rf(n)}
      ++ exists.
      ++ Note that \spad{new} is a nullary function returning a new
      ++ V every time.
      ++ The condition on \spad{a(n)} is that \spad{a(n)/a(n-1)}
      ++ is a rational function of \spad{n}.
      --++  \spad{sum(a(n), n) = rf(n) * a(n)}.

  CODE ==> add

      import PolynomialCategoryQuotientFunctions(E, V, R, P, Q)
      import LinearSystemMatrixPackage(RQ,Vector RQ,Vector RQ,Matrix RQ)

      InnerGospersMethod: (RQ, V, () -> V) -> Union(RQ, "failed")
      GosperPQR:   (PQ, PQ, V, () -> V)       -> List PQ
      GosperDegBd: (PQ, PQ, PQ, V, () -> V)    -> I
      GosperF:     (I, PQ, PQ, PQ, V, () -> V) -> Union(RQ, "failed")
      linearAndNNIntRoot: (PQ, V) -> Union(I, "failed")
      deg0:    (PQ, V) -> I       -- degree with deg 0 = -1.
      pCoef:   (PQ, PQ) -> PQ  -- pCoef(p, a*b**2)
      RF2QIfCan: Q -> Union(RQ, "failed")
      UP2QIfCan: P -> Union(PQ,"failed")
      RFQ2R    : RQ -> Q
      PQ2R     : PQ -> Q
      rat?     : R  -> Boolean

      deg0(p, v) == (zero? p => -1; degree(p, v))

      rat? x     == retractIfCan(x::P::Q)@Union(RN, "failed") case RN

      RFQ2R f    == PQ2R(numer f) / PQ2R(denom f)

      PQ2R p ==
        map(x+->x::P::Q, y+->y::Q, p)$PolynomialCategoryLifting(
                                       IndexedExponents V, V, RN, PQ, Q)

      GospersMethod(aquo, n, newV) ==
        ((q := RF2QIfCan aquo) case "failed") or
          ((u := InnerGospersMethod(q::RQ, n, newV)) case "failed") =>
             "failed"
        RFQ2R(u::RQ)

      RF2QIfCan f ==
        (n := UP2QIfCan numer f) case "failed" => "failed"
        (d := UP2QIfCan denom f) case "failed" => "failed"
        n::PQ / d::PQ

      UP2QIfCan p ==
        every?(rat?, coefficients p) =>
          map(x +-> x::PQ, 
              y +-> (retractIfCan(y::P::Q)@Union(RN, "failed"))::RN::PQ,p)_
               $PolynomialCategoryLifting(E, V, R, P, PQ)
        "failed"

      InnerGospersMethod(aquo, n, newV) ==
            -- 1. Define coprime polys an,anm1 such that
            --      an/anm1=a(n)/a(n-1)
            an   := numer aquo
            anm1 := denom aquo

            -- 2. Define p,q,r such that
            --      a(n)/a(n-1) = (p(n)/p(n-1)) * (q(n)/r(n))
            --    and
            --      gcd(q(n), r(n+j)) = 1, for all j: NNI.
            pqr:= GosperPQR(an, anm1, n, newV)
            pn := first pqr; qn := second pqr; rn := third pqr

            -- 3. If the sum is a rational fn, there is a poly f with
            --      sum(a(n), n) = q(n+1)/p(n) * a(n) * f(n).

            -- 4. Bound the degree of f(n).
            (k := GosperDegBd(pn, qn, rn, n, newV)) < 0 => "failed"

            -- 5. Find a polynomial f of degree at most k, satisfying
            --      p(n) = q(n+1)*f(n) - r(n)*f(n-1)
            (ufn := GosperF(k, pn, qn, rn, n, newV)) case "failed" =>
              "failed"
            fn  := ufn::RQ

            -- 6. The sum is q(n-1)/p(n)*f(n) * a(n). We leave out a(n).
            --qnm1 := eval(qn,n,n::PQ - 1)
            --qnm1/pn * fn
            qn1 := eval(qn,n,n::PQ + 1)
            qn1/pn * fn

      GosperF(k, pn, qn, rn, n, newV) ==
            mv := newV(); mp := mv::PQ; np := n::PQ
            fn:       PQ := +/[mp**(i+1) * np**i for i in 0..k]
            fnminus1: PQ := eval(fn, n, np-1)
            qnplus1        := eval(qn, n, np+1)
            zro  := qnplus1 * fn - rn * fnminus1 - pn
            zron := univariate(zro, n)
            dz  := degree zron
            mat: Matrix RQ := zero(dz+1, (k+1)::NonNegativeInteger)
            vec: Vector RQ := new(dz+1, 0)
            while zron ^= 0 repeat
                cz := leadingCoefficient zron
                dz := degree zron
                zron := reductum zron
                mz := univariate(cz, mv)
                while mz ^= 0 repeat
                    cmz := leadingCoefficient(mz)::RQ
                    dmz := degree mz
                    mz := reductum mz
                    dmz = 0 => vec(dz + minIndex vec) := -cmz
                    qsetelt_!(mat, dz + minRowIndex mat,
                                 dmz + minColIndex(mat) - 1, cmz)
            (soln := particularSolution(mat, vec)) case "failed" => "failed"
            vec := soln::Vector RQ
            (+/[np**i * vec(i + minIndex vec) for i in 0..k])@RQ

      GosperPQR(an, anm1, n, newV) ==
            np := n::PQ   -- polynomial version of n
            -- Initial guess.
            pn: PQ := 1
            qn: PQ := an
            rn: PQ := anm1
            -- Find all j: NNI giving common factors to q(n) and r(n+j).
            j     := newV()
            rnj   := eval(rn, n, np + j::PQ)
            res   := resultant(qn, rnj, n)
            fres  := factor(res)$MRationalFactorize(IndexedExponents V,
                                                    V, I, PQ)
            js    := [rt::I for fe in factors fres
                       | (rt := linearAndNNIntRoot(fe.factor,j)) case I]
            -- For each such j, change variables to remove the gcd.
            for rt in js repeat
                rtp:= rt::PQ  -- polynomial version of rt
                gn := gcd(qn, eval(rn,n,np+rtp))
                qn := (qn exquo gn)::PQ
                rn := (rn exquo eval(gn, n, np-rtp))::PQ
                pn := pn * */[eval(gn, n, np-i::PQ) for i in 0..rt-1]
            [pn, qn, rn]

        -- Find a degree bound for the polynomial f(n) which satisfies
        --   p(n) = q(n+1)*f(n) - r(n)*f(n-1).
      GosperDegBd(pn, qn, rn, n, newV) ==
            np := n::PQ
            qnplus1  := eval(qn, n, np+1)
            lplus  := deg0(qnplus1 + rn,  n)
            lminus := deg0(qnplus1 - rn, n)
            degp   := deg0(pn, n)
            k := degp - max(lplus-1, lminus)
            lplus <= lminus => k
            -- Find L(k), such that
            --   p(n) = L(k)*c[k]*n**(k + lplus - 1) + ...
            -- To do this, write f(n) and f(n-1) symbolically.
            --   f(n)  = c[k]*n**k + c[k-1]*n**(k-1) +O(n**(k-2))
            --   f(n-1)=c[k]*n**k + (c[k-1]-k*c[k])*n**(k-1)+O(n**(k-2))
            kk := newV()::PQ
            ck := newV()::PQ
            ckm1 := newV()::PQ
            nkm1:= newV()::PQ
            nk := np*nkm1
            headfn   := ck*nk +         ckm1*nkm1
            headfnm1 := ck*nk + (ckm1-kk*ck)*nkm1
            -- Then p(n) = q(n+1)*f(n) - r(n)*f(n-1) gives L(k).
            pk   := qnplus1 * headfn - rn * headfnm1
            lcpk := pCoef(pk, ck*np*nkm1)
            -- The degree bd is now given by k, and the root of L.
            k0 := linearAndNNIntRoot(lcpk, mainVariable(kk)::V)
            k0 case "failed" => k
            max(k0::I, k)

      pCoef(p, nom) ==
            not monomial? nom =>
              error "pCoef requires a monomial 2nd arg"
            vlist := variables nom
            for v in vlist while p ^= 0 repeat
                unom:= univariate(nom,v)
                pow:=degree unom
                nom:=leadingCoefficient unom
                up  := univariate(p, v)
                p   := coefficient(up, pow)
            p

      linearAndNNIntRoot(mp, v) ==
            p := univariate(mp, v)
            degree p ^= 1 => "failed"
            (p1 := retractIfCan(coefficient(p, 1))@Union(RN,"failed"))
             case "failed" or
              (p0 := retractIfCan(coefficient(p, 0))@Union(RN,"failed"))
               case "failed" => "failed"
            rt := -(p0::RN)/(p1::RN)
            rt < 0 or denom rt ^= 1 => "failed"
            numer rt