[BACK]Return to generic_floating_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_floating_linear_solvers.adb, Revision 1.1.1.1

1.1       maekawa     1: -- debugging
                      2: --with text_io; use text_io;
                      3: --with Standard_Natural_Vectors_io; use Standard_Natural_Vectors_io;
                      4:
                      5: package body Generic_Floating_Linear_Solvers is
                      6:
                      7:   use Field,Vectors;
                      8:
                      9: -- AUXILIARIES :
                     10:
                     11:   function csign ( x,y : number ) return number is
                     12:
                     13:     res : number;
                     14:
                     15:   begin
                     16:     if y > zero
                     17:      then res := AbsVal(x);
                     18:      else res := AbsVal(x);
                     19:           Min(res);
                     20:     end if;
                     21:     return res;
                     22:    -- return AbsVal(x) * y / AbsVal(y);
                     23:   end csign;
                     24:
                     25:   function Inverse_Abs_Sum ( z : Vectors.Vector ) return number is
                     26:
                     27:   -- DESCRIPTION :
                     28:   --   Returns the reciprocal of the sum of the absolute values in z.
                     29:
                     30:     res,sum,acc : number;
                     31:
                     32:   begin
                     33:     Copy(zero,sum);
                     34:     for i in z'range loop
                     35:       acc := AbsVal(z(i));
                     36:       Add(sum,acc);
                     37:       Clear(acc);
                     38:     end loop;
                     39:     res := one/sum;
                     40:     Clear(sum);
                     41:     return res;
                     42:   end Inverse_Abs_Sum;
                     43:
                     44: -- STATIC TRIANGULATORS :
                     45:
                     46:   procedure lufac ( a : in out matrix; n : in natural;
                     47:                     ipvt : out Standard_Natural_Vectors.Vector;
                     48:                     info : out natural ) is
                     49:
                     50:     kp1,l,nm1 : natural;
                     51:     smax,temp,acc : number;
                     52:
                     53:   begin
                     54:     info := 0;
                     55:     nm1 := n - 1;
                     56:     if nm1 >= 1
                     57:      then for k in 1..nm1 loop
                     58:             kp1 := k + 1;
                     59:             l := k;
                     60:             smax := AbsVal(a(k,k));                 -- find the pivot index l
                     61:             for i in kp1..n loop
                     62:               acc := AbsVal(a(i,k));
                     63:               if acc > smax
                     64:                then l := i;
                     65:                     Copy(acc,smax);
                     66:               end if;
                     67:               Clear(acc);
                     68:             end loop;
                     69:             ipvt(k) := l;
                     70:             if Equal(smax,zero)
                     71:              then info := k;           -- this column is already triangulated
                     72:              else if l /= k                       -- interchange if necessary
                     73:                    then Copy(a(l,k),temp);
                     74:                         Copy(a(k,k),a(l,k));
                     75:                         Copy(temp,a(k,k));
                     76:                   end if;
                     77:                   acc := one/a(k,k);                   -- compute multipliers
                     78:                   Min(acc);
                     79:                   for i in kp1..n loop
                     80:                     Mul(a(i,k),acc);
                     81:                   end loop;
                     82:                   Clear(acc);
                     83:                   for j in kp1..n loop                     -- row elimination
                     84:                     Copy(a(l,j),temp);
                     85:                     if l /= k
                     86:                      then Copy(a(k,j),a(l,j));
                     87:                           Copy(temp,a(k,j));
                     88:                     end if;
                     89:                     for i in kp1..n loop
                     90:                       acc := temp*a(i,k);
                     91:                       Add(a(i,j),acc);
                     92:                       Clear(acc);
                     93:                     end loop;
                     94:                   end loop;
                     95:                   Clear(temp);
                     96:             end if;
                     97:             Clear(smax);
                     98:           end loop;
                     99:     end if;
                    100:     ipvt(n) := n;
                    101:     if Equal(a(n,n),zero)
                    102:      then info := n;
                    103:     end if;
                    104:   end lufac;
                    105:
                    106:   procedure lufco ( a : in out Matrix; n : in natural;
                    107:                     ipvt : out Standard_Natural_Vectors.Vector;
                    108:                     rcond : out number ) is
                    109:
                    110:   -- NOTE :
                    111:   --   rcond = 1/(norm(a)*(estimate of norm(inverse(a))))
                    112:   --   estimate = norm(z)/norm(y) where a*z = y and ctrans(a)*y = e.
                    113:   --   ctrans(a) is the conjugate transpose of a.
                    114:   --   The components of e are chosen to cause maximum local
                    115:   --   growth in teh elements of w where ctrans(u)*w = e.
                    116:   --   The vectors are frequently rescaled to avoid overflow.
                    117:
                    118:     z : Vectors.Vector(1..n);
                    119:     info,kb,kp1,l : natural;
                    120:     s,sm,sum,anorm,ynorm,ek,t,wk,wkm,acc,absacc1,absacc2 : number;
                    121:     ipvtt : Standard_Natural_Vectors.Vector(1..n);
                    122:
                    123:   begin
                    124:     Copy(zero,anorm);                                 -- compute 1-norm of a
                    125:     for j in 1..n loop
                    126:       Copy(zero,sum);
                    127:       for i in 1..n loop
                    128:         acc := AbsVal(a(i,j));
                    129:         Add(sum,acc);
                    130:         Clear(acc);
                    131:       end loop;
                    132:       if sum > anorm
                    133:        then Copy(sum,anorm);
                    134:       end if;
                    135:     end loop;
                    136:     Clear(sum);
                    137:     lufac(a,n,ipvtt,info);                                         -- factor
                    138:    -- put_line("Factorization completed");
                    139:    -- put("ipvtt : "); put(ipvtt); new_line;
                    140:     for i in 1..n loop
                    141:       ipvt(i) := ipvtt(i);
                    142:     end loop;
                    143:     Copy(one,ek);                                    -- solve ctrans(u)*w = e
                    144:     for j in 1..n loop
                    145:       Copy(zero,z(j));
                    146:     end loop;
                    147:    -- put_line("At start of first k loop");
                    148:     for k in 1..n loop
                    149:       acc := AbsVal(z(k));
                    150:       if not Equal(acc,zero)
                    151:        then Clear(acc);
                    152:             acc := -z(k);
                    153:             ek := csign(ek,acc);
                    154:             Clear(acc);
                    155:       end if;
                    156:       acc := ek-z(k);
                    157:       absacc1 := AbsVal(acc);
                    158:       absacc2 := AbsVal(a(k,k));
                    159:       if absacc1 > absacc2
                    160:        then s := absacc2/absacc1;
                    161:             Mul(z,s);
                    162:             Mul(ek,s);
                    163:             Clear(s);
                    164:       end if;
                    165:       Clear(absacc1); Clear(absacc2);
                    166:       Clear(acc);
                    167:       wk := ek - z(k);
                    168:       wkm := -ek;
                    169:       Clear(ek);
                    170:       Sub(wkm,z(k));
                    171:       s := AbsVal(wk);
                    172:       sm := AbsVal(wkm);
                    173:       acc := AbsVal(a(k,k));
                    174:       if Equal(acc,zero)
                    175:        then Copy(one,wk);
                    176:             Copy(one,wkm);
                    177:        else wk := wk / a(k,k);
                    178:             wkm := wkm / a(k,k);
                    179:       end if;
                    180:       Clear(acc);
                    181:       kp1 := k + 1;
                    182:       if kp1 <= n
                    183:        then for j in kp1..n loop
                    184:               acc := wkm*a(k,j);
                    185:               Add(acc,z(j));
                    186:               absacc1 := AbsVal(acc);
                    187:               Add(sm,absacc1);
                    188:               Clear(acc); Clear(absacc1);
                    189:               acc := wk*a(k,j);
                    190:               Add(z(j),acc);
                    191:               Clear(acc);
                    192:               absacc1 := AbsVal(z(j));
                    193:               Add(s,absacc1);
                    194:             end loop;
                    195:             if s < sm
                    196:              then t := wkm - wk;
                    197:                   Copy(wkm,wk);
                    198:                   for j in kp1..n loop
                    199:                     acc := t*a(k,j);
                    200:                     Add(z(j),acc);
                    201:                     Clear(acc);
                    202:                   end loop;
                    203:                   Clear(t);
                    204:             end if;
                    205:       end if;
                    206:       Copy(wk,z(k)); Clear(wk); Clear(wkm);
                    207:       Clear(s); Clear(sm);
                    208:     end loop;
                    209:    -- put_line("Gone through first k loop");
                    210:     s := Inverse_Abs_Sum(z);
                    211:     Mul(z,s); Clear(s);
                    212:    -- put_line("At start of second k loop");
                    213:     for k in 1..n loop                              -- solve ctrans(l)*y = w
                    214:       kb := n+1-k;
                    215:       if kb < n
                    216:        then Copy(zero,t);
                    217:             for i in (kb+1)..n loop
                    218:               acc := a(i,kb)*z(i);
                    219:               Add(t,acc);
                    220:               Clear(acc);
                    221:             end loop;
                    222:             Add(z(kb),t); Clear(t);
                    223:       end if;
                    224:      -- put_line("In the middle of second k loop");
                    225:       acc := AbsVal(z(kb));
                    226:       if acc > one
                    227:        then s := one / acc;
                    228:             Mul(z,s); Clear(s);
                    229:       end if;
                    230:       Clear(acc);
                    231:       l := ipvtt(kb);
                    232:      -- put_line("Just before copying in second k loop");
                    233:       if l /= kb
                    234:        then Copy(z(l),t);
                    235:             Copy(z(kb),z(l));
                    236:             Copy(t,z(kb)); Clear(t);
                    237:       end if;
                    238:      -- put_line("At end of one stage of second k loop");
                    239:     end loop;
                    240:    -- put_line("At end of second k loop");
                    241:     s := Inverse_Abs_Sum(z);
                    242:     Mul(z,s); Clear(s);
                    243:     Copy(one,ynorm);
                    244:    -- put_line("At start of third k loop");
                    245:     for k in 1..n loop                                      -- solve l*v = y
                    246:       l := ipvtt(k);
                    247:       if l /= k
                    248:        then Copy(z(l),t);
                    249:             Copy(z(k),z(l));
                    250:             Copy(t,z(k));
                    251:        else Copy(z(l),t);
                    252:       end if;
                    253:       if k < n
                    254:        then for i in (k+1)..n loop
                    255:               acc := t*a(i,k);
                    256:               Add(z(i),acc);
                    257:               Clear(acc);
                    258:             end loop;
                    259:       end if;
                    260:       Clear(t);
                    261:       acc := AbsVal(z(k));
                    262:       if acc > one
                    263:        then s := one / acc;
                    264:             Mul(z,s);
                    265:             Mul(ynorm,s); Clear(s);
                    266:       end if;
                    267:       Clear(acc);
                    268:     end loop;
                    269:    -- put_line("At end of third k loop");
                    270:     s := Inverse_Abs_Sum(z);
                    271:     Mul(z,s);
                    272:     Mul(ynorm,s); Clear(s);
                    273:    -- put_line("At start of fourth k loop");
                    274:     for k in 1..n loop                                      -- solve u*z = v
                    275:       kb := n+1-k;
                    276:       absacc1 := AbsVal(z(kb));
                    277:       absacc2 := AbsVal(a(kb,kb));
                    278:       if absacc1 > absacc2
                    279:        then s := absacc2 / absacc1;
                    280:             Mul(z,s);
                    281:             Mul(ynorm,s); Clear(s);
                    282:       end if;
                    283:       Clear(absacc1);
                    284:       if Equal(absacc2,zero)
                    285:        then Copy(one,z(kb));
                    286:        else Div(z(kb),a(kb,kb));
                    287:       end if;
                    288:       Clear(absacc2);
                    289:       t := -z(kb);
                    290:       for i in 1..(kb-1) loop
                    291:         acc := t*a(i,kb);
                    292:         Add(z(i),acc);
                    293:         Clear(acc);
                    294:       end loop;
                    295:       Clear(t);
                    296:     end loop;
                    297:     s := Inverse_Abs_Sum(z);                             -- make znorm = 1.0
                    298:     Mul(z,s);
                    299:     Mul(ynorm,s); Clear(s);
                    300:     if Equal(anorm,zero)
                    301:      then Copy(zero,rcond);
                    302:      else rcond := ynorm/anorm;
                    303:     end if;
                    304:   end lufco;
                    305:
                    306:   procedure lusolve ( a : in matrix; n : in natural;
                    307:                       ipvt : in Standard_Natural_Vectors.Vector;
                    308:                       b : in out Vectors.vector ) is
                    309:
                    310:     l,nm1,kb : integer;
                    311:     temp,acc : number;
                    312:
                    313:   begin
                    314:     nm1 := n-1;
                    315:     if nm1 >= 1                                             -- solve l*y = b
                    316:      then for k in 1..nm1 loop
                    317:             l := ipvt(k);
                    318:             Copy(b(l),temp);
                    319:             if l /= k
                    320:              then Copy(b(k),b(l));
                    321:                   Copy(temp,b(k));
                    322:             end if;
                    323:             for i in (k+1)..n loop
                    324:               acc := temp*a(i,k);
                    325:               Add(b(i),acc);
                    326:               Clear(acc);
                    327:             end loop;
                    328:             Clear(temp);
                    329:           end loop;
                    330:     end if;
                    331:     for k in 1..n loop                                      -- solve u*x = y
                    332:       kb := n+1-k;
                    333:       Div(b(kb),a(kb,kb));
                    334:       temp := -b(kb);
                    335:       for j in 1..(kb-1) loop
                    336:         acc := temp*a(j,kb);
                    337:         Add(b(j),acc);
                    338:         Clear(acc);
                    339:       end loop;
                    340:       Clear(temp);
                    341:     end loop;
                    342:   end lusolve;
                    343:
                    344:   procedure Triangulate ( a : in out Matrix; n,m : in integer ) is
                    345:
                    346:     pivot,k,kcolumn : integer;
                    347:     max,temp,acc : number;
                    348:
                    349:   begin
                    350:     k := 1;
                    351:     kcolumn := 1;
                    352:     while (k <= n) and (kcolumn <= m) loop
                    353:       max := zero;                                            -- find pivot
                    354:       for l in k..n loop
                    355:         if AbsVal(a(l,kcolumn)) > max
                    356:          then max := AbsVal(a(l,kcolumn));
                    357:               pivot := l;
                    358:         end if;
                    359:       end loop;
                    360:       if Equal(max,zero)
                    361:        then kcolumn := kcolumn + 1;
                    362:        else if pivot /= k                       -- interchange if necessary
                    363:              then for i in 1..m loop
                    364:                     temp := a(pivot,i);
                    365:                     a(pivot,i) := a(k,i);
                    366:                     a(k,i) := temp;
                    367:                   end loop;
                    368:             end if;
                    369:             for j in (kcolumn+1)..m loop                   -- triangulate a
                    370:               Div(a(k,j),a(k,kcolumn));
                    371:             end loop;
                    372:             Copy(one,a(k,kcolumn));
                    373:             for i in (k+1)..n loop
                    374:               for j in (kcolumn+1)..m loop
                    375:                 acc := a(i,kcolumn)*a(k,j);
                    376:                 Sub(a(i,j),acc);
                    377:                 Clear(acc);
                    378:               end loop;
                    379:             end loop;
                    380:             for j in (k+1)..n loop
                    381:               Copy(zero,a(j,kcolumn));
                    382:             end loop;
                    383:             k := k + 1;
                    384:             kcolumn := kcolumn + 1;
                    385:        end if;
                    386:     end loop;
                    387:   end Triangulate;
                    388:
                    389:   procedure Diagonalize ( a : in out Matrix; n,m : in integer ) is
                    390:
                    391:     max,temp,acc : number;
                    392:     pivot,k,kcolumn : integer;
                    393:
                    394:   begin
                    395:     k := 1;
                    396:     kcolumn := 1;
                    397:     while (k <= n) and (kcolumn <= m) loop
                    398:       max := zero;                                              -- find pivot
                    399:       for l in k..n loop
                    400:         if AbsVal(a(l,kcolumn)) > max
                    401:          then max := AbsVal(a(l,kcolumn));
                    402:               pivot := l;
                    403:         end if;
                    404:       end loop;
                    405:       if Equal(max,zero)
                    406:        then kcolumn := kcolumn + 1;
                    407:        else if pivot /= k                       -- interchange if necessary
                    408:              then for i in 1..m loop
                    409:                     temp := a(pivot,i);
                    410:                     a(pivot,i) := a(k,i);
                    411:                     a(k,i) := temp;
                    412:                   end loop;
                    413:             end if;
                    414:             for j in (kcolumn+1)..m loop                   -- diagonalize a
                    415:               Div(a(k,j),a(k,kcolumn));
                    416:             end loop;
                    417:             Copy(one,a(k,kcolumn));
                    418:             for i in 1..(k-1) loop
                    419:               for j in (kcolumn+1)..m loop
                    420:                 acc := a(i,kcolumn)*a(k,j);
                    421:                 Sub(a(i,j),acc);
                    422:                 Clear(acc);
                    423:               end loop;
                    424:             end loop;
                    425:             for i in (k+1)..n loop
                    426:               for j in (kcolumn+1)..m loop
                    427:                 acc := a(i,kcolumn)*a(k,j);
                    428:                 Sub(a(i,j),acc);
                    429:                 Clear(acc);
                    430:               end loop;
                    431:             end loop;
                    432:             for j in 1..(k-1) loop
                    433:               Copy(zero,a(j,kcolumn));
                    434:             end loop;
                    435:             for j in (k+1)..n loop
                    436:               Copy(zero,a(j,kcolumn));
                    437:             end loop;
                    438:             k := k + 1;
                    439:             kcolumn := kcolumn + 1;
                    440:       end if;
                    441:     end loop;
                    442:   end Diagonalize;
                    443:
                    444: -- DYNAMIC TRIANGULATORS :
                    445:
                    446:   procedure Upper_Triangulate
                    447:                ( row : in natural; mat : in out Matrix; tol : in number;
                    448:                  ipvt : in out Standard_Natural_Vectors.Vector;
                    449:                  pivot : out integer ) is
                    450:
                    451:    factor,tmp,max,acc : number;
                    452:    piv,tpi : integer := 0;
                    453:
                    454:   begin
                    455:     for j in mat'first(1)..row-1 loop
                    456:       if AbsVal(mat(row,j)) > tol                 -- make mat(row,j) zero
                    457:        then factor := mat(row,j)/mat(j,j);
                    458:             for k in j..mat'last(2) loop
                    459:               acc := factor*mat(j,k);
                    460:               Sub(mat(row,k),acc);
                    461:               Clear(acc);
                    462:             end loop;
                    463:       end if;
                    464:     end loop;
                    465:     for j in row..ipvt'last loop             -- search pivot
                    466:       tmp := AbsVal(mat(row,j));
                    467:       if tmp > tol
                    468:        then if piv = 0
                    469:              then max := tmp; piv := j;
                    470:              elsif tmp > max
                    471:                  then max := tmp; piv := j;
                    472:             end if;
                    473:       end if;
                    474:     end loop;
                    475:     pivot := piv;
                    476:     if piv /= 0                                -- zero row
                    477:      then if piv /= row                        -- interchange columns
                    478:            then for k in mat'range(1) loop
                    479:                   tmp := mat(k,row); mat(k,row) := mat(k,piv);
                    480:                   mat(k,piv) := tmp;
                    481:                 end loop;
                    482:                 tpi := ipvt(row); ipvt(row) := ipvt(piv); ipvt(piv) := tpi;
                    483:           end if;
                    484:     end if;
                    485:   end Upper_Triangulate;
                    486:
                    487:   procedure Upper_Triangulate
                    488:                ( roweli : in natural; elim : in Matrix; tol : in number;
                    489:                  rowmat : in natural; mat : in out Matrix ) is
                    490:
                    491:     factor,acc : number;
                    492:
                    493:   begin
                    494:     if AbsVal(mat(rowmat,roweli)) > tol
                    495:      then factor := mat(rowmat,roweli)/elim(roweli,roweli);
                    496:           for i in roweli..mat'last(2) loop
                    497:             acc := factor*elim(roweli,i);
                    498:             Sub(mat(rowmat,i),acc);
                    499:             Clear(acc);
                    500:           end loop;
                    501:     end if;
                    502:   end Upper_Triangulate;
                    503:
                    504:   procedure Upper_Triangulate
                    505:                ( roweli : in natural; elim : in Matrix; tol : in number;
                    506:                  firstrow,lastrow : in natural; mat : in out Matrix ) is
                    507:   begin
                    508:     for i in firstrow..lastrow loop
                    509:       Upper_Triangulate(roweli,elim,tol,i,mat);
                    510:     end loop;
                    511:   end Upper_Triangulate;
                    512:
                    513:   procedure Switch ( ipvt : in Standard_Natural_Vectors.Vector;
                    514:                      row : in integer; mat : in out Matrix ) is
                    515:
                    516:     tmp : Vectors.Vector(mat'range(2));
                    517:
                    518:   begin
                    519:     for k in tmp'range loop
                    520:       tmp(k) := mat(row,k);
                    521:     end loop;
                    522:     for k in ipvt'range loop
                    523:       mat(row,k) := tmp(ipvt(k));
                    524:     end loop;
                    525:     for k in ipvt'last+1..mat'last(2) loop
                    526:       mat(row,k) := tmp(k);
                    527:     end loop;
                    528:   end Switch;
                    529:
                    530:   procedure Switch ( k,pivot,first,last : in integer; mat : in out Matrix ) is
                    531:
                    532:     tmp : number;
                    533:
                    534:   begin
                    535:     if k /= pivot
                    536:      then for i in first..last loop
                    537:             tmp := mat(i,k);
                    538:             mat(i,k) := mat(i,pivot);
                    539:             mat(i,pivot) := tmp;
                    540:           end loop;
                    541:     end if;
                    542:   end Switch;
                    543:
                    544:   function Solve ( mat : Matrix; tol : number;
                    545:                    ipvt : Standard_Natural_Vectors.Vector )
                    546:                  return Vectors.Vector is
                    547:
                    548:     res,x : Vectors.Vector(mat'range(2)) := (mat'range(2) => zero);
                    549:     index : integer;
                    550:     acc : number;
                    551:
                    552:   begin
                    553:     for i in mat'range(1) loop
                    554:       index := i;
                    555:       exit when i > mat'last(2);
                    556:       exit when AbsVal(mat(i,i)) < tol;
                    557:     end loop;
                    558:     if (AbsVal(mat(index,index)) > tol) and then (index < mat'last(2))
                    559:      then index := index + 1;
                    560:     end if;
                    561:     Copy(one,x(index));
                    562:     for i in reverse mat'first(1)..(index-1) loop
                    563:       x(i) := -mat(i,index);
                    564:       for j in i+1..index-1 loop
                    565:         acc := mat(i,j)*x(j);
                    566:         Sub(x(i),acc);
                    567:         Clear(acc);
                    568:       end loop;
                    569:       Div(x(i),mat(i,i));
                    570:     end loop;
                    571:     for k in ipvt'range loop
                    572:       res(ipvt(k)) := x(k);
                    573:     end loop;
                    574:     for k in ipvt'last+1..res'last loop
                    575:       res(k) := x(k);
                    576:     end loop;
                    577:     return res;
                    578:   end Solve;
                    579:
                    580:   function Solve ( n,col : natural; mat : Matrix )
                    581:                  return Vectors.Vector is
                    582:
                    583:     res : Vectors.Vector(1..n+1);
                    584:     acc : number;
                    585:
                    586:   begin
                    587:     Copy(one,res(n+1));
                    588:     for i in reverse 1..n loop
                    589:       res(i) := -mat(i,col);
                    590:       for j in i+1..n loop
                    591:         acc := mat(i,j)*res(j);
                    592:         Sub(res(i),acc);
                    593:         Clear(acc);
                    594:       end loop;
                    595:       Div(res(i),mat(i,i));
                    596:     end loop;
                    597:     return res;
                    598:   end Solve;
                    599:
                    600: end Generic_Floating_Linear_Solvers;

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