[BACK]Return to generic_integer_linear_solvers.adb CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / PHC / Ada / Math_Lib / Matrices

Annotation of OpenXM_contrib/PHC/Ada/Math_Lib/Matrices/generic_integer_linear_solvers.adb, Revision 1.1.1.1

1.1       maekawa     1: package body Generic_Integer_Linear_Solvers is
                      2:
                      3:   use Common_Divisors;
                      4:
                      5: -- SCALERS :
                      6:
                      7:   function Divisors ( a : Matrix ) return Vectors.Vector is
                      8:
                      9:   -- DESCRIPTION :
                     10:   --   Returns a vector containing the gcd of the elements of each row.
                     11:
                     12:     v : Vectors.Vector(a'range(1));
                     13:
                     14:   begin
                     15:     for i in a'range(1) loop
                     16:       v(i) := a(i,a'first(2));
                     17:       if not Equal(v(i),one)
                     18:        then for j in (a'first(2)+1)..a'last(2) loop
                     19:               v(i) := gcd(v(i),a(i,j));
                     20:               exit when Equal(v(i),one);
                     21:             end loop;
                     22:       end if;
                     23:     end loop;
                     24:     return v;
                     25:   end Divisors;
                     26:
                     27:   function Scale ( a : Matrix ) return Matrix is
                     28:
                     29:     v : Vectors.Vector(a'range(1)) := Divisors(a);
                     30:     b : Matrix(a'range(1),a'range(2));
                     31:
                     32:   begin
                     33:     for i in b'range(1) loop
                     34:       if (Equal(v(i),one) or Equal(v(i),zero))
                     35:        then for j in b'range(2) loop
                     36:              b(i,j) := a(i,j);
                     37:             end loop;
                     38:        else for j in b'range(2) loop
                     39:              b(i,j) := a(i,j) / v(i);
                     40:             end loop;
                     41:       end if;
                     42:     end loop;
                     43:     return b;
                     44:   end Scale;
                     45:
                     46:   procedure Scale ( a : in out Matrix; v : out Vectors.Vector ) is
                     47:
                     48:     dv : Vectors.Vector(a'range(1)) := Divisors(a);
                     49:
                     50:   begin
                     51:     for i in a'range(1) loop
                     52:       if (Equal(dv(i),one) or Equal(dv(i),zero))
                     53:        then null;
                     54:        else for j in a'range(2) loop
                     55:              a(i,j) := a(i,j) / dv(i);
                     56:             end loop;
                     57:       end if;
                     58:     end loop;
                     59:     v := dv;
                     60:   end Scale;
                     61:
                     62:   procedure Scale ( a : in out Matrix ) is
                     63:
                     64:     v : Vectors.Vector(a'range(1)) := Divisors(a);
                     65:
                     66:   begin
                     67:     for i in a'range(1) loop
                     68:       if (Equal(v(i),one) or Equal(v(i),zero))
                     69:        then null;
                     70:        else for j in a'range(2) loop
                     71:              a(i,j) := a(i,j) / v(i);
                     72:             end loop;
                     73:       end if;
                     74:     end loop;
                     75:   end Scale;
                     76:
                     77:   procedure Scale ( a : in out Matrix; row,col : in integer ) is
                     78:
                     79:     g : number := a(row,col);
                     80:
                     81:   begin
                     82:     if not Equal(g,one)
                     83:      then for l in (col+1)..a'last(2) loop
                     84:             g := gcd(g,a(row,l));
                     85:             exit when Equal(g,one);
                     86:           end loop;
                     87:     end if;
                     88:     if (not Equal(g,zero)) and (not Equal(g,one))
                     89:      then for l in row..a'last(2) loop
                     90:             a(row,l) := a(row,l)/g;
                     91:           end loop;
                     92:     end if;
                     93:   end Scale;
                     94:
                     95: -- STATIC TRIANGULATORS :
                     96:
                     97:   procedure Upper_Triangulate ( l : out Matrix; a : in out Matrix ) is
                     98:
                     99:     row,pivot : integer;
                    100:     temp,aa,bb,ka,lb,d,a_rowk,a_ik : number;
                    101:     ll : Matrix(a'range(1),a'range(1));
                    102:
                    103:   begin
                    104:     for i in ll'range(1) loop
                    105:       for j in ll'range(2) loop
                    106:         Copy(zero,ll(i,j));
                    107:       end loop;
                    108:       Copy(one,ll(i,i));
                    109:     end loop;
                    110:     row := a'first(1);
                    111:     for j in a'first(2)..a'last(2) loop
                    112:       pivot := row-1;                                         -- find pivot
                    113:       for i in row..a'last(1) loop
                    114:         if not Equal(a(i,j),zero)
                    115:          then pivot := i;
                    116:               exit;
                    117:         end if;
                    118:       end loop;
                    119:       if pivot >= row
                    120:        then if pivot /= row                      -- interchange if necessary
                    121:              then for k in a'range(2) loop
                    122:                     Copy(a(row,k),temp);
                    123:                     Copy(a(pivot,k),a(row,k));
                    124:                     Copy(temp,a(pivot,k));
                    125:                   end loop;
                    126:                   for k in ll'range(2) loop
                    127:                     Copy(ll(row,k),temp);
                    128:                     Copy(ll(pivot,k),ll(row,k));
                    129:                     Copy(temp,ll(pivot,k));
                    130:                   end loop;
                    131:             end if;
                    132:             for i in (row+1)..a'last(1) loop                  -- make zeroes
                    133:               if not Equal(a(i,j),zero)
                    134:                then gcd(a(row,j),a(i,j),ka,lb,d);
                    135:                     aa := a(row,j)/d;     bb := a(i,j)/d;
                    136:                     if Equal(aa,bb) and then Equal(ka,zero)
                    137:                      then Copy(lb,ka); Copy(zero,lb);
                    138:                     end if;
                    139:                     if Equal(aa,-bb) and then Equal(ka,zero)
                    140:                      then ka := -lb; Copy(zero,lb);
                    141:                     end if;
                    142:                     for k in j..a'last(2) loop
                    143:                       Copy(a(row,k),a_rowk); Clear(a(row,k));
                    144:                          -- a_rowk := a(row,k);
                    145:                       Copy(a(i,k),a_ik); Clear(a(i,k)); -- a_ik := a(i,k);
                    146:                       a(row,k) :=  ka*a_rowk + lb*a_ik;
                    147:                       a(i,k)   := -bb*a_rowk + aa*a_ik;
                    148:                     end loop;
                    149:                     for k in ll'range(2) loop
                    150:                       a_rowk := ll(row,k);
                    151:                       a_ik := ll(i,k);
                    152:                       ll(row,k) :=  ka*a_rowk + lb*a_ik;
                    153:                       ll(i,k)   := -bb*a_rowk + aa*a_ik;
                    154:                     end loop;
                    155:               end if;
                    156:            end loop;
                    157:            row := row + 1;
                    158:       end if;
                    159:       exit when row > a'last(1);
                    160:     end loop;
                    161:     l := ll;
                    162:   end Upper_Triangulate;
                    163:
                    164:   procedure Upper_Triangulate ( a : in out Matrix ) is
                    165:
                    166:     row,pivot : integer;
                    167:     temp,aa,bb,ka,lb,d,a_rowk,a_ik : number;
                    168:
                    169:   begin
                    170:     row := a'first(1);
                    171:     for j in a'first(2)..a'last(2) loop
                    172:       pivot := row-1;                                           -- find pivot
                    173:       for i in row..a'last(1) loop
                    174:         if not Equal(a(i,j),zero)
                    175:          then pivot := i;
                    176:               exit;
                    177:         end if;
                    178:       end loop;
                    179:       if pivot >= row
                    180:        then if pivot /= row                       -- interchange if necessary
                    181:             then for k in a'range(2) loop
                    182:                   Copy(a(row,k),temp);
                    183:                   Copy(a(pivot,k),a(row,k));
                    184:                   Copy(temp,a(pivot,k));
                    185:                 end loop;
                    186:            end if;
                    187:            for i in (row+1)..a'last(1) loop                    -- make zeroes
                    188:              if not Equal(a(i,j),zero)
                    189:               then gcd(a(row,j),a(i,j),ka,lb,d);
                    190:                    aa := a(row,j)/d;     bb := a(i,j)/d;
                    191:                    if Equal(aa,bb) and then Equal(ka,zero)
                    192:                     then Copy(lb,ka); Copy(zero,lb);
                    193:                    end if;
                    194:                    if Equal(aa,-bb) and then Equal(ka,zero)
                    195:                     then ka := -lb; Copy(zero,lb);
                    196:                    end if;
                    197:                   for k in j..a'last(2) loop
                    198:                      Copy(a(row,k),a_rowk); Clear(a(row,k));
                    199:                                --a_rowk := a(row,k);
                    200:                      Copy(a(i,k),a_ik); Clear(a(i,k)); --a_ik   := a(i,k);
                    201:                      a(row,k) :=  ka*a_rowk + lb*a_ik;
                    202:                      a(i,k)   := -bb*a_rowk + aa*a_ik;
                    203:                    end loop;
                    204:              end if;
                    205:            end loop;
                    206:           row := row + 1;
                    207:        end if;
                    208:        exit when row > a'last(1);
                    209:     end loop;
                    210:   end Upper_Triangulate;
                    211:
                    212:   procedure Upper_Triangulate
                    213:                  ( a : in out Matrix;
                    214:                    ipvt : in out Standard_Integer_Vectors.Vector ) is
                    215:
                    216:     row,pivot,tmppiv : integer;
                    217:     temp,aa,bb,ka,lb,d,a_rowk,a_ik : number;
                    218:
                    219:   begin
                    220:     row := a'first(1);
                    221:     for j in a'first(2)..a'last(2) loop
                    222:       pivot := row-1;                                           -- find pivot
                    223:       for i in row..a'last(1) loop
                    224:         if not Equal(a(i,j),zero)
                    225:          then pivot := i;
                    226:               exit;
                    227:         end if;
                    228:       end loop;
                    229:       if pivot >= row
                    230:        then if pivot /= row                       -- interchange if necessary
                    231:             then for k in a'range(2) loop
                    232:                    Copy(a(row,k),temp);
                    233:                    Copy(a(pivot,k),a(row,k));
                    234:                    Copy(temp,a(pivot,k));
                    235:                 end loop;
                    236:                  tmppiv := ipvt(row);
                    237:                  ipvt(row) := ipvt(pivot);
                    238:                  ipvt(pivot) := tmppiv;
                    239:            end if;
                    240:            for i in (row+1)..a'last(1) loop                   -- make zeroes
                    241:              if not Equal(a(i,j),zero)
                    242:               then gcd(a(row,j),a(i,j),ka,lb,d);
                    243:                    aa := a(row,j)/d;     bb := a(i,j)/d;
                    244:                    if Equal(aa,bb) and then Equal(ka,zero)
                    245:                     then Copy(lb,ka); Copy(zero,lb);
                    246:                    end if;
                    247:                    if Equal(aa,-bb) and then Equal(ka,zero)
                    248:                     then ka := -lb; Copy(zero,lb);
                    249:                    end if;
                    250:                    for k in j..a'last(2) loop
                    251:                      Copy(a(row,k),a_rowk); Clear(a(row,k));
                    252:                          -- a_rowk := a(row,k);
                    253:                      Copy(a(i,k),a_ik); Clear(a(i,k)); -- a_ik   := a(i,k);
                    254:                      a(row,k) :=  ka*a_rowk + lb*a_ik;
                    255:                      a(i,k)   := -bb*a_rowk + aa*a_ik;
                    256:                    end loop;
                    257:              end if;
                    258:            end loop;
                    259:           row := row + 1;
                    260:        end if;
                    261:        exit when row > a'last(1);
                    262:     end loop;
                    263:   end Upper_Triangulate;
                    264:
                    265:   procedure Lower_Triangulate ( a : in out Matrix; u : out Matrix ) is
                    266:
                    267:     column,pivot : integer;
                    268:     temp,aa,bb,ka,lb,d,a_kcolumn,a_kj : number;
                    269:     uu : Matrix(a'range(2),a'range(2));
                    270:
                    271:   begin
                    272:
                    273:     for i in uu'range(1) loop
                    274:       for j in uu'range(2) loop
                    275:         Copy(zero,uu(i,j));
                    276:       end loop;
                    277:       Copy(one,uu(i,i));
                    278:     end loop;
                    279:     column := a'first(2);
                    280:     for i in a'first(1)..a'last(1) loop
                    281:       pivot := column-1;                                      -- find pivot
                    282:       for j in column..a'last(2) loop
                    283:         if not Equal(a(i,j),zero)
                    284:          then pivot := j;
                    285:               exit;
                    286:         end if;
                    287:       end loop;
                    288:       if pivot >= column
                    289:        then if pivot /= column                  -- interchange if necessary
                    290:              then for k in a'range(1) loop
                    291:                     Copy(a(k,column),temp);
                    292:                     Copy(a(k,pivot),a(k,column));
                    293:                     Copy(temp,a(k,pivot));
                    294:                   end loop;
                    295:                   for k in uu'range(1) loop
                    296:                     Copy(uu(k,column),temp);
                    297:                     Copy(uu(k,pivot),uu(k,column));
                    298:                     Copy(temp,uu(k,pivot));
                    299:                   end loop;
                    300:             end if;
                    301:             for j in (column+1)..a'last(2) loop               -- make zeroes
                    302:               if not Equal(a(i,j),zero)
                    303:                then gcd(a(i,column),a(i,j),ka,lb,d);
                    304:                     aa := a(i,column)/d;        bb := a(i,j)/d;
                    305:                     if Equal(aa,bb) and then Equal(ka,zero)
                    306:                      then Copy(lb,ka); Copy(zero,lb);
                    307:                     end if;
                    308:                     if Equal(aa,-bb) and then Equal(ka,zero)
                    309:                      then ka := -lb; Copy(zero,lb);
                    310:                     end if;
                    311:                     for k in i..a'last(1) loop
                    312:                       Copy(a(k,column),a_kcolumn); Clear(a(k,column));
                    313:                                               -- a_kcolumn := a(k,column);
                    314:                       Copy(a(k,j),a_kj); Clear(a(k,j)); -- a_kj := a(k,j);
                    315:                       a(k,column) := a_kcolumn*ka    + a_kj*lb;
                    316:                       a(k,j)      := a_kcolumn*(-bb) + a_kj*aa;
                    317:                     end loop;
                    318:                     for k in uu'range(1) loop
                    319:                       Copy(uu(k,column),a_kcolumn); Clear(uu(k,column));
                    320:                                                -- a_kcolumn := uu(k,column);
                    321:                       Copy(uu(k,j),a_kj); Clear(u(k,j)); -- a_kj := uu(k,j);
                    322:                       uu(k,column) := a_kcolumn*ka    + a_kj*lb;
                    323:                       uu(k,j)      := a_kcolumn*(-bb) + a_kj*aa;
                    324:                     end loop;
                    325:               end if;
                    326:             end loop;
                    327:             column := column + 1;
                    328:       end if;
                    329:       exit when column > a'last(2);
                    330:     end loop;
                    331:     u := uu;
                    332:   end Lower_Triangulate;
                    333:
                    334:   procedure Lower_Triangulate ( a : in out Matrix ) is
                    335:
                    336:     column,pivot : integer;
                    337:     temp,aa,bb,ka,lb,d,a_kcolumn,a_kj : number;
                    338:
                    339:   begin
                    340:     column := a'first(2);
                    341:     for i in a'first(1)..a'last(1) loop
                    342:       pivot := column-1;                                      -- find pivot
                    343:       for j in column..a'last(2) loop
                    344:         if not Equal(a(i,j),zero)
                    345:          then pivot := j;
                    346:               exit;
                    347:         end if;
                    348:       end loop;
                    349:       if pivot >= column
                    350:        then if pivot /= column                  -- interchange if necessary
                    351:              then for k in a'range(1) loop
                    352:                     Copy(a(k,column),temp);
                    353:                     Copy(a(k,pivot),a(k,column));
                    354:                     Copy(temp,a(k,pivot));
                    355:                   end loop;
                    356:             end if;
                    357:             for j in (column+1)..a'last(2) loop               -- make zeroes
                    358:              if not Equal(a(i,j),zero)
                    359:               then gcd(a(i,column),a(i,j),ka,lb,d);
                    360:                    aa := a(i,column)/d; bb := a(i,j)/d;
                    361:                    if Equal(aa,bb) and then Equal(ka,zero)
                    362:                     then Copy(lb,ka); Copy(zero,lb);
                    363:                    end if;
                    364:                    if Equal(aa,-bb) and then Equal(ka,zero)
                    365:                     then ka := -lb; Copy(zero,lb);
                    366:                    end if;
                    367:                    for k in i..a'last(1) loop
                    368:                      Copy(a(k,column),a_kcolumn); Clear(a(k,column));
                    369:                                          -- a_kcolumn := a(k,column);
                    370:                      Copy(a(k,j),a_kj); Clear(a(k,j)); -- a_kj := a(k,j);
                    371:                      a(k,column) := a_kcolumn*ka    + a_kj*lb;
                    372:                      a(k,j)      := a_kcolumn*(-bb) + a_kj*aa;
                    373:                    end loop;
                    374:              end if;
                    375:            end loop;
                    376:            column := column + 1;
                    377:       end if;
                    378:       exit when column > a'last(2);
                    379:     end loop;
                    380:   end Lower_Triangulate;
                    381:
                    382:   procedure Lower_Triangulate
                    383:                ( a : in out Matrix;
                    384:                  ipvt : in out Standard_Integer_Vectors.Vector ) is
                    385:
                    386:     column,pivot,tmppiv : integer;
                    387:     temp,aa,bb,ka,lb,d,a_kcolumn,a_kj : number;
                    388:
                    389:   begin
                    390:     column := a'first(2);
                    391:     for i in a'first(1)..a'last(1) loop
                    392:       pivot := column-1;                                       -- find pivot
                    393:       for j in column..a'last(2) loop
                    394:         if not Equal(a(i,j),zero)
                    395:          then pivot := j;
                    396:               exit;
                    397:         end if;
                    398:       end loop;
                    399:       if pivot >= column
                    400:        then if pivot /= column                   -- interchange if necessary
                    401:              then for k in a'range(1) loop
                    402:                     Copy(a(k,column),temp);
                    403:                     Copy(a(k,pivot),a(k,column));
                    404:                     Copy(temp,a(k,pivot));
                    405:                   end loop;
                    406:                   tmppiv := ipvt(column);
                    407:                   ipvt(column) := ipvt(pivot);
                    408:                   ipvt(pivot) := tmppiv;
                    409:             end if;
                    410:             for j in (column+1)..a'last(2) loop               -- make zeroes
                    411:               if not Equal(a(i,j),zero)
                    412:                then gcd(a(i,column),a(i,j),ka,lb,d);
                    413:                     aa := a(i,column)/d; bb := a(i,j)/d;
                    414:                     if Equal(aa,bb) and then Equal(ka,zero)
                    415:                      then Copy(lb,ka); Copy(zero,lb);
                    416:                     end if;
                    417:                     if Equal(aa,-bb) and then Equal(ka,zero)
                    418:                      then ka := -lb; Copy(zero,lb);
                    419:                     end if;
                    420:                     for k in i..a'last(1) loop
                    421:                       Copy(a(k,column),a_kcolumn); Clear(a(k,column));
                    422:                                                 -- a_kcolumn := a(k,column);
                    423:                       Copy(a(k,j),a_kj); Clear(a(k,j)); -- a_kj := a(k,j);
                    424:                       a(k,column) := a_kcolumn*ka    + a_kj*lb;
                    425:                       a(k,j)      := a_kcolumn*(-bb) + a_kj*aa;
                    426:                     end loop;
                    427:               end if;
                    428:             end loop;
                    429:             column := column + 1;
                    430:       end if;
                    431:       exit when column > a'last(2);
                    432:     end loop;
                    433:   end Lower_Triangulate;
                    434:
                    435: -- SELECTORS :
                    436:
                    437:   function Det ( a : Matrix ) return number is
                    438:
                    439:   -- NOTE :
                    440:   --   The triangulation is implemented independently to keep track
                    441:   --   of row interchanges.
                    442:
                    443:     res : number := one;
                    444:     m : matrix(a'range(1),a'range(2));
                    445:     row,pivot : integer;
                    446:     temp,aa,bb,ka,lb,d,m_rowk,m_ik : number;
                    447:
                    448:   begin
                    449:     Copy(a,m);   -- triangulate m
                    450:     row := m'first(1);
                    451:     for j in m'first(2)..m'last(2) loop
                    452:       pivot := row-1;                                           -- find pivot
                    453:       for i in row..m'last(1) loop
                    454:         if not Equal(m(i,j),zero)
                    455:          then pivot := i;
                    456:               exit;
                    457:         end if;
                    458:       end loop;
                    459:       if pivot >= row
                    460:        then if pivot /= row                       -- interchange if necessary
                    461:              then for k in m'range(2) loop
                    462:                     Copy(m(row,k),temp);
                    463:                     Copy(m(pivot,k),m(row,k));
                    464:                     Copy(temp,m(pivot,k));
                    465:                   end loop;
                    466:                   Min(res);
                    467:             end if;
                    468:             for i in (row+1)..m'last(1) loop                   -- make zeroes
                    469:               if not Equal(m(i,j),zero)
                    470:                then gcd(m(row,j),m(i,j),ka,lb,d);
                    471:                     aa := m(row,j)/d; bb := m(i,j)/d;
                    472:                     if Equal(aa,bb) and then Equal(ka,zero)
                    473:                      then Copy(lb,ka); Copy(zero,lb);
                    474:                     end if;
                    475:                     if Equal(aa,-bb) and then Equal(ka,zero)
                    476:                      then ka := -lb; Copy(zero,lb);
                    477:                     end if;
                    478:                     for k in j..m'last(2) loop
                    479:                       Copy(m(row,k),m_rowk); Clear(m(row,k));
                    480:                                                          -- m_rowk := m(row,k);
                    481:                       Copy(m(i,k),m_ik); Clear(m(i,k));  -- m_ik   := m(i,k);
                    482:                       m(row,k) :=  ka*m_rowk + lb*m_ik;
                    483:                       m(i,k)   := -bb*m_rowk + aa*m_ik;
                    484:                     end loop;
                    485:               end if;
                    486:             end loop;
                    487:             row := row + 1;
                    488:        end if;
                    489:        exit when row > m'last(1);
                    490:     end loop;
                    491:     for k in m'range(1) loop
                    492:       Mul(res,m(k,k));
                    493:     end loop;
                    494:     Clear(m);
                    495:     return res;
                    496:   end Det;
                    497:
                    498:   function Per ( i,n : natural; a : matrix;
                    499:                  kk : Standard_Integer_Vectors.Vector ) return number is
                    500:   begin
                    501:     if i = n+1
                    502:      then return one;
                    503:      else declare
                    504:             res,acc : number;
                    505:             kkk : Standard_Integer_Vectors.Vector(kk'range) := kk;
                    506:           begin
                    507:             Copy(zero,res);
                    508:             for j in kk'range loop
                    509:               if not Equal(a(i,j),zero) and then (kk(j) /= 0)
                    510:                then kkk(j) := kkk(j) - 1;
                    511:                     acc := Per(i+1,n,a,kkk);
                    512:                     Add(res,acc);
                    513:                     Clear(acc);
                    514:                     kkk(j) := kkk(j) + 1;
                    515:               end if;
                    516:             end loop;
                    517:             return res;
                    518:           end;
                    519:     end if;
                    520:   end Per;
                    521:
                    522:   function Per ( i,n : natural; a : matrix;
                    523:                  kk : Standard_Integer_Vectors.Vector; max : number )
                    524:                return number is
                    525:   begin
                    526:     if i = n+1
                    527:      then return one;
                    528:      else declare
                    529:             res,acc : number;
                    530:             kkk : Standard_Integer_Vectors.Vector(kk'range) := kk;
                    531:           begin
                    532:             Copy(zero,res);
                    533:             for j in kk'range loop
                    534:               if not Equal(a(i,j),zero) and then (kk(j) /= 0)
                    535:                then kkk(j) := kkk(j) - 1;
                    536:                     acc := a(i,j)*Per(i+1,n,a,kkk,max);
                    537:                     Add(res,acc);
                    538:                     Clear(acc);
                    539:                     kkk(j) := kkk(j) + 1;
                    540:               end if;
                    541:               exit when (res > max) or Equal(res,max);
                    542:             end loop;
                    543:             return res;
                    544:           end;
                    545:     end if;
                    546:   end Per;
                    547:
                    548:   function Per ( a : matrix; k : Standard_Integer_Vectors.Vector )
                    549:                return number is
                    550:
                    551:   -- ALGORITHM :
                    552:   --   Row expansion without memory, as developed by C.W. Wampler,
                    553:   --   see `Bezout Number Calculations for Multi-Homogeneous Polynomial
                    554:   --        Systems', Appl. Math. Comput. 51:(2-3), 143-157, 1992.
                    555:
                    556:   begin
                    557:     return Per(1,a'last(1),a,k);
                    558:   end Per;
                    559:
                    560:   function Per ( a : matrix; k : Standard_Integer_Vectors.Vector;
                    561:                  max : number ) return number is
                    562:
                    563:   -- ALGORITHM :
                    564:   --   Row expansion without memory, as developed by C.W. Wampler,
                    565:   --   see `Bezout Number Calculations for Multi-Homogeneous Polynomial
                    566:   --        Systems', Appl. Math. Comput. 51:(2-3), 143-157, 1992.
                    567:
                    568:   begin
                    569:     return Per(1,a'last(1),a,k,max);
                    570:   end Per;
                    571:
                    572:   function Rank ( a : Matrix ) return natural is
                    573:
                    574:     res : natural := 0;
                    575:     m : Matrix(a'range(1),a'range(2));
                    576:     column : integer;
                    577:
                    578:   begin
                    579:     Copy(a,m);
                    580:     Upper_Triangulate(m);
                    581:    -- compute the length of chain of nonzero elements in m :
                    582:    -- search first nonzero element in first row of m :
                    583:     column := m'first(2)-1;
                    584:     for k in m'range(2) loop
                    585:       if not Equal(m(m'first(1),k),zero)
                    586:        then column := k;
                    587:       end if;
                    588:       exit when (column = k);
                    589:     end loop;
                    590:     if column < m'first(2)
                    591:      then return 0;   -- all elements of m are zero
                    592:      else for k in m'range(1) loop
                    593:             exit when column > m'last(2);
                    594:             if not Equal(m(k,column),zero)
                    595:              then res := res + 1;
                    596:              else -- search for next nonzero element on row k :
                    597:                   for l in column+1..m'last(2) loop
                    598:                     if not Equal(m(k,l),zero)
                    599:                      then column := l;
                    600:                           res := res + 1;
                    601:                     end if;
                    602:                     exit when (column = l);
                    603:                   end loop;
                    604:             end if;
                    605:             column := column + 1;
                    606:           end loop;
                    607:     end if;
                    608:     Clear(m);
                    609:     return res;
                    610:   end Rank;
                    611:
                    612: -- DYNAMIC TRIANGULATOR :
                    613:
                    614:   procedure Triangulate ( l : in integer; m : in out matrix;
                    615:                           ipvt : in out Standard_Integer_Vectors.vector;
                    616:                           piv : out integer ) is
                    617:
                    618:   -- DESCRIPTION :
                    619:   --   Updates lth row of m such that m remains upper triangular.
                    620:
                    621:     tmp,a,b,lcmab,faca,facb : number;
                    622:     pivot,index,tmppiv : integer;
                    623:
                    624:   begin
                    625:     Switch(ipvt,l,m);                      -- pivoting for previous unknowns
                    626:     index := 1;                         -- update : make l-1 zeroes in row l
                    627:     for k in 1..(l-1) loop
                    628:       if (not Equal(m(l,index),zero))
                    629:          and then (not Equal(m(k,index),zero))    -- make m(l,index) zero
                    630:        then a := m(k,index); b := m(l,index);
                    631:             lcmab := lcm(a,b);
                    632:             if lcmab < zero then lcmab := -lcmab; end if;
                    633:             facb := lcmab/b; faca := lcmab/a;
                    634:             if facb > zero
                    635:              then for i in index..m'last(2) loop
                    636:                     m(l,i) :=  facb*m(l,i) - faca*m(k,i);
                    637:                   end loop;
                    638:              else for i in index..m'last(2) loop
                    639:                     m(l,i) := -facb*m(l,i) + faca*m(k,i);
                    640:                   end loop;
                    641:             end if;
                    642:       end if;
                    643:       if not Equal(m(k,index),zero)
                    644:        then index := index + 1;
                    645:       end if;
                    646:     end loop;
                    647:     pivot := 0;                                              -- search pivot
                    648:     for k in l..m'last(2)-1 loop
                    649:       if not Equal(m(l,k),zero)
                    650:        then pivot := k;
                    651:       end if;
                    652:       exit when pivot /= 0;
                    653:     end loop;
                    654:     if pivot > l
                    655:      then for k in 1..l loop              -- interchange columns l and pivot
                    656:             Copy(m(k,l),tmp);
                    657:             Copy(m(k,pivot),m(k,l));
                    658:             Copy(tmp,m(k,pivot));
                    659:           end loop;
                    660:           tmppiv := ipvt(l);
                    661:           ipvt(l) := ipvt(pivot);
                    662:           ipvt(pivot) := tmppiv;
                    663:     end if;
                    664:     piv := pivot;
                    665:   end Triangulate;
                    666:
                    667:   procedure Switch ( ipvt : in Standard_Integer_Vectors.vector;
                    668:                      index : in integer; m : in out matrix ) is
                    669:
                    670:     tmpv : Vectors.Vector(m'range(2));
                    671:
                    672:   begin
                    673:     for k in tmpv'range loop
                    674:       Copy(m(index,k),tmpv(k));
                    675:     end loop;
                    676:     for k in tmpv'range loop
                    677:       Copy(tmpv(ipvt(k)),m(index,k));
                    678:     end loop;
                    679:     Vectors.Clear(tmpv);
                    680:   end Switch;
                    681:
                    682:   procedure Switch ( ipvt : in Standard_Integer_Vectors.vector;
                    683:                      first,last : in integer; m : in out matrix) is
                    684:
                    685:     tmpv : Vectors.Vector(m'range(2));
                    686:
                    687:   begin
                    688:     for index in first..last loop
                    689:       for k in tmpv'range loop
                    690:         Copy(m(index,k),tmpv(k));
                    691:       end loop;
                    692:       for k in tmpv'range loop
                    693:         Copy(tmpv(ipvt(k)),m(index,k));
                    694:       end loop;
                    695:       Vectors.Clear(tmpv);
                    696:     end loop;
                    697:   end Switch;
                    698:
                    699:   procedure Switch ( l,pivot,index : in integer; m : in out matrix ) is
                    700:
                    701:     tmp : number;
                    702:
                    703:   begin
                    704:     if l /= pivot
                    705:      then Copy(m(index,l),tmp);
                    706:           Copy(m(index,pivot),m(index,l));
                    707:           Copy(tmp,m(index,pivot));
                    708:     end if;
                    709:   end Switch;
                    710:
                    711:   procedure Switch ( l,pivot : in integer;
                    712:                      first,last : in integer; m : in out matrix ) is
                    713:
                    714:     tmp : number;
                    715:
                    716:   begin
                    717:     if l /= pivot
                    718:      then for index in first..last loop
                    719:             Copy(m(index,l),tmp);
                    720:             Copy(m(index,pivot),m(index,l));
                    721:             Copy(tmp,m(index,pivot));
                    722:           end loop;
                    723:     end if;
                    724:   end Switch;
                    725:
                    726: -- SOLVERS :
                    727:
                    728:   function Check0 ( a : Matrix; x : Vectors.Vector ) return boolean is
                    729:
                    730:    -- DESCRIPTION :
                    731:    --   Returns true if x is a solution of the system a*x = 0.
                    732:
                    733:     tmp : Vectors.Vector(a'range(1));
                    734:
                    735:   begin
                    736:     tmp := a*x;
                    737:     for i in tmp'range loop
                    738:       if not Equal(tmp(i),zero)
                    739:        then Vectors.Clear(tmp); return false;
                    740:       end if;
                    741:     end loop;
                    742:     Vectors.Clear(tmp);
                    743:     return true;
                    744:   end Check0;
                    745:
                    746:   procedure Solve0 ( a : in Matrix; x : in out Vectors.Vector ) is
                    747:
                    748:   -- ALGORITHM :
                    749:   --   An intermediate, generating matrix tmp will be constructed,
                    750:   --   such that
                    751:   --      1) the solution x to tmp*x = 0 is the same of a*x = 0;
                    752:   --      2) tmp(i,i) and tmp(i,ind) are the only nonzero entries.
                    753:   --   Before this construction, it will be checked whether there
                    754:   --   exists a zero column and the index ind must be determined.
                    755:   --   After the definition of tmp, the back substitution process
                    756:   --   yields a solution.
                    757:
                    758:     piv,ind : integer;
                    759:     tmp : Matrix(a'first(1)..(a'last(1)+1),a'range(2));
                    760:     res : Vectors.Vector(x'range);
                    761:     pivots : Standard_Integer_Vectors.Vector(x'range);
                    762:     zero_column : boolean;
                    763:
                    764:   begin
                    765:    -- initialization of tmp,ind and pivots :
                    766:     for i in tmp'range(1) loop
                    767:       for j in tmp'range(2) loop
                    768:        Copy(zero,tmp(i,j));
                    769:       end loop;
                    770:     end loop;
                    771:     for i in pivots'range loop
                    772:       pivots(i) := i;
                    773:     end loop;
                    774:     ind := x'first(1)-1;
                    775:     for i in a'range(1) loop
                    776:       piv := pivots'first-1;
                    777:       for j in a'range(2) loop
                    778:        if not Equal(a(i,j),zero)
                    779:          then piv := pivots(j);
                    780:              pivots(j) := pivots(i);
                    781:              pivots(i) := piv;
                    782:              exit;
                    783:         end if;
                    784:       end loop;
                    785:       zero_column := true;
                    786:       for j in a'first(1)..i loop
                    787:         Copy(a(j,pivots(i)),tmp(j,i));
                    788:        if zero_column and then not Equal(tmp(j,i),zero)
                    789:         then zero_column := false;
                    790:         end if;
                    791:       end loop;
                    792:       if piv < pivots'first or else zero_column or else Equal(tmp(i,i),zero)
                    793:        then ind := i; exit;
                    794:       end if;
                    795:     end loop;
                    796:     if zero_column
                    797:      then for i in x'range loop
                    798:             Copy(zero,x(i));
                    799:           end loop;
                    800:          Copy(one,x(ind));
                    801:      elsif (ind < x'first(1)) and (a'last(1) >= a'last(2))
                    802:          then for i in x'range loop
                    803:                 Copy(zero,x(i));
                    804:               end loop;
                    805:          else
                    806:            if ind < x'first(1)
                    807:            then ind := a'last(1)+1;
                    808:                 for j in tmp'range(2) loop
                    809:                   Copy(zero,tmp(ind,j));
                    810:                  end loop;
                    811:                 zero_column := true;
                    812:                 for j in a'range(1) loop
                    813:                   Copy(a(j,pivots(ind)),tmp(j,ind));
                    814:                   if zero_column and then not Equal(tmp(j,ind),zero)
                    815:                    then zero_column := false;
                    816:                    end if;
                    817:                  end loop;
                    818:            end if;
                    819:            if zero_column
                    820:            then for i in x'range loop
                    821:                    Copy(zero,x(i));
                    822:                  end loop;
                    823:                 Copy(one,x(ind));
                    824:             else
                    825:              -- construct generating matrix :
                    826:               for i in reverse (tmp'first(2)+1)..(ind-1) loop  -- i = column
                    827:                 for k in tmp'first(1)..(i-1) loop
                    828:                   if not Equal(tmp(k,i),zero)  -- make tmp(k,i) zero
                    829:                    then declare
                    830:                           aa,bb,d : number;
                    831:                         begin
                    832:                           d := gcd(tmp(i,i),tmp(k,i));
                    833:                           aa := tmp(i,i)/d;     bb := tmp(k,i)/d;
                    834:                           for l in k..(i-1) loop
                    835:                             Mul(tmp(k,l),aa);
                    836:                           end loop;
                    837:                           Copy(zero,tmp(k,i)); --aa*tmp(k,i) - bb*tmp(i,i);
                    838:                           tmp(k,ind) := aa*tmp(k,ind) - bb*tmp(i,ind);
                    839:                         end;
                    840:                         Scale(tmp,k,k);  -- to avoid numeric_error
                    841:                   end if;
                    842:                 end loop; -- upper half of ith colum consists of zero entries
                    843:               end loop;
                    844:              -- generate x by back substitution :
                    845:               x(ind) := tmp(x'first,x'first);
                    846:               for i in (x'first+1)..(ind-1) loop
                    847:                if not Equal(tmp(i,i),zero)
                    848:                  then x(ind) := lcm(tmp(i,i),x(ind));
                    849:                 end if;
                    850:               end loop;
                    851:               for i in x'first..(ind-1) loop
                    852:                if Equal(tmp(i,i),zero)
                    853:                 then Copy(zero,x(i));
                    854:                  else x(i) := -(tmp(i,ind)*x(ind))/tmp(i,i);
                    855:                 end if;
                    856:               end loop;
                    857:            end if;
                    858:     end if;
                    859:     for i in res'range loop                      -- take pivots into account
                    860:       Copy(zero,res(i));
                    861:     end loop;
                    862:     for i in x'first..ind loop
                    863:       Copy(x(i),res(pivots(i)));
                    864:     end loop;
                    865:     Vectors.Copy(res,x);
                    866:   end Solve0;
                    867:
                    868:   procedure Solve1 ( a : in Matrix; x : in out Vectors.Vector;
                    869:                      b : in Vectors.Vector; fail : out boolean ) is
                    870:
                    871:     acc : number;
                    872:
                    873:   begin
                    874:     fail := false;
                    875:     for i in reverse x'range loop
                    876:       Copy(b(i),x(i));
                    877:       for j in (i+1)..x'last loop
                    878:         acc := a(i,j)*x(j);
                    879:         Sub(x(i),acc);
                    880:         Clear(acc);
                    881:       end loop;
                    882:       if not Equal(x(i),zero) and then not Equal(a(i,i),zero)
                    883:        then acc := Rmd(x(i),a(i,i));
                    884:             if Equal(acc,zero)
                    885:              then Div(x(i),a(i,i));
                    886:              else fail := true;
                    887:             end if;
                    888:             Clear(acc);
                    889:             if fail
                    890:              then Vectors.Clear(x); return;
                    891:             end if;
                    892:       end if;
                    893:     end loop;
                    894:   end Solve1;
                    895:
                    896:   procedure Solve1 ( a : in Matrix; b : in out Vectors.Vector;
                    897:                      fail : out boolean ) is
                    898:
                    899:     acc : number;
                    900:
                    901:   begin
                    902:     fail := false;
                    903:     for i in reverse b'range loop
                    904:       for j in (i+1)..b'last loop
                    905:         acc := a(i,j)*b(j);
                    906:         Sub(b(i),acc);
                    907:         Clear(acc);
                    908:       end loop;
                    909:       if not Equal(b(i),zero) and then not Equal(a(i,i),zero)
                    910:        then acc := Rmd(b(i),a(i,i));
                    911:             if Equal(acc,zero)
                    912:              then Div(b(i),a(i,i));
                    913:              else fail := true;
                    914:             end if;
                    915:             Clear(acc);
                    916:             if fail
                    917:              then Vectors.Clear(b); return;
                    918:             end if;
                    919:       end if;
                    920:     end loop;
                    921:   end Solve1;
                    922:
                    923:   function Solve ( m : Matrix; ipvt : Standard_Integer_Vectors.Vector )
                    924:                  return Vectors.Vector is
                    925:
                    926:     x,res : Vectors.Vector(ipvt'range);
                    927:     a : matrix(m'first(1)..m'last(1)-1,m'range(2));
                    928:     ind : integer := a'first(1);       -- index for the current row number
                    929:     cnt0 : natural := 0;                 -- counts the number of zero rows
                    930:
                    931:   begin
                    932:     for k in a'range(1) loop
                    933:       if not Equal(m(k,k),zero)               -- otherwise : skip zero row !
                    934:        then for l in a'range(2) loop
                    935:               Copy(m(k,l),a(ind,l));
                    936:             end loop;
                    937:             ind := ind + 1;
                    938:        else for l in a'range(2) loop
                    939:               Copy(m(k,l),a(a'last(1) - cnt0,l));
                    940:             end loop;
                    941:             cnt0 := cnt0 + 1;
                    942:       end if;
                    943:     end loop;
                    944:     for i in x'range loop
                    945:       Copy(zero,x(i));
                    946:     end loop;
                    947:     Solve0(a,x);
                    948:     for k in res'range loop
                    949:       res(ipvt(k)) := x(k);
                    950:     end loop;
                    951:     if res(res'last) < zero
                    952:      then Vectors.Min(res);
                    953:     end if;
                    954:     Clear(a);
                    955:     return res;
                    956:   end Solve;
                    957:
                    958: end Generic_Integer_Linear_Solvers;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>