This file is indexed.

/usr/share/axiom-20170501/src/algebra/FFFG.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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
)abbrev package FFFG FractionFreeFastGaussian
++ Author: Martin Rubey
++ Description:
++ This package implements the interpolation algorithm proposed in Beckermann,
++ Bernhard and Labahn, George, Fraction-free computation of matrix rational
++ interpolants and matrix GCDs, SIAM Journal on Matrix Analysis and
++ Applications 22.
++ The packages defined in this file provide fast fraction free rational
++ interpolation algorithms. (see FAMR2, FFFG, FFFGF, NEWTON)

FractionFreeFastGaussian(D, V) : SIG == CODE where
  D : Join(IntegralDomain, GcdDomain)
  V : AbelianMonoidRing(D, NonNegativeInteger) -- for example, SUP D

  SUP  ==> SparseUnivariatePolynomial

  cFunction ==> (NonNegativeInteger, Vector SUP D) -> D

  CoeffAction ==> (NonNegativeInteger, NonNegativeInteger, V) -> D

  SIG ==> with

    fffg : (List D, cFunction, List NonNegativeInteger) -> Matrix SUP D
      ++ \spad{fffg} is the general algorithm as proposed by Beckermann and
      ++ Labahn.
      ++
      ++ The first argument is the list of c_{i,i}.  These are the only values
      ++ of C explicitely needed in \spad{fffg}.
      ++
      ++ The second argument c, computes c_k(M), c_k(.) is the dual basis
      ++ of the vector space V, but also knows about the special multiplication
      ++ rule as descibed in Equation (2).  Note that the information about f
      ++ is therefore encoded in c.
      ++
      ++ The third argument is the vector of degree bounds n, as introduced in
      ++ Definition 2.1.  In particular, the sum of the entries is the order of
      ++ the Mahler system computed.

    interpolate : (List D, List D, NonNegativeInteger) -> Fraction SUP D
      ++ \spad{interpolate(xlist, ylist, deg} returns the rational function with
      ++ numerator degree at most \spad{deg} and denominator degree at most
      ++ \spad{#xlist-deg-1}  that interpolates the given points using
      ++ fraction free arithmetic. Note that rational interpolation does not
      ++ guarantee that all given points are interpolated correctly:
      ++ unattainable points may make this impossible.

    interpolate: (List Fraction D, List Fraction D, NonNegativeInteger) 
                -> Fraction SUP D
      ++ \spad{interpolate(xlist, ylist, deg} returns the rational function with
      ++ numerator degree \spad{deg} that interpolates the given points using
      ++ fraction free arithmetic.

    generalInterpolation: (List D, CoeffAction, 
                           Vector V, List NonNegativeInteger) -> Matrix SUP D
      ++ \spad{generalInterpolation(C, CA, f, eta)} performs Hermite-Pade
      ++ approximation using the given action CA of polynomials on the elements
      ++ of f. The result is guaranteed to be correct up to order
      ++ |eta|-1. Given that eta is a "normal" point, the degrees on the
      ++ diagonal are given by eta. The degrees of column i are in this case
      ++ eta + e.i - [1,1,...,1], where the degree of zero is -1.
      ++
      ++ The first argument C is the list of coefficients c_{k,k} in the 
      ++ expansion <x^k> z g(x) = sum_{i=0}^k c_{k,i} <x^i> g(x).
      ++
      ++ The second argument, CA(k, l, f), should return the coefficient of x^k
      ++ in z^l f(x).

    generalInterpolation: (List D, CoeffAction, 
                           Vector V, NonNegativeInteger, NonNegativeInteger) 
                         -> Stream Matrix SUP D
      ++ \spad{generalInterpolation(C, CA, f, sumEta, maxEta)} applies
      ++ \spad{generalInterpolation(C, CA, f, eta)} for all possible \spad{eta}
      ++ with maximal entry \spad{maxEta} and sum of entries at most
      ++ \spad{sumEta}.
      ++
      ++ The first argument C is the list of coefficients c_{k,k} in the 
      ++ expansion <x^k> z g(x) = sum_{i=0}^k c_{k,i} <x^i> g(x).
      ++
      ++ The second argument, CA(k, l, f), should return the coefficient of x^k 
      ++ in z^l f(x).

    generalCoefficient: (CoeffAction, Vector V, 
                         NonNegativeInteger, Vector SUP D) -> D
      ++ \spad{generalCoefficient(action, f, k, p)} gives the coefficient of
      ++ x^k in p(z)\dot f(x), where the action of z^l on a polynomial in x is
      ++ given by action, action(k, l, f) should return the coefficient
      ++ of x^k in z^l f(x).

    ShiftAction: (NonNegativeInteger, NonNegativeInteger, V) -> D
      ++ \spad{ShiftAction(k, l, g)} gives the coefficient of x^k in z^l g(x),
      ++ where \spad{z*(a+b*x+c*x^2+d*x^3+...) = (b*x+2*c*x^2+3*d*x^3+...)}. In
      ++ terms of sequences, z*u(n)=n*u(n).

    ShiftC: NonNegativeInteger -> List D
      ++ \spad{ShiftC} gives the coefficients c_{k,k} in the expansion <x^k> z
      ++ g(x) = sum_{i=0}^k c_{k,i} <x^i> g(x), where z acts on g(x) by
      ++ shifting. In fact, the result is [0,1,2,...]

    DiffAction: (NonNegativeInteger, NonNegativeInteger, V) -> D
      ++ \spad{DiffAction(k, l, g)} gives the coefficient of x^k in z^l g(x),
      ++ where z*(a+b*x+c*x^2+d*x^3+...) = (a*x+b*x^2+c*x^3+...),
      ++ multiplication with x.

    DiffC: NonNegativeInteger -> List D
      ++ \spad{DiffC} gives the coefficients c_{k,k} in the expansion <x^k> z
      ++ g(x) = sum_{i=0}^k c_{k,i} <x^i> g(x), where z acts on g(x) by
      ++ shifting. In fact, the result is [0,0,0,...]

    qShiftAction: (D, NonNegativeInteger, NonNegativeInteger, V) -> D
      ++ \spad{qShiftAction(q, k, l, g)} gives the coefficient of x^k in z^l
      ++ g(x), where z*(a+b*x+c*x^2+d*x^3+...) =
      ++ (a+q*b*x+q^2*c*x^2+q^3*d*x^3+...). In terms of sequences,
      ++ z*u(n)=q^n*u(n).

    qShiftC: (D, NonNegativeInteger) -> List D
      ++ \spad{qShiftC} gives the coefficients c_{k,k} in the expansion <x^k> z
      ++ g(x) = sum_{i=0}^k c_{k,i} <x^i> g(x), where z acts on g(x) by
      ++ shifting. In fact, the result is [1,q,q^2,...]

  CODE ==> add

-------------------------------------------------------------------------------
-- Shift Operator
-------------------------------------------------------------------------------

-- ShiftAction(k, l, f) is the CoeffAction appropriate for the shift operator.

    ShiftAction(k: NonNegativeInteger, l: NonNegativeInteger, f: V): D ==
      k**l*coefficient(f, k)


    ShiftC(total: NonNegativeInteger): List D == 
      [i::D for i in 0..total-1]

-------------------------------------------------------------------------------
-- q-Shift Operator
-------------------------------------------------------------------------------

-- q-ShiftAction(k, l, f) is the CoeffAction appropriate for the q-shift operator.

    qShiftAction(q: D, k: NonNegativeInteger, l: NonNegativeInteger, f: V): D ==
      q**(k*l)*coefficient(f, k)


    qShiftC(q: D, total: NonNegativeInteger): List D == 
      [q**i for i in 0..total-1]

-------------------------------------------------------------------------------
-- Differentiation Operator
-------------------------------------------------------------------------------

-- DiffAction(k, l, f) is the CoeffAction appropriate for the differentiation
-- operator.

    DiffAction(k: NonNegativeInteger, l: NonNegativeInteger, f: V): D ==
      coefficient(f, (k-l)::NonNegativeInteger)


    DiffC(total: NonNegativeInteger): List D == 
      [0 for i in 1..total]

-------------------------------------------------------------------------------
-- general - suitable for functions f
-------------------------------------------------------------------------------

-- get the coefficient of z^k in the scalar product of p and f, the action
-- being defined by coeffAction

    generalCoefficient(coeffAction: CoeffAction, f: Vector V, 
                       k: NonNegativeInteger, p: Vector SUP D): D == 
      res: D := 0
      for i in 1..#f repeat

-- Defining a and b and summing only over those coefficients that might be
-- nonzero makes a huge difference in speed
        a := f.i
        b := p.i
        for l in minimumDegree b..degree b repeat
            if not zero? coefficient(b, l)
            then res := res + coefficient(b, l) * coeffAction(k, l, a)
      res


    generalInterpolation(C: List D, coeffAction: CoeffAction, 
                         f: Vector V, 
                         eta: List NonNegativeInteger): Matrix SUP D == 

      c: cFunction := (x,y) +-> generalCoefficient(coeffAction, f,
                                         (x-1)::NonNegativeInteger, y)
      fffg(C, c, eta)



-------------------------------------------------------------------------------
-- general - suitable for functions f - trying all possible degree combinations
-------------------------------------------------------------------------------


    nextVector!(p: NonNegativeInteger, v: List NonNegativeInteger)
               : Union("failed", List NonNegativeInteger) ==
      n := #v
      pos := position(x +-> x < p, v)
      zero? pos => return "failed"
      if pos = 1 then
        sum: Integer := v.1
        for i in 2..n repeat    
          if v.i < p and sum > 0 then
            v.i := v.i + 1
            sum := sum - 1
            for j in 1..i-1 repeat
              if sum > p then
                v.j := p
                sum := sum - p
              else
                v.j := sum::NonNegativeInteger
                sum := 0
            return v
          else sum := sum + v.i
        return "failed" 
      else
        v.pos     := v.pos + 1    
        v.(pos-1) := (v.(pos-1) - 1)::NonNegativeInteger

      v

    vectorStream(p: NonNegativeInteger, v: List NonNegativeInteger)
                : Stream List NonNegativeInteger == delay
      next := nextVector!(p, copy v)
      (next case "failed") => empty()$Stream(List NonNegativeInteger)
      cons(next, vectorStream(p, next))

    vectorStream2(p: NonNegativeInteger, v: List NonNegativeInteger)
                 : Stream List NonNegativeInteger == delay
      next := nextVector!(p, copy v)
      (next case "failed") => empty()$Stream(List NonNegativeInteger)
      next2 := nextVector!(p, copy next)
      (next2 case "failed") => cons(next, empty())
      cons(next2, vectorStream2(p, next2))
    generalInterpolation(C: List D, coeffAction: CoeffAction, 
                         f: Vector V, 
                         sumEta: NonNegativeInteger,
                         maxEta: NonNegativeInteger)
                        : Stream Matrix SUP D ==


      sum: Integer := sumEta
      entry: Integer
      eta: List NonNegativeInteger
          := [(if sum < maxEta _
               then (entry := sum; sum := 0) _
               else (entry := maxEta; sum := sum - maxEta); _
               entry::NonNegativeInteger) for i in 1..#f]

      if #f = 2 then
        map(x +-> generalInterpolation(C, coeffAction, f, x), 
            cons(eta, vectorStream2(maxEta, eta)))
           $StreamFunctions2(List NonNegativeInteger,
                             Matrix SUP D)
      else
        map(x +-> generalInterpolation(C, coeffAction, f, x), 
            cons(eta, vectorStream(maxEta, eta)))
           $StreamFunctions2(List NonNegativeInteger,
                           Matrix SUP D)

-------------------------------------------------------------------------------
-- rational interpolation
-------------------------------------------------------------------------------

    interpolate(x: List Fraction D, y: List Fraction D, d: NonNegativeInteger) 
               : Fraction SUP D ==
      gx := splitDenominator(x)$InnerCommonDenominator(D, Fraction D, _
                                                       List D, _
                                                       List Fraction D)
      gy := splitDenominator(y)$InnerCommonDenominator(D, Fraction D, _
                                                       List D, _
                                                       List Fraction D)
      r := interpolate(gx.num, gy.num, d)
      elt(numer r,monomial(gx.den,1))/(gy.den*elt(denom r, monomial(gx.den,1)))

    interpolate(x: List D, y: List D, d: NonNegativeInteger): Fraction SUP D ==
      -- berechne Interpolante mit Graden d und N-d-1
      if (N := #x) ~= #y then
        error "interpolate: number of points and values must match"
      if N <= d then
        error _
   "interpolate: numerator degree must be smaller than number of data points"
      c: cFunction := (s,u) +-> y.s * elt(u.2, x.s) - elt(u.1, x.s)
      eta: List NonNegativeInteger := [d, (N-d)::NonNegativeInteger]
      M := fffg(x, c, eta)
      if zero?(M.(2,1)) then M.(1,2)/M.(2,2)
                        else M.(1,1)/M.(2,1)

-------------------------------------------------------------------------------
-- fffg
-------------------------------------------------------------------------------

    -- a major part of the time is spent here
    recurrence(M: Matrix SUP D, pi: NonNegativeInteger, m: NonNegativeInteger,_
            r: Vector D, d: D, z: SUP D, Ck: D, p: Vector D): Matrix SUP D ==
        rPi: D := qelt(r, pi)
        polyf: SUP D := rPi * (z - Ck::SUP D)
        for i in 1..m repeat
            MiPi: SUP D    := qelt(M, i, pi)
            newMiPi: SUP D := polyf * MiPi
            -- update columns ~= pi and calculate their sum
            for l in 1..m | l ~= pi repeat
                rl: D  := qelt(r, l)
            -- I need the coercion to SUP D, since exquo returns an element of
            -- Union("failed", SUP D)...
                Mil:SUP D := ((qelt(M, i, l) * rPi - MiPi * rl) exquo d)::SUP D
                qsetelt!(M, i, l, Mil)
                pl: D  := qelt(p, l)
                newMiPi := newMiPi - pl * Mil
            -- update column pi
            qsetelt!(M, i, pi, (newMiPi exquo d)::SUP D)
        M


    fffg(C: List D,c: cFunction, eta: List NonNegativeInteger): Matrix SUP D ==
        -- eta is the vector of degrees. 
        -- We compute M with degrees eta+e_i-1, i=1..m 
        z: SUP D := monomial(1, 1)
        m: NonNegativeInteger := #eta
        M: Matrix SUP D := scalarMatrix(m, 1)
        d: D := 1
        K: NonNegativeInteger := reduce(_+, eta)
        etak: Vector NonNegativeInteger := zero(m)
        r: Vector D := zero(m)
        p: Vector D := zero(m)
        Lambda: List Integer
        lambdaMax: Integer
        lambda: NonNegativeInteger
        for k in 1..K repeat
            for l in 1..m repeat r.l := c(k, column(M, l))
            Lambda := [eta.l-etak.l for l in 1..m | r.l ~= 0]
            -- if Lambda is empty, then M, d and etak remain unchanged. 
            -- Otherwise, we look for the next closest para-normal point.
            (empty? Lambda) => "iterate"
            lambdaMax := reduce(max, Lambda)
            lambda := 1
            while eta.lambda-etak.lambda < lambdaMax or r.lambda = 0 repeat 
                lambda := lambda + 1
            -- Calculate leading coefficients
            for l in 1..m | l ~= lambda repeat
                if etak.l > 0 then
                    p.l := coefficient(M.(l, lambda), 
                                       (etak.l-1)::NonNegativeInteger)
                else 
                    p.l := 0
            -- increase order and adjust degree constraints
            M := recurrence(M, lambda, m, r, d, z, C.k, p)
            d := r.lambda
            etak.lambda := etak.lambda + 1

        M