comparison liboctave/CSparse.cc @ 5506:b4cfbb0ec8c4

[project @ 2005-10-23 19:09:32 by dbateman]
author dbateman
date Sun, 23 Oct 2005 19:09:33 +0000
parents ed08548b9054
children 8c56849b1509
comparison
equal deleted inserted replaced
5505:17682e3fba2a 5506:b4cfbb0ec8c4
39 #include "boolSparse.h" 39 #include "boolSparse.h"
40 #include "dSparse.h" 40 #include "dSparse.h"
41 #include "oct-spparms.h" 41 #include "oct-spparms.h"
42 #include "SparseCmplxLU.h" 42 #include "SparseCmplxLU.h"
43 #include "oct-sparse.h" 43 #include "oct-sparse.h"
44 #include "sparse-util.h"
45 #include "SparseCmplxCHOL.h"
44 46
45 // Fortran functions we call. 47 // Fortran functions we call.
46 extern "C" 48 extern "C"
47 { 49 {
48 F77_RET_T 50 F77_RET_T
583 SparseComplexMatrix 585 SparseComplexMatrix
584 SparseComplexMatrix::inverse (void) const 586 SparseComplexMatrix::inverse (void) const
585 { 587 {
586 octave_idx_type info; 588 octave_idx_type info;
587 double rcond; 589 double rcond;
588 return inverse (info, rcond, 0, 0); 590 SparseType mattype (*this);
591 return inverse (mattype, info, rcond, 0, 0);
589 } 592 }
590 593
591 SparseComplexMatrix 594 SparseComplexMatrix
592 SparseComplexMatrix::inverse (octave_idx_type& info) const 595 SparseComplexMatrix::inverse (SparseType& mattype) const
593 { 596 {
597 octave_idx_type info;
594 double rcond; 598 double rcond;
595 return inverse (info, rcond, 0, 0); 599 return inverse (mattype, info, rcond, 0, 0);
596 } 600 }
597 601
598 SparseComplexMatrix 602 SparseComplexMatrix
599 SparseComplexMatrix::inverse (octave_idx_type& info, double& rcond, int force, 603 SparseComplexMatrix::inverse (SparseType& mattype, octave_idx_type& info) const
600 int calc_cond) const 604 {
601 { 605 double rcond;
602 info = -1; 606 return inverse (mattype, info, rcond, 0, 0);
603 (*current_liboctave_error_handler) 607 }
604 ("SparseComplexMatrix::inverse not implemented yet"); 608
605 return SparseComplexMatrix (); 609 SparseComplexMatrix
610 SparseComplexMatrix::dinverse (SparseType &mattyp, octave_idx_type& info,
611 double& rcond, const bool force,
612 const bool calccond) const
613 {
614 SparseComplexMatrix retval;
615
616 octave_idx_type nr = rows ();
617 octave_idx_type nc = cols ();
618 info = 0;
619
620 if (nr == 0 || nc == 0 || nr != nc)
621 (*current_liboctave_error_handler) ("inverse requires square matrix");
622 else
623 {
624 // Print spparms("spumoni") info if requested
625 int typ = mattyp.type ();
626 mattyp.info ();
627
628 if (typ == SparseType::Diagonal ||
629 typ == SparseType::Permuted_Diagonal)
630 {
631 if (typ == SparseType::Permuted_Diagonal)
632 retval = transpose();
633 else
634 retval = *this;
635
636 // Force make_unique to be called
637 Complex *v = retval.data();
638
639 if (calccond)
640 {
641 double dmax = 0., dmin = octave_Inf;
642 for (octave_idx_type i = 0; i < nr; i++)
643 {
644 double tmp = std::abs(v[i]);
645 if (tmp > dmax)
646 dmax = tmp;
647 if (tmp < dmin)
648 dmin = tmp;
649 }
650 rcond = dmin / dmax;
651 }
652
653 for (octave_idx_type i = 0; i < nr; i++)
654 v[i] = 1.0 / v[i];
655 }
656 else
657 (*current_liboctave_error_handler) ("incorrect matrix type");
658 }
659
660 return retval;
661 }
662
663 SparseComplexMatrix
664 SparseComplexMatrix::tinverse (SparseType &mattyp, octave_idx_type& info,
665 double& rcond, const bool force,
666 const bool calccond) const
667 {
668 SparseComplexMatrix retval;
669
670 octave_idx_type nr = rows ();
671 octave_idx_type nc = cols ();
672 info = 0;
673
674 if (nr == 0 || nc == 0 || nr != nc)
675 (*current_liboctave_error_handler) ("inverse requires square matrix");
676 else
677 {
678 // Print spparms("spumoni") info if requested
679 int typ = mattyp.type ();
680 mattyp.info ();
681
682 if (typ == SparseType::Upper || typ == SparseType::Permuted_Upper ||
683 typ == SparseType::Lower || typ == SparseType::Permuted_Lower)
684 {
685 double anorm = 0.;
686 double ainvnorm = 0.;
687
688 if (calccond)
689 {
690 // Calculate the 1-norm of matrix for rcond calculation
691 for (octave_idx_type j = 0; j < nr; j++)
692 {
693 double atmp = 0.;
694 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++)
695 atmp += std::abs(data(i));
696 if (atmp > anorm)
697 anorm = atmp;
698 }
699 }
700
701 if (typ == SparseType::Upper || typ == SparseType::Lower)
702 {
703 octave_idx_type nz = nnz();
704 octave_idx_type cx = 0;
705 octave_idx_type nz2 = nz;
706 retval = SparseComplexMatrix (nr, nc, nz2);
707
708 for (octave_idx_type i = 0; i < nr; i++)
709 {
710 OCTAVE_QUIT;
711 // place the 1 in the identity position
712 octave_idx_type cx_colstart = cx;
713
714 if (cx == nz2)
715 {
716 nz2 *= 2;
717 retval.change_capacity (nz2);
718 }
719
720 retval.xcidx(i) = cx;
721 retval.xridx(cx) = i;
722 retval.xdata(cx) = 1.0;
723 cx++;
724
725 // iterate accross columns of input matrix
726 for (octave_idx_type j = i+1; j < nr; j++)
727 {
728 Complex v = 0.;
729 // iterate to calculate sum
730 octave_idx_type colXp = retval.xcidx(i);
731 octave_idx_type colUp = cidx(j);
732 octave_idx_type rpX, rpU;
733 do
734 {
735 OCTAVE_QUIT;
736 rpX = retval.xridx(colXp);
737 rpU = ridx(colUp);
738
739 if (rpX < rpU)
740 colXp++;
741 else if (rpX > rpU)
742 colUp++;
743 else
744 {
745 v -= retval.xdata(colXp) * data(colUp);
746 colXp++;
747 colUp++;
748 }
749 } while ((rpX<j) && (rpU<j) &&
750 (colXp<cx) && (colUp<nz));
751
752 // get A(m,m)
753 colUp = cidx(j+1) - 1;
754 Complex pivot = data(colUp);
755 if (pivot == 0.)
756 (*current_liboctave_error_handler)
757 ("division by zero");
758
759 if (v != 0.)
760 {
761 if (cx == nz2)
762 {
763 nz2 *= 2;
764 retval.change_capacity (nz2);
765 }
766
767 retval.xridx(cx) = j;
768 retval.xdata(cx) = v / pivot;
769 cx++;
770 }
771 }
772
773 // get A(m,m)
774 octave_idx_type colUp = cidx(i+1) - 1;
775 Complex pivot = data(colUp);
776 if (pivot == 0.)
777 (*current_liboctave_error_handler) ("division by zero");
778
779 if (pivot != 1.0)
780 for (octave_idx_type j = cx_colstart; j < cx; j++)
781 retval.xdata(j) /= pivot;
782 }
783 retval.xcidx(nr) = cx;
784 retval.maybe_compress ();
785 }
786 else
787 {
788 octave_idx_type nz = nnz();
789 octave_idx_type cx = 0;
790 octave_idx_type nz2 = nz;
791 retval = SparseComplexMatrix (nr, nc, nz2);
792
793 OCTAVE_LOCAL_BUFFER (Complex, work, nr);
794 OCTAVE_LOCAL_BUFFER (octave_idx_type, rperm, nr);
795
796 octave_idx_type *perm = mattyp.triangular_perm();
797 if (typ == SparseType::Permuted_Upper)
798 {
799 for (octave_idx_type i = 0; i < nr; i++)
800 rperm[perm[i]] = i;
801 }
802 else
803 {
804 for (octave_idx_type i = 0; i < nr; i++)
805 rperm[i] = perm[i];
806 for (octave_idx_type i = 0; i < nr; i++)
807 perm[rperm[i]] = i;
808 }
809
810 for (octave_idx_type i = 0; i < nr; i++)
811 {
812 OCTAVE_QUIT;
813 octave_idx_type iidx = rperm[i];
814
815 for (octave_idx_type j = 0; j < nr; j++)
816 work[j] = 0.;
817
818 // place the 1 in the identity position
819 work[iidx] = 1.0;
820
821 // iterate accross columns of input matrix
822 for (octave_idx_type j = iidx+1; j < nr; j++)
823 {
824 Complex v = 0.;
825 octave_idx_type jidx = perm[j];
826 // iterate to calculate sum
827 for (octave_idx_type k = cidx(jidx);
828 k < cidx(jidx+1); k++)
829 {
830 OCTAVE_QUIT;
831 v -= work[ridx(k)] * data(k);
832 }
833
834 // get A(m,m)
835 Complex pivot = data(cidx(jidx+1) - 1);
836 if (pivot == 0.)
837 (*current_liboctave_error_handler)
838 ("division by zero");
839
840 work[j] = v / pivot;
841 }
842
843 // get A(m,m)
844 octave_idx_type colUp = cidx(perm[iidx]+1) - 1;
845 Complex pivot = data(colUp);
846 if (pivot == 0.)
847 (*current_liboctave_error_handler)
848 ("division by zero");
849
850 octave_idx_type new_cx = cx;
851 for (octave_idx_type j = iidx; j < nr; j++)
852 if (work[j] != 0.0)
853 {
854 new_cx++;
855 if (pivot != 1.0)
856 work[j] /= pivot;
857 }
858
859 if (cx < new_cx)
860 {
861 nz2 = (2*nz2 < new_cx ? new_cx : 2*nz2);
862 retval.change_capacity (nz2);
863 }
864
865 retval.xcidx(i) = cx;
866 for (octave_idx_type j = iidx; j < nr; j++)
867 if (work[j] != 0.)
868 {
869 retval.xridx(cx) = j;
870 retval.xdata(cx++) = work[j];
871 }
872 }
873
874 retval.xcidx(nr) = cx;
875 retval.maybe_compress ();
876 }
877
878 if (calccond)
879 {
880 // Calculate the 1-norm of inverse matrix for rcond calculation
881 for (octave_idx_type j = 0; j < nr; j++)
882 {
883 double atmp = 0.;
884 for (octave_idx_type i = retval.cidx(j);
885 i < retval.cidx(j+1); i++)
886 atmp += std::abs(retval.data(i));
887 if (atmp > ainvnorm)
888 ainvnorm = atmp;
889 }
890
891 rcond = 1. / ainvnorm / anorm;
892 }
893 }
894 else
895 (*current_liboctave_error_handler) ("incorrect matrix type");
896 }
897
898 return retval;
899 }
900
901 SparseComplexMatrix
902 SparseComplexMatrix::inverse (SparseType& mattype, octave_idx_type& info,
903 double& rcond, int force, int calc_cond) const
904 {
905 int typ = mattype.type (false);
906 SparseComplexMatrix ret;
907
908 if (typ == SparseType::Unknown)
909 typ = mattype.type (*this);
910
911 if (typ == SparseType::Diagonal || typ == SparseType::Permuted_Diagonal)
912 ret = dinverse (mattype, info, rcond, true, calc_cond);
913 else if (typ == SparseType::Upper || typ == SparseType::Permuted_Upper)
914 ret = tinverse (mattype, info, rcond, true, calc_cond).transpose();
915 else if (typ == SparseType::Lower || typ == SparseType::Permuted_Lower)
916 ret = transpose().tinverse (mattype, info, rcond, true, calc_cond);
917 else if (typ != SparseType::Rectangular)
918 {
919 if (mattype.is_hermitian())
920 {
921 SparseType tmp_typ (SparseType::Upper);
922 SparseComplexCHOL fact (*this, info, false);
923 rcond = fact.rcond();
924 if (info == 0)
925 {
926 double rcond2;
927 SparseMatrix Q = fact.Q();
928 SparseComplexMatrix InvL = fact.L().transpose().
929 tinverse(tmp_typ, info, rcond2, true, false);
930 ret = Q * InvL.hermitian() * InvL * Q.transpose();
931 }
932 else
933 {
934 // Matrix is either singular or not positive definite
935 mattype.mark_as_unsymmetric ();
936 typ = SparseType::Full;
937 }
938 }
939
940 if (!mattype.is_hermitian())
941 {
942 octave_idx_type n = rows();
943 ColumnVector Qinit(n);
944 for (octave_idx_type i = 0; i < n; i++)
945 Qinit(i) = i;
946
947 SparseType tmp_typ (SparseType::Upper);
948 SparseComplexLU fact (*this, Qinit, -1.0, false);
949 rcond = fact.rcond();
950 double rcond2;
951 SparseComplexMatrix InvL = fact.L().transpose().
952 tinverse(tmp_typ, info, rcond2, true, false);
953 SparseComplexMatrix InvU = fact.U().
954 tinverse(tmp_typ, info, rcond2, true, false).transpose();
955 ret = fact.Pc().transpose() * InvU * InvL * fact.Pr();
956 }
957 }
958 else
959 (*current_liboctave_error_handler) ("inverse requires square matrix");
960
961 return ret;
606 } 962 }
607 963
608 ComplexDET 964 ComplexDET
609 SparseComplexMatrix::determinant (void) const 965 SparseComplexMatrix::determinant (void) const
610 { 966 {
4644 volatile int typ = mattype.type (); 5000 volatile int typ = mattype.type ();
4645 mattype.info (); 5001 mattype.info ();
4646 5002
4647 if (typ == SparseType::Hermitian) 5003 if (typ == SparseType::Hermitian)
4648 { 5004 {
4649 // XXX FIXME XXX Write the cholesky solver and only fall 5005 #ifdef HAVE_CHOLMOD
4650 // through if cholesky factorization fails 5006 cholmod_common Common;
4651 5007 cholmod_common *cm = &Common;
5008
5009 // Setup initial parameters
5010 CHOLMOD_NAME(start) (cm);
5011 cm->prefer_zomplex = FALSE;
5012
5013 double spu = Voctave_sparse_controls.get_key ("spumoni");
5014 if (spu == 0.)
5015 {
5016 cm->print = -1;
5017 cm->print_function = NULL;
5018 }
5019 else
5020 {
5021 cm->print = (int)spu + 2;
5022 cm->print_function =&SparseCholPrint;
5023 }
5024
5025 cm->error_handler = &SparseCholError;
5026 cm->complex_divide = CHOLMOD_NAME(divcomplex);
5027 cm->hypotenuse = CHOLMOD_NAME(hypot);
5028
5029 #ifdef HAVE_METIS
5030 // METIS 4.0.1 uses malloc and free, and will terminate MATLAB if
5031 // it runs out of memory. Use CHOLMOD's memory guard for METIS,
5032 // which mxMalloc's a huge block of memory (and then immediately
5033 // mxFree's it) before calling METIS
5034 cm->metis_memory = 2.0;
5035
5036 #if defined(METIS_VERSION)
5037 #if (METIS_VERSION >= METIS_VER(4,0,2))
5038 // METIS 4.0.2 uses function pointers for malloc and free
5039 METIS_malloc = cm->malloc_memory;
5040 METIS_free = cm->free_memory;
5041 // Turn off METIS memory guard. It is not needed, because mxMalloc
5042 // will safely terminate the mexFunction and free any workspace
5043 // without killing all of octave.
5044 cm->metis_memory = 0.0;
5045 #endif
5046 #endif
5047 #endif
5048
5049 cm->final_ll = TRUE;
5050
5051 cholmod_sparse Astore;
5052 cholmod_sparse *A = &Astore;
5053 double dummy;
5054 A->nrow = nr;
5055 A->ncol = nc;
5056
5057 A->p = cidx();
5058 A->i = ridx();
5059 A->nzmax = nonzero();
5060 A->packed = TRUE;
5061 A->sorted = TRUE;
5062 A->nz = NULL;
5063 #ifdef IDX_TYPE_LONG
5064 A->itype = CHOLMOD_LONG;
5065 #else
5066 A->itype = CHOLMOD_INT;
5067 #endif
5068 A->dtype = CHOLMOD_DOUBLE;
5069 A->stype = 1;
5070 A->xtype = CHOLMOD_COMPLEX;
5071
5072 if (nr < 1)
5073 A->x = &dummy;
5074 else
5075 A->x = data();
5076
5077 cholmod_dense Bstore;
5078 cholmod_dense *B = &Bstore;
5079 B->nrow = b.rows();
5080 B->ncol = b.cols();
5081 B->d = B->nrow;
5082 B->nzmax = B->nrow * B->ncol;
5083 B->dtype = CHOLMOD_DOUBLE;
5084 B->xtype = CHOLMOD_REAL;
5085 if (nc < 1 || b.cols() < 1)
5086 B->x = &dummy;
5087 else
5088 // We won't alter it, honest :-)
5089 B->x = const_cast<double *>(b.fortran_vec());
5090
5091 cholmod_factor *L;
5092 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5093 L = CHOLMOD_NAME(analyze) (A, cm);
5094 CHOLMOD_NAME(factorize) (A, L, cm);
5095 rcond = CHOLMOD_NAME(rcond)(L, cm);
5096 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5097
5098 if (rcond == 0.0)
5099 {
5100 // Either its indefinite or singular. Try UMFPACK
5101 mattype.mark_as_unsymmetric ();
5102 typ = SparseType::Full;
5103 }
5104 else
5105 {
5106 volatile double rcond_plus_one = rcond + 1.0;
5107
5108 if (rcond_plus_one == 1.0 || xisnan (rcond))
5109 {
5110 err = -2;
5111
5112 if (sing_handler)
5113 sing_handler (rcond);
5114 else
5115 (*current_liboctave_error_handler)
5116 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
5117 rcond);
5118
5119 #ifdef HAVE_LSSOLVE
5120 return retval;
5121 #endif
5122 }
5123
5124 cholmod_dense *X;
5125 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5126 X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
5127 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5128
5129 retval.resize (b.rows (), b.cols());
5130 for (octave_idx_type j = 0; j < b.cols(); j++)
5131 {
5132 octave_idx_type jr = j * b.rows();
5133 for (octave_idx_type i = 0; i < b.rows(); i++)
5134 retval.xelem(i,j) = static_cast<Complex *>(X->x)[jr + i];
5135 }
5136
5137 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5138 CHOLMOD_NAME(free_dense) (&X, cm);
5139 CHOLMOD_NAME(free_factor) (&L, cm);
5140 CHOLMOD_NAME(finish) (cm);
5141 CHOLMOD_NAME(print_common) (" ", cm);
5142 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5143 }
5144 #else
4652 (*current_liboctave_warning_handler) 5145 (*current_liboctave_warning_handler)
4653 ("SparseMatrix::solve XXX FIXME XXX Cholesky code not done"); 5146 ("CHOLMOD not installed");
4654 5147
4655 mattype.mark_as_unsymmetric (); 5148 mattype.mark_as_unsymmetric ();
4656 typ = SparseType::Full; 5149 typ = SparseType::Full;
5150 #endif
4657 } 5151 }
4658 5152
4659 if (typ == SparseType::Full) 5153 if (typ == SparseType::Full)
4660 { 5154 {
4661 #ifdef HAVE_UMFPACK 5155 #ifdef HAVE_UMFPACK
4770 (*current_liboctave_error_handler) 5264 (*current_liboctave_error_handler)
4771 ("matrix dimension mismatch solution of linear equations"); 5265 ("matrix dimension mismatch solution of linear equations");
4772 else 5266 else
4773 { 5267 {
4774 // Print spparms("spumoni") info if requested 5268 // Print spparms("spumoni") info if requested
4775 int typ = mattype.type (); 5269 volatile int typ = mattype.type ();
4776 mattype.info (); 5270 mattype.info ();
4777 5271
4778 if (typ == SparseType::Hermitian) 5272 if (typ == SparseType::Hermitian)
4779 { 5273 {
4780 // XXX FIXME XXX Write the cholesky solver and only fall 5274 #ifdef HAVE_CHOLMOD
4781 // through if cholesky factorization fails 5275 cholmod_common Common;
4782 5276 cholmod_common *cm = &Common;
5277
5278 // Setup initial parameters
5279 CHOLMOD_NAME(start) (cm);
5280 cm->prefer_zomplex = FALSE;
5281
5282 double spu = Voctave_sparse_controls.get_key ("spumoni");
5283 if (spu == 0.)
5284 {
5285 cm->print = -1;
5286 cm->print_function = NULL;
5287 }
5288 else
5289 {
5290 cm->print = (int)spu + 2;
5291 cm->print_function =&SparseCholPrint;
5292 }
5293
5294 cm->error_handler = &SparseCholError;
5295 cm->complex_divide = CHOLMOD_NAME(divcomplex);
5296 cm->hypotenuse = CHOLMOD_NAME(hypot);
5297
5298 #ifdef HAVE_METIS
5299 // METIS 4.0.1 uses malloc and free, and will terminate MATLAB if
5300 // it runs out of memory. Use CHOLMOD's memory guard for METIS,
5301 // which mxMalloc's a huge block of memory (and then immediately
5302 // mxFree's it) before calling METIS
5303 cm->metis_memory = 2.0;
5304
5305 #if defined(METIS_VERSION)
5306 #if (METIS_VERSION >= METIS_VER(4,0,2))
5307 // METIS 4.0.2 uses function pointers for malloc and free
5308 METIS_malloc = cm->malloc_memory;
5309 METIS_free = cm->free_memory;
5310 // Turn off METIS memory guard. It is not needed, because mxMalloc
5311 // will safely terminate the mexFunction and free any workspace
5312 // without killing all of octave.
5313 cm->metis_memory = 0.0;
5314 #endif
5315 #endif
5316 #endif
5317
5318 cm->final_ll = TRUE;
5319
5320 cholmod_sparse Astore;
5321 cholmod_sparse *A = &Astore;
5322 double dummy;
5323 A->nrow = nr;
5324 A->ncol = nc;
5325
5326 A->p = cidx();
5327 A->i = ridx();
5328 A->nzmax = nonzero();
5329 A->packed = TRUE;
5330 A->sorted = TRUE;
5331 A->nz = NULL;
5332 #ifdef IDX_TYPE_LONG
5333 A->itype = CHOLMOD_LONG;
5334 #else
5335 A->itype = CHOLMOD_INT;
5336 #endif
5337 A->dtype = CHOLMOD_DOUBLE;
5338 A->stype = 1;
5339 A->xtype = CHOLMOD_COMPLEX;
5340
5341 if (nr < 1)
5342 A->x = &dummy;
5343 else
5344 A->x = data();
5345
5346 cholmod_sparse Bstore;
5347 cholmod_sparse *B = &Bstore;
5348 B->nrow = b.rows();
5349 B->ncol = b.cols();
5350 B->p = b.cidx();
5351 B->i = b.ridx();
5352 B->nzmax = b.nonzero();
5353 B->packed = TRUE;
5354 B->sorted = TRUE;
5355 B->nz = NULL;
5356 #ifdef IDX_TYPE_LONG
5357 B->itype = CHOLMOD_LONG;
5358 #else
5359 B->itype = CHOLMOD_INT;
5360 #endif
5361 B->dtype = CHOLMOD_DOUBLE;
5362 B->stype = 0;
5363 B->xtype = CHOLMOD_REAL;
5364
5365 if (b.rows() < 1 || b.cols() < 1)
5366 B->x = &dummy;
5367 else
5368 B->x = b.data();
5369
5370 cholmod_factor *L;
5371 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5372 L = CHOLMOD_NAME(analyze) (A, cm);
5373 CHOLMOD_NAME(factorize) (A, L, cm);
5374 rcond = CHOLMOD_NAME(rcond)(L, cm);
5375 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5376
5377 if (rcond == 0.0)
5378 {
5379 // Either its indefinite or singular. Try UMFPACK
5380 mattype.mark_as_unsymmetric ();
5381 typ = SparseType::Full;
5382 }
5383 else
5384 {
5385 volatile double rcond_plus_one = rcond + 1.0;
5386
5387 if (rcond_plus_one == 1.0 || xisnan (rcond))
5388 {
5389 err = -2;
5390
5391 if (sing_handler)
5392 sing_handler (rcond);
5393 else
5394 (*current_liboctave_error_handler)
5395 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
5396 rcond);
5397
5398 #ifdef HAVE_LSSOLVE
5399 return retval;
5400 #endif
5401 }
5402
5403 cholmod_sparse *X;
5404 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5405 X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
5406 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5407
5408 retval = SparseComplexMatrix
5409 (static_cast<octave_idx_type>(X->nrow),
5410 static_cast<octave_idx_type>(X->ncol),
5411 static_cast<octave_idx_type>(X->nzmax));
5412 for (octave_idx_type j = 0;
5413 j <= static_cast<octave_idx_type>(X->ncol); j++)
5414 retval.xcidx(j) = static_cast<octave_idx_type *>(X->p)[j];
5415 for (octave_idx_type j = 0;
5416 j < static_cast<octave_idx_type>(X->nzmax); j++)
5417 {
5418 retval.xridx(j) = static_cast<octave_idx_type *>(X->i)[j];
5419 retval.xdata(j) = static_cast<Complex *>(X->x)[j];
5420 }
5421
5422 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5423 CHOLMOD_NAME(free_sparse) (&X, cm);
5424 CHOLMOD_NAME(free_factor) (&L, cm);
5425 CHOLMOD_NAME(finish) (cm);
5426 CHOLMOD_NAME(print_common) (" ", cm);
5427 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5428 }
5429 #else
4783 (*current_liboctave_warning_handler) 5430 (*current_liboctave_warning_handler)
4784 ("SparseMatrix::solve XXX FIXME XXX Cholesky code not done"); 5431 ("CHOLMOD not installed");
4785 5432
4786 mattype.mark_as_unsymmetric (); 5433 mattype.mark_as_unsymmetric ();
4787 typ = SparseType::Full; 5434 typ = SparseType::Full;
5435 #endif
4788 } 5436 }
4789 5437
4790 if (typ == SparseType::Full) 5438 if (typ == SparseType::Full)
4791 { 5439 {
4792 #ifdef HAVE_UMFPACK 5440 #ifdef HAVE_UMFPACK
4930 (*current_liboctave_error_handler) 5578 (*current_liboctave_error_handler)
4931 ("matrix dimension mismatch solution of linear equations"); 5579 ("matrix dimension mismatch solution of linear equations");
4932 else 5580 else
4933 { 5581 {
4934 // Print spparms("spumoni") info if requested 5582 // Print spparms("spumoni") info if requested
4935 int typ = mattype.type (); 5583 volatile int typ = mattype.type ();
4936 mattype.info (); 5584 mattype.info ();
4937 5585
4938 if (typ == SparseType::Hermitian) 5586 if (typ == SparseType::Hermitian)
4939 { 5587 {
4940 // XXX FIXME XXX Write the cholesky solver and only fall 5588 #ifdef HAVE_CHOLMOD
4941 // through if cholesky factorization fails 5589 cholmod_common Common;
4942 5590 cholmod_common *cm = &Common;
5591
5592 // Setup initial parameters
5593 CHOLMOD_NAME(start) (cm);
5594 cm->prefer_zomplex = FALSE;
5595
5596 double spu = Voctave_sparse_controls.get_key ("spumoni");
5597 if (spu == 0.)
5598 {
5599 cm->print = -1;
5600 cm->print_function = NULL;
5601 }
5602 else
5603 {
5604 cm->print = (int)spu + 2;
5605 cm->print_function =&SparseCholPrint;
5606 }
5607
5608 cm->error_handler = &SparseCholError;
5609 cm->complex_divide = CHOLMOD_NAME(divcomplex);
5610 cm->hypotenuse = CHOLMOD_NAME(hypot);
5611
5612 #ifdef HAVE_METIS
5613 // METIS 4.0.1 uses malloc and free, and will terminate MATLAB if
5614 // it runs out of memory. Use CHOLMOD's memory guard for METIS,
5615 // which mxMalloc's a huge block of memory (and then immediately
5616 // mxFree's it) before calling METIS
5617 cm->metis_memory = 2.0;
5618
5619 #if defined(METIS_VERSION)
5620 #if (METIS_VERSION >= METIS_VER(4,0,2))
5621 // METIS 4.0.2 uses function pointers for malloc and free
5622 METIS_malloc = cm->malloc_memory;
5623 METIS_free = cm->free_memory;
5624 // Turn off METIS memory guard. It is not needed, because mxMalloc
5625 // will safely terminate the mexFunction and free any workspace
5626 // without killing all of octave.
5627 cm->metis_memory = 0.0;
5628 #endif
5629 #endif
5630 #endif
5631
5632 cm->final_ll = TRUE;
5633
5634 cholmod_sparse Astore;
5635 cholmod_sparse *A = &Astore;
5636 double dummy;
5637 A->nrow = nr;
5638 A->ncol = nc;
5639
5640 A->p = cidx();
5641 A->i = ridx();
5642 A->nzmax = nonzero();
5643 A->packed = TRUE;
5644 A->sorted = TRUE;
5645 A->nz = NULL;
5646 #ifdef IDX_TYPE_LONG
5647 A->itype = CHOLMOD_LONG;
5648 #else
5649 A->itype = CHOLMOD_INT;
5650 #endif
5651 A->dtype = CHOLMOD_DOUBLE;
5652 A->stype = 1;
5653 A->xtype = CHOLMOD_COMPLEX;
5654
5655 if (nr < 1)
5656 A->x = &dummy;
5657 else
5658 A->x = data();
5659
5660 cholmod_dense Bstore;
5661 cholmod_dense *B = &Bstore;
5662 B->nrow = b.rows();
5663 B->ncol = b.cols();
5664 B->d = B->nrow;
5665 B->nzmax = B->nrow * B->ncol;
5666 B->dtype = CHOLMOD_DOUBLE;
5667 B->xtype = CHOLMOD_COMPLEX;
5668 if (nc < 1 || b.cols() < 1)
5669 B->x = &dummy;
5670 else
5671 // We won't alter it, honest :-)
5672 B->x = const_cast<Complex *>(b.fortran_vec());
5673
5674 cholmod_factor *L;
5675 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5676 L = CHOLMOD_NAME(analyze) (A, cm);
5677 CHOLMOD_NAME(factorize) (A, L, cm);
5678 rcond = CHOLMOD_NAME(rcond)(L, cm);
5679 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5680
5681 if (rcond == 0.0)
5682 {
5683 // Either its indefinite or singular. Try UMFPACK
5684 mattype.mark_as_unsymmetric ();
5685 typ = SparseType::Full;
5686 }
5687 else
5688 {
5689 volatile double rcond_plus_one = rcond + 1.0;
5690
5691 if (rcond_plus_one == 1.0 || xisnan (rcond))
5692 {
5693 err = -2;
5694
5695 if (sing_handler)
5696 sing_handler (rcond);
5697 else
5698 (*current_liboctave_error_handler)
5699 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
5700 rcond);
5701
5702 #ifdef HAVE_LSSOLVE
5703 return retval;
5704 #endif
5705 }
5706
5707 cholmod_dense *X;
5708 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5709 X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
5710 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5711
5712 retval.resize (b.rows (), b.cols());
5713 for (octave_idx_type j = 0; j < b.cols(); j++)
5714 {
5715 octave_idx_type jr = j * b.rows();
5716 for (octave_idx_type i = 0; i < b.rows(); i++)
5717 retval.xelem(i,j) = static_cast<Complex *>(X->x)[jr + i];
5718 }
5719
5720 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5721 CHOLMOD_NAME(free_dense) (&X, cm);
5722 CHOLMOD_NAME(free_factor) (&L, cm);
5723 CHOLMOD_NAME(finish) (cm);
5724 CHOLMOD_NAME(print_common) (" ", cm);
5725 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5726 }
5727 #else
4943 (*current_liboctave_warning_handler) 5728 (*current_liboctave_warning_handler)
4944 ("SparseMatrix::solve XXX FIXME XXX Cholesky code not done"); 5729 ("CHOLMOD not installed");
4945 5730
4946 mattype.mark_as_unsymmetric (); 5731 mattype.mark_as_unsymmetric ();
4947 typ = SparseType::Full; 5732 typ = SparseType::Full;
5733 #endif
4948 } 5734 }
4949 5735
4950 if (typ == SparseType::Full) 5736 if (typ == SparseType::Full)
4951 { 5737 {
4952 #ifdef HAVE_UMFPACK 5738 #ifdef HAVE_UMFPACK
5039 (*current_liboctave_error_handler) 5825 (*current_liboctave_error_handler)
5040 ("matrix dimension mismatch solution of linear equations"); 5826 ("matrix dimension mismatch solution of linear equations");
5041 else 5827 else
5042 { 5828 {
5043 // Print spparms("spumoni") info if requested 5829 // Print spparms("spumoni") info if requested
5044 int typ = mattype.type (); 5830 volatile int typ = mattype.type ();
5045 mattype.info (); 5831 mattype.info ();
5046 5832
5047 if (typ == SparseType::Hermitian) 5833 if (typ == SparseType::Hermitian)
5048 { 5834 {
5049 // XXX FIXME XXX Write the cholesky solver and only fall 5835 #ifdef HAVE_CHOLMOD
5050 // through if cholesky factorization fails 5836 cholmod_common Common;
5051 5837 cholmod_common *cm = &Common;
5838
5839 // Setup initial parameters
5840 CHOLMOD_NAME(start) (cm);
5841 cm->prefer_zomplex = FALSE;
5842
5843 double spu = Voctave_sparse_controls.get_key ("spumoni");
5844 if (spu == 0.)
5845 {
5846 cm->print = -1;
5847 cm->print_function = NULL;
5848 }
5849 else
5850 {
5851 cm->print = (int)spu + 2;
5852 cm->print_function =&SparseCholPrint;
5853 }
5854
5855 cm->error_handler = &SparseCholError;
5856 cm->complex_divide = CHOLMOD_NAME(divcomplex);
5857 cm->hypotenuse = CHOLMOD_NAME(hypot);
5858
5859 #ifdef HAVE_METIS
5860 // METIS 4.0.1 uses malloc and free, and will terminate MATLAB if
5861 // it runs out of memory. Use CHOLMOD's memory guard for METIS,
5862 // which mxMalloc's a huge block of memory (and then immediately
5863 // mxFree's it) before calling METIS
5864 cm->metis_memory = 2.0;
5865
5866 #if defined(METIS_VERSION)
5867 #if (METIS_VERSION >= METIS_VER(4,0,2))
5868 // METIS 4.0.2 uses function pointers for malloc and free
5869 METIS_malloc = cm->malloc_memory;
5870 METIS_free = cm->free_memory;
5871 // Turn off METIS memory guard. It is not needed, because mxMalloc
5872 // will safely terminate the mexFunction and free any workspace
5873 // without killing all of octave.
5874 cm->metis_memory = 0.0;
5875 #endif
5876 #endif
5877 #endif
5878
5879 cm->final_ll = TRUE;
5880
5881 cholmod_sparse Astore;
5882 cholmod_sparse *A = &Astore;
5883 double dummy;
5884 A->nrow = nr;
5885 A->ncol = nc;
5886
5887 A->p = cidx();
5888 A->i = ridx();
5889 A->nzmax = nonzero();
5890 A->packed = TRUE;
5891 A->sorted = TRUE;
5892 A->nz = NULL;
5893 #ifdef IDX_TYPE_LONG
5894 A->itype = CHOLMOD_LONG;
5895 #else
5896 A->itype = CHOLMOD_INT;
5897 #endif
5898 A->dtype = CHOLMOD_DOUBLE;
5899 A->stype = 1;
5900 A->xtype = CHOLMOD_COMPLEX;
5901
5902 if (nr < 1)
5903 A->x = &dummy;
5904 else
5905 A->x = data();
5906
5907 cholmod_sparse Bstore;
5908 cholmod_sparse *B = &Bstore;
5909 B->nrow = b.rows();
5910 B->ncol = b.cols();
5911 B->p = b.cidx();
5912 B->i = b.ridx();
5913 B->nzmax = b.nonzero();
5914 B->packed = TRUE;
5915 B->sorted = TRUE;
5916 B->nz = NULL;
5917 #ifdef IDX_TYPE_LONG
5918 B->itype = CHOLMOD_LONG;
5919 #else
5920 B->itype = CHOLMOD_INT;
5921 #endif
5922 B->dtype = CHOLMOD_DOUBLE;
5923 B->stype = 0;
5924 B->xtype = CHOLMOD_COMPLEX;
5925
5926 if (b.rows() < 1 || b.cols() < 1)
5927 B->x = &dummy;
5928 else
5929 B->x = b.data();
5930
5931 cholmod_factor *L;
5932 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5933 L = CHOLMOD_NAME(analyze) (A, cm);
5934 CHOLMOD_NAME(factorize) (A, L, cm);
5935 rcond = CHOLMOD_NAME(rcond)(L, cm);
5936 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5937
5938 if (rcond == 0.0)
5939 {
5940 // Either its indefinite or singular. Try UMFPACK
5941 mattype.mark_as_unsymmetric ();
5942 typ = SparseType::Full;
5943 }
5944 else
5945 {
5946 volatile double rcond_plus_one = rcond + 1.0;
5947
5948 if (rcond_plus_one == 1.0 || xisnan (rcond))
5949 {
5950 err = -2;
5951
5952 if (sing_handler)
5953 sing_handler (rcond);
5954 else
5955 (*current_liboctave_error_handler)
5956 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g",
5957 rcond);
5958
5959 #ifdef HAVE_LSSOLVE
5960 return retval;
5961 #endif
5962 }
5963
5964 cholmod_sparse *X;
5965 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5966 X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
5967 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5968
5969 retval = SparseComplexMatrix
5970 (static_cast<octave_idx_type>(X->nrow),
5971 static_cast<octave_idx_type>(X->ncol),
5972 static_cast<octave_idx_type>(X->nzmax));
5973 for (octave_idx_type j = 0;
5974 j <= static_cast<octave_idx_type>(X->ncol); j++)
5975 retval.xcidx(j) = static_cast<octave_idx_type *>(X->p)[j];
5976 for (octave_idx_type j = 0;
5977 j < static_cast<octave_idx_type>(X->nzmax); j++)
5978 {
5979 retval.xridx(j) = static_cast<octave_idx_type *>(X->i)[j];
5980 retval.xdata(j) = static_cast<Complex *>(X->x)[j];
5981 }
5982
5983 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5984 CHOLMOD_NAME(free_sparse) (&X, cm);
5985 CHOLMOD_NAME(free_factor) (&L, cm);
5986 CHOLMOD_NAME(finish) (cm);
5987 CHOLMOD_NAME(print_common) (" ", cm);
5988 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
5989 }
5990 #else
5052 (*current_liboctave_warning_handler) 5991 (*current_liboctave_warning_handler)
5053 ("SparseMatrix::solve XXX FIXME XXX Cholesky code not done"); 5992 ("CHOLMOD not installed");
5054 5993
5055 mattype.mark_as_unsymmetric (); 5994 mattype.mark_as_unsymmetric ();
5056 typ = SparseType::Full; 5995 typ = SparseType::Full;
5996 #endif
5057 } 5997 }
5058 5998
5059 if (typ == SparseType::Full) 5999 if (typ == SparseType::Full)
5060 { 6000 {
5061 #ifdef HAVE_UMFPACK 6001 #ifdef HAVE_UMFPACK