Mercurial > hg > octave-nkf
comparison liboctave/fMatrix.cc @ 8392:c187f0e3a7ee
use m-file implementation for expm
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Wed, 10 Dec 2008 11:55:23 +0100 |
parents | 25bc2d31e1bf |
children | 5114ea5a41b5 |
comparison
equal
deleted
inserted
replaced
8391:343f0fbca6eb | 8392:c187f0e3a7ee |
---|---|
2570 solve_singularity_warning (float rcon) | 2570 solve_singularity_warning (float rcon) |
2571 { | 2571 { |
2572 (*current_liboctave_warning_handler) | 2572 (*current_liboctave_warning_handler) |
2573 ("singular matrix encountered in expm calculation, rcond = %g", | 2573 ("singular matrix encountered in expm calculation, rcond = %g", |
2574 rcon); | 2574 rcon); |
2575 } | |
2576 | |
2577 FloatMatrix | |
2578 FloatMatrix::expm (void) const | |
2579 { | |
2580 FloatMatrix retval; | |
2581 | |
2582 FloatMatrix m = *this; | |
2583 | |
2584 if (numel () == 1) | |
2585 return FloatMatrix (1, 1, exp (m(0))); | |
2586 | |
2587 octave_idx_type nc = columns (); | |
2588 | |
2589 // Preconditioning step 1: trace normalization to reduce dynamic | |
2590 // range of poles, but avoid making stable eigenvalues unstable. | |
2591 | |
2592 // trace shift value | |
2593 volatile float trshift = 0.0; | |
2594 | |
2595 for (octave_idx_type i = 0; i < nc; i++) | |
2596 trshift += m.elem (i, i); | |
2597 | |
2598 trshift /= nc; | |
2599 | |
2600 if (trshift > 0.0) | |
2601 { | |
2602 for (octave_idx_type i = 0; i < nc; i++) | |
2603 m.elem (i, i) -= trshift; | |
2604 } | |
2605 | |
2606 // Preconditioning step 2: balancing; code follows development | |
2607 // in AEPBAL | |
2608 | |
2609 float *p_m = m.fortran_vec (); | |
2610 | |
2611 octave_idx_type info, ilo, ihi, ilos, ihis; | |
2612 Array<float> dpermute (nc); | |
2613 Array<float> dscale (nc); | |
2614 | |
2615 // permutation first | |
2616 char job = 'P'; | |
2617 F77_XFCN (sgebal, SGEBAL, (F77_CONST_CHAR_ARG2 (&job, 1), | |
2618 nc, p_m, nc, ilo, ihi, | |
2619 dpermute.fortran_vec (), info | |
2620 F77_CHAR_ARG_LEN (1))); | |
2621 | |
2622 // then scaling | |
2623 job = 'S'; | |
2624 F77_XFCN (sgebal, SGEBAL, (F77_CONST_CHAR_ARG2 (&job, 1), | |
2625 nc, p_m, nc, ilos, ihis, | |
2626 dscale.fortran_vec (), info | |
2627 F77_CHAR_ARG_LEN (1))); | |
2628 | |
2629 // Preconditioning step 3: scaling. | |
2630 | |
2631 FloatColumnVector work(nc); | |
2632 float inf_norm; | |
2633 | |
2634 F77_XFCN (xslange, XSLANGE, (F77_CONST_CHAR_ARG2 ("I", 1), | |
2635 nc, nc, m.fortran_vec (), nc, | |
2636 work.fortran_vec (), inf_norm | |
2637 F77_CHAR_ARG_LEN (1))); | |
2638 | |
2639 octave_idx_type sqpow = static_cast<octave_idx_type> (inf_norm > 0.0 | |
2640 ? (1.0 + log (inf_norm) / log (2.0)) | |
2641 : 0.0); | |
2642 | |
2643 // Check whether we need to square at all. | |
2644 | |
2645 if (sqpow < 0) | |
2646 sqpow = 0; | |
2647 | |
2648 if (sqpow > 0) | |
2649 { | |
2650 if (sqpow > 1023) | |
2651 sqpow = 1023; | |
2652 | |
2653 float scale_factor = 1.0; | |
2654 for (octave_idx_type i = 0; i < sqpow; i++) | |
2655 scale_factor *= 2.0; | |
2656 | |
2657 m = m / scale_factor; | |
2658 } | |
2659 | |
2660 // npp, dpp: pade' approx polynomial matrices. | |
2661 | |
2662 FloatMatrix npp (nc, nc, 0.0); | |
2663 float *pnpp = npp.fortran_vec (); | |
2664 FloatMatrix dpp = npp; | |
2665 float *pdpp = dpp.fortran_vec (); | |
2666 | |
2667 // Now powers a^8 ... a^1. | |
2668 | |
2669 octave_idx_type minus_one_j = -1; | |
2670 for (octave_idx_type j = 7; j >= 0; j--) | |
2671 { | |
2672 for (octave_idx_type i = 0; i < nc; i++) | |
2673 { | |
2674 octave_idx_type k = i * nc + i; | |
2675 pnpp[k] += padec[j]; | |
2676 pdpp[k] += minus_one_j * padec[j]; | |
2677 } | |
2678 | |
2679 npp = m * npp; | |
2680 pnpp = npp.fortran_vec (); | |
2681 | |
2682 dpp = m * dpp; | |
2683 pdpp = dpp.fortran_vec (); | |
2684 | |
2685 minus_one_j *= -1; | |
2686 } | |
2687 | |
2688 // Zero power. | |
2689 | |
2690 dpp = -dpp; | |
2691 for (octave_idx_type j = 0; j < nc; j++) | |
2692 { | |
2693 npp.elem (j, j) += 1.0; | |
2694 dpp.elem (j, j) += 1.0; | |
2695 } | |
2696 | |
2697 // Compute pade approximation = inverse (dpp) * npp. | |
2698 | |
2699 float rcon; | |
2700 retval = dpp.solve (npp, info, rcon, solve_singularity_warning); | |
2701 | |
2702 if (info < 0) | |
2703 return retval; | |
2704 | |
2705 // Reverse preconditioning step 3: repeated squaring. | |
2706 | |
2707 while (sqpow) | |
2708 { | |
2709 retval = retval * retval; | |
2710 sqpow--; | |
2711 } | |
2712 | |
2713 // Reverse preconditioning step 2: inverse balancing. | |
2714 // apply inverse scaling to computed exponential | |
2715 for (octave_idx_type i = 0; i < nc; i++) | |
2716 for (octave_idx_type j = 0; j < nc; j++) | |
2717 retval(i,j) *= dscale(i) / dscale(j); | |
2718 | |
2719 OCTAVE_QUIT; | |
2720 | |
2721 // construct balancing permutation vector | |
2722 Array<octave_idx_type> iperm (nc); | |
2723 for (octave_idx_type i = 0; i < nc; i++) | |
2724 iperm(i) = i; // identity permutation | |
2725 | |
2726 // trailing permutations must be done in reverse order | |
2727 for (octave_idx_type i = nc - 1; i >= ihi; i--) | |
2728 { | |
2729 octave_idx_type swapidx = static_cast<octave_idx_type> (dpermute(i)) - 1; | |
2730 octave_idx_type tmp = iperm(i); | |
2731 iperm(i) = iperm(swapidx); | |
2732 iperm(swapidx) = tmp; | |
2733 } | |
2734 | |
2735 // leading permutations in forward order | |
2736 for (octave_idx_type i = 0; i < (ilo-1); i++) | |
2737 { | |
2738 octave_idx_type swapidx = static_cast<octave_idx_type> (dpermute(i)) - 1; | |
2739 octave_idx_type tmp = iperm(i); | |
2740 iperm(i) = iperm (swapidx); | |
2741 iperm(swapidx) = tmp; | |
2742 } | |
2743 | |
2744 // construct inverse balancing permutation vector | |
2745 Array<octave_idx_type> invpvec (nc); | |
2746 for (octave_idx_type i = 0; i < nc; i++) | |
2747 invpvec(iperm(i)) = i; // Thanks to R. A. Lippert for this method | |
2748 | |
2749 OCTAVE_QUIT; | |
2750 | |
2751 FloatMatrix tmpMat = retval; | |
2752 for (octave_idx_type i = 0; i < nc; i++) | |
2753 for (octave_idx_type j = 0; j < nc; j++) | |
2754 retval(i,j) = tmpMat(invpvec(i),invpvec(j)); | |
2755 | |
2756 // Reverse preconditioning step 1: fix trace normalization. | |
2757 | |
2758 if (trshift > 0.0) | |
2759 retval = expf (trshift) * retval; | |
2760 | |
2761 return retval; | |
2762 } | 2575 } |
2763 | 2576 |
2764 FloatMatrix& | 2577 FloatMatrix& |
2765 FloatMatrix::operator += (const FloatDiagMatrix& a) | 2578 FloatMatrix::operator += (const FloatDiagMatrix& a) |
2766 { | 2579 { |