This file is indexed.

/usr/share/axiom-20170501/src/algebra/MHROWRED.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
)abbrev package MHROWRED ModularHermitianRowReduction
++ Author: Manuel Bronstein
++ Date Created: 22 February 1989
++ Date Last Updated: 24 November 1993
++ Description:
++ Modular hermitian row reduction.
-- should be moved into matrix whenever possible

ModularHermitianRowReduction(R) : SIG == CODE where
  R : EuclideanDomain

  Z   ==> Integer
  V   ==> Vector R
  M   ==> Matrix R
  REC ==> Record(val:R, cl:Z, rw:Z)

  SIG ==> with

    rowEch : M -> M
      ++ rowEch(m) computes a modular row-echelon form of m, finding
      ++ an appropriate modulus.

    rowEchelon : (M, R) -> M
      ++ rowEchelon(m, d) computes a modular row-echelon form mod d of
      ++    [d     ]
      ++    [  d   ]
      ++    [    . ]
      ++    [     d]
      ++    [   M  ]
      ++ where \spad{M = m mod d}.

    rowEchLocal : (M, R) -> M
      ++ rowEchLocal(m,p) computes a modular row-echelon form of m, finding
      ++ an appropriate modulus over a local ring where p is the only prime.

    rowEchelonLocal : (M, R, R) -> M
      ++ rowEchelonLocal(m, d, p) computes the row-echelon form of m
      ++ concatenated with d times the identity matrix
      ++ over a local ring where p is the only prime.

    normalizedDivide : (R, R) -> Record(quotient:R, remainder:R)
      ++ normalizedDivide(n,d) returns a normalized quotient and
      ++ remainder such that consistently unique representatives
      ++ for the residue class are chosen, for example, positive remainders

  CODE ==> add

    order   : (R, R) -> Z
    vconc   : (M, R) -> M
    non0    : (V, Z) -> Union(REC, "failed")
    nonzero?: V -> Boolean
    mkMat   : (M, List Z) -> M
    diagSubMatrix: M -> Union(Record(val:R, mat:M), "failed")
    determinantOfMinor: M -> R
    enumerateBinomial: (List Z, Z, Z) -> List Z

    nonzero? v == any?(s +-> s ^= 0, v)

    -- returns [a, i, rown] if v = [0,...,0,a,0,...,0]
    -- where a <> 0 and i is the index of a, "failed" otherwise.
    non0(v, rown) ==
      ans:REC
      allZero:Boolean := true
      for i in minIndex v .. maxIndex v repeat
        if qelt(v, i) ^= 0 then
          if allZero then
            allZero := false
            ans := [qelt(v, i), i, rown]
          else return "failed"
      allZero => "failed"
      ans

    -- returns a matrix made from the non-zero rows of x whose row number
    -- is not in l
    mkMat(x, l) ==
      empty?(ll := [parts row(x, i)
         for i in minRowIndex x .. maxRowIndex x |
           (not member?(i, l)) and nonzero? row(x, i)]$List(List R)) =>
              zero(1, ncols x)
      matrix ll

    -- returns [m, d] where m = x with the zero rows and the rows of
    -- the diagonal of d removed, if x has a diagonal submatrix of d's,
    -- "failed" otherwise.
    diagSubMatrix x ==
      l  := [u::REC for i in minRowIndex x .. maxRowIndex x |
                                     (u := non0(row(x, i), i)) case REC]
      for a in removeDuplicates([r.val for r in l]$List(R)) repeat
        {[r.cl for r in l | r.val = a]$List(Z)}$Set(Z) =
          {[z for z in minColIndex x .. maxColIndex x]$List(Z)}$Set(Z)
            => return [a, mkMat(x, [r.rw for r in l | a = r.val])]
      "failed"

    -- returns a non-zero determinant of a minor of x of rank equal to
    -- the number of columns of x, if there is one, 0 otherwise
    determinantOfMinor x ==
      -- do not compute a modulus for square matrices, since this is as 
      -- expensive as the Hermite reduction itself
      (nr := nrows x) <= (nc := ncols x) => 0
      lc := [i for i in minColIndex x .. maxColIndex x]$List(Integer)
      lr := [i for i in minRowIndex x .. maxRowIndex x]$List(Integer)
      for i in 1..(n := binomial(nr, nc)) repeat
        (d := determinant x(enumerateBinomial(lr, nc, i), lc)) ^= 0 =>
          j := i + 1 + (random()$Z rem (n - i))
          return gcd(d, determinant x(enumerateBinomial(lr, nc, j), lc))
      0

    -- returns the i-th selection of m elements of l = (a1,...,an),
    --                 /n\
    -- where 1 <= i <= | |
    --                 \m/
    enumerateBinomial(l, m, i) ==
      m1 := minIndex l - 1
      zero?(m := m - 1) => [l(m1 + i)]
      for j in 1..(n := #l) repeat
        i <= (b := binomial(n - j, m)) =>
          return concat(l(m1 + j), enumerateBinomial(rest(l, j), m, i))
        i := i - b
      error "Should not happen"

    rowEch x ==
      (u := diagSubMatrix x) case "failed" =>
        zero?(d := determinantOfMinor x) => rowEchelon x
        rowEchelon(x, d)
      rowEchelon(u.mat, u.val)

    vconc(y, m) ==
      vertConcat(diagonalMatrix new(ncols y, m)$V, map(s +-> s rem m, y))

    order(m, p) ==
      zero? m => -1
      for i in 0.. repeat
        (mm := m exquo p) case "failed" => return i
        m := mm::R

    if R has IntegerNumberSystem then

        normalizedDivide(n:R, d:R):Record(quotient:R, remainder:R) ==
            qr := divide(n, d)
            qr.remainder >= 0 => qr
            d > 0 =>
                qr.remainder := qr.remainder + d
                qr.quotient := qr.quotient - 1
                qr
            qr.remainder := qr.remainder - d
            qr.quotient := qr.quotient + 1
            qr
    else

        normalizedDivide(n:R, d:R):Record(quotient:R, remainder:R) ==
            divide(n, d)

    rowEchLocal(x,p) ==
      (u := diagSubMatrix x) case "failed" =>
        zero?(d := determinantOfMinor x) => rowEchelon x
        rowEchelonLocal(x, d, p)
      rowEchelonLocal(u.mat, u.val, p)

    rowEchelonLocal(y, m, p) ==
        m := p**(order(m,p)::NonNegativeInteger)
        x     := vconc(y, m)
        nrows := maxRowIndex x
        ncols := maxColIndex x
        minr  := i := minRowIndex x
        for j in minColIndex x .. ncols repeat
          if i > nrows then leave x
          rown := minr - 1
          pivord : Integer
          npivord : Integer
          for k in i .. nrows repeat
            qelt(x,k,j) = 0 => "next k"
            npivord := order(qelt(x,k,j),p)
            (rown = minr - 1) or (npivord  <  pivord) =>
                    rown := k
                    pivord := npivord
          rown = minr - 1 => "enuf"
          x := swapRows_!(x, i, rown)
          (a, b, d) := extendedEuclidean(qelt(x,i,j), m)
          qsetelt_!(x,i,j,d)
          pivot := d
          for k in j+1 .. ncols repeat
            qsetelt_!(x,i,k, a * qelt(x,i,k) rem m)
          for k in i+1 .. nrows repeat
            zero? qelt(x,k,j) => "next k"
            q := (qelt(x,k,j) exquo pivot) :: R
            for k1 in j+1 .. ncols repeat
              v2 := (qelt(x,k,k1) - q * qelt(x,i,k1)) rem m
              qsetelt_!(x, k, k1, v2)
            qsetelt_!(x, k, j, 0)
          for k in minr .. i-1 repeat
            zero? qelt(x,k,j) => "enuf"
            qr    := normalizedDivide(qelt(x,k,j), pivot)
            qsetelt_!(x,k,j, qr.remainder)
            for k1 in j+1 .. ncols x repeat
              qsetelt_!(x,k,k1,
                     (qelt(x,k,k1) - qr.quotient * qelt(x,i,k1)) rem m)
          i := i+1
        x

    if R has Field then

      rowEchelon(y, m) == rowEchelon vconc(y, m)

    else

      rowEchelon(y, m) ==
        x     := vconc(y, m)
        nrows := maxRowIndex x
        ncols := maxColIndex x
        minr  := i := minRowIndex x
        for j in minColIndex x .. ncols repeat
          if i > nrows then leave
          rown := minr - 1
          for k in i .. nrows repeat
            if (qelt(x,k,j) ^= 0) and ((rown = minr - 1) or
                  sizeLess?(qelt(x,k,j), qelt(x,rown,j))) then rown := k
          rown = minr - 1 => "next j"
          x := swapRows_!(x, i, rown)
          for k in i+1 .. nrows repeat
            zero? qelt(x,k,j) => "next k"
            (a, b, d) := extendedEuclidean(qelt(x,i,j), qelt(x,k,j))
            (b1, a1) :=
               ((qelt(x,i,j) exquo d)::R, (qelt(x,k,j) exquo d)::R)
            -- a*b1+a1*b = 1
            for k1 in j+1 .. ncols repeat
              v1 := (a  * qelt(x,i,k1) +  b * qelt(x,k,k1)) rem m
              v2 := (b1 * qelt(x,k,k1) - a1 * qelt(x,i,k1)) rem m
              qsetelt_!(x, i, k1, v1)
              qsetelt_!(x, k, k1, v2)
            qsetelt_!(x, i, j, d)
            qsetelt_!(x, k, j, 0)
          un := unitNormal qelt(x,i,j)
          qsetelt_!(x,i,j,un.canonical)
          if un.associate ^= 1 then for jj in (j+1)..ncols repeat
              qsetelt_!(x,i,jj,un.associate * qelt(x,i,jj))
          xij := qelt(x,i,j)
          for k in minr .. i-1 repeat
            zero? qelt(x,k,j) => "next k"
            qr    := normalizedDivide(qelt(x,k,j), xij)
            qsetelt_!(x,k,j, qr.remainder)
            for k1 in j+1 .. ncols x repeat
              qsetelt_!(x,k,k1,
                     (qelt(x,k,k1) - qr.quotient * qelt(x,i,k1)) rem m)
          i := i+1
        x