00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <iostream>
00026
00027 #include <QTime>
00028
00029 #include <QVApplication>
00030 #include <QVPropertyContainer>
00031 #include <QVSparseBlockMatrix>
00032 #include <qvmatrixalgebra.h>
00033
00034 int main(int argc, char *argv[])
00035 {
00036
00037 QVApplication app(argc,argv,"Performance test for solving of sparse systems of equation methods in QVision",false);
00038
00039
00040 QVPropertyContainer arg_container(argv[0]);
00041 arg_container.addProperty<int>("Blocks",QVPropertyContainer::inputFlag,20,
00042 "# of row blocks (size for the square sparse block test matrix)",1,1000);
00043 arg_container.addProperty<int>("Rows",QVPropertyContainer::inputFlag,10,
00044 "# of rows per block (size for each square block of test matrix)",1,1000);
00045 arg_container.addProperty<int>("n_tests",QVPropertyContainer::inputFlag,1,
00046 "Number of tests to average execution time",1,100);
00047 arg_container.addProperty<QString>("method",QVPropertyContainer::inputFlag,"QVMKL_DSS",
00048 "........Sparse solving method to use (available methods follow):\n"
00049 " "
00050 "QVMKL_DSS | QVMKL_ISS");
00051 arg_container.addProperty<bool>("verbose",QVPropertyContainer::inputFlag,false,
00052 "If true, print involved matrices and vectors");
00053 arg_container.addProperty<bool>("symmetric",QVPropertyContainer::inputFlag,true,
00054 "If true, coefficient matrix will be symmetric");
00055 arg_container.addProperty<bool>("positive",QVPropertyContainer::inputFlag,true,
00056 "If true, coefficient matrix will be positive definite");
00057 arg_container.addProperty<double>("prob",QVPropertyContainer::inputFlag,0.5,
00058 "Probability of a block of being nonzero in the generated matrix",0.0,1.0);
00059 arg_container.addProperty<bool>("iters_or_resid",QVPropertyContainer::inputFlag,false,
00060 "(only ISS method) if true, use iters, otherwise resid");
00061 arg_container.addProperty<int>("iters",QVPropertyContainer::inputFlag,20,
00062 "(only ISS method) Number of iterations to be executed by method",1,500);
00063 arg_container.addProperty<double>("resid",QVPropertyContainer::inputFlag,1.0E-10,
00064 "(only ISS method) iterate until square of residual below this");
00065 arg_container.addProperty<bool>("progressive",QVPropertyContainer::inputFlag,false,
00066 ".....(only ISS method) If true, consecutively execute method \n"
00067 " "
00068 "for 1, 2, 3, etc. iterations (in order to show rate of convergence, \n"
00069 " "
00070 "combine with --show_residuals to print successive values)");
00071 arg_container.addProperty<bool>("grad_desc",QVPropertyContainer::inputFlag,false,
00072 "......(only ISS method) If true, repeatedly execute method for\n"
00073 " "
00074 "only one iteration, starting in each step from the current solution\n"
00075 " "
00076 "(this ammounts to a simple gradient descent method); combine with\n"
00077 " "
00078 "show_residuals to print successive values in order to show (slower)\n"
00079 " "
00080 "rate of convergence. Overrides progressive option");
00081 arg_container.addProperty<bool>("show_residuals",QVPropertyContainer::inputFlag,false,
00082 "If true, print test residuals");
00083
00084
00085 int ret_value = app.processArguments();
00086 if(ret_value != 1) exit(ret_value);
00087
00088
00089 const int Blocks = arg_container.getPropertyValue<int>("Blocks");
00090 const int Rows = arg_container.getPropertyValue<int>("Rows");
00091 const int n_tests = arg_container.getPropertyValue<int>("n_tests");
00092 const QString method = arg_container.getPropertyValue<QString>("method");
00093 const bool verbose = arg_container.getPropertyValue<bool>("verbose");
00094 const bool symmetric = arg_container.getPropertyValue<bool>("symmetric");
00095 const bool positive = arg_container.getPropertyValue<bool>("positive");
00096 const double prob = arg_container.getPropertyValue<double>("prob");
00097 const bool iters_or_resid = arg_container.getPropertyValue<bool>("iters_or_resid");
00098 const int iters = arg_container.getPropertyValue<int>("iters");
00099 const double resid = arg_container.getPropertyValue<double>("resid");
00100 const bool progressive = arg_container.getPropertyValue<bool>("progressive");
00101 const bool grad_desc = arg_container.getPropertyValue<bool>("grad_desc");
00102 const bool show_residuals = arg_container.getPropertyValue<bool>("show_residuals");
00103
00104 TQVSparseSolve_Method sparse_method;
00105 if(method == "QVMKL_DSS")
00106 sparse_method = QVMKL_DSS;
00107 else if(method == "QVMKL_ISS")
00108 sparse_method = QVMKL_ISS;
00109 else {
00110 std::cout << "Incorrect sparse method. Use --help to see available methods.\n";
00111 exit(-1);
00112 }
00113 std::cout << "Using values: Blocks=" << Blocks << " Rows=" << Rows << " prob=" << prob;
00114 if(symmetric) {
00115 std::cout << " symmetric";
00116 if(positive)
00117 std::cout << " positive definite";
00118 else
00119 std::cout << " undefinite";
00120 } else {
00121 std::cout << " non-symmetric";
00122 }
00123 std::cout << " n_tests=" << n_tests << " Sparse method=" << qPrintable(method);
00124 if(sparse_method == QVMKL_ISS) {
00125 if(iters_or_resid)
00126 std::cout << " iters=" << iters;
00127 else
00128 std::cout << " resid=" << resid;
00129 if(grad_desc)
00130 std::cout << " grad_desc" ;
00131 else if(progressive)
00132 std::cout << " progressive" ;
00133 }
00134 std::cout << "\n";
00135
00136 double total_ms = 0.0;
00137
00138 for(int i=0;i<n_tests;i++) {
00139
00140 QVSparseBlockMatrix M = QVSparseBlockMatrix::randomSquare(Blocks,Rows,prob,symmetric,positive);
00141
00142 QVMatrix M_dense = M;
00143
00144 QVVector x, b, x_sol;
00145
00146
00147 x_sol = QVVector::random(Blocks*Rows);
00148 b = M_dense * x_sol;
00149
00150 QTime t;
00151
00152 t.start();
00153
00154 double returned_squared_residual = resid;
00155 QList<double> residual_list;
00156 int final_iters;
00157
00158 if(sparse_method == QVMKL_ISS) {
00159 if(grad_desc or progressive) {
00160
00161 int j;
00162 for(j=0;(iters_or_resid?(j<iters):(returned_squared_residual>=resid and (j<b.size() or grad_desc)));j++) {
00163 if(grad_desc) {
00164
00165 returned_squared_residual =
00166 SparseSolve(M, x, b, symmetric, positive, QVMKL_ISS, (j==0)?false:true, true, 1);
00167 } else if(progressive) {
00168
00169 returned_squared_residual =
00170 SparseSolve(M, x, b, symmetric, positive, QVMKL_ISS, false, true, j+1);
00171 }
00172 residual_list << sqrt(returned_squared_residual);
00173 }
00174 final_iters = j;
00175 } else {
00176
00177 SparseSolve(M, x, b, symmetric, positive, QVMKL_ISS, false, iters_or_resid, iters, resid, final_iters);
00178 }
00179 } else {
00180
00181 SparseSolve(M, x, b, symmetric, positive, QVMKL_DSS);
00182 }
00183
00184 total_ms += t.elapsed();
00185
00186 if(verbose) {
00187 std::cout << "*****************************************\n";
00188
00189 std::cout << "M_dense:" << M_dense << "\n";
00190 if(symmetric) {
00191 QVVector lambda;
00192 EigenValues(M_dense, lambda, LAPACK_DSYEV_ONLY);
00193 std::cout << "Eigenvalues of M_dense: " << lambda << "\n";
00194 }
00195 std::cout << "b:" << b << "\n";
00196 std::cout << "x:" << x << "\n";
00197 std::cout << "x_sol:" << x_sol << "\n";
00198 std::cout << "*****************************************\n";
00199 }
00200
00201 if(show_residuals) {
00202 std::cout << "Test solve residual = " << SolveResidual(M_dense, x_sol, b) << "\n";
00203 double residual = SolveResidual(M_dense, x, b);
00204 std::cout << "Sparse solve residual = " << residual;
00205 if (sparse_method == QVMKL_ISS and not iters_or_resid)
00206 std::cout << " (square residual = " << residual*residual << ")";
00207 if (sparse_method == QVMKL_ISS)
00208 std::cout << " (final_iters = " << final_iters << ")";
00209 std::cout << "\n";
00210 if (sparse_method == QVMKL_ISS and (progressive or grad_desc)) {
00211 std::cout << "Residual list (" << residual_list.size() << " elems.):";
00212 for (int k=0; k<residual_list.size(); k++)
00213 std::cout << " " << residual_list[k] ;
00214 std::cout << "\n";
00215 }
00216 std::cout << "x - x_sol residual = " << (x-x_sol).norm2() << "\n";
00217 std::cout << "x norm = " << x.norm2() << "\n";
00218 std::cout << "x_sol norm = " << x_sol.norm2() << "\n";
00219 }
00220 }
00221
00222 total_ms /= n_tests;
00223
00224 if(n_tests==1)
00225 std::cout << "Total time: " << total_ms << " ms.\n";
00226 else
00227 std::cout << "Average total time: " << total_ms << " ms.\n";
00228
00229 std::cout << "Finished.\n";
00230 }