1 /* Program usage: mpiexec -n 1 rosenbrock2 [-help] [all TAO options] */ 2 3 /* Include "petsctao.h" so we can use TAO solvers. */ 4 #include <petsctao.h> 5 6 static char help[] = "This example demonstrates use of the TAO package to \n\ 7 solve an unconstrained minimization problem on a single processor. We \n\ 8 minimize the extended Rosenbrock function: \n\ 9 sum_{i=0}^{n/2-1} (alpha*(x_{2i+1}-x_{2i}^2)^2 + (1-x_{2i})^2) \n\ 10 or the chained Rosenbrock function:\n\ 11 sum_{i=0}^{n-1} alpha*(x_{i+1} - x_i^2)^2 + (1 - x_i)^2\n"; 12 13 /*T 14 Concepts: TAO^Solving an unconstrained minimization problem 15 Routines: TaoCreate(); 16 Routines: TaoSetType(); TaoSetObjectiveAndGradient(); 17 Routines: TaoSetHessian(); 18 Routines: TaoSetSolution(); 19 Routines: TaoSetFromOptions(); 20 Routines: TaoSolve(); 21 Routines: TaoDestroy(); 22 Processors: 1 23 T*/ 24 25 /* 26 User-defined application context - contains data needed by the 27 application-provided call-back routines that evaluate the function, 28 gradient, and hessian. 29 */ 30 typedef struct { 31 PetscInt n; /* dimension */ 32 PetscReal alpha; /* condition parameter */ 33 PetscBool chained; 34 } AppCtx; 35 36 /* -------------- User-defined routines ---------- */ 37 PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*); 38 PetscErrorCode FormHessian(Tao,Vec,Mat,Mat,void*); 39 40 int main(int argc,char **argv) 41 { 42 PetscReal zero=0.0; 43 Vec x; /* solution vector */ 44 Mat H; 45 Tao tao; /* Tao solver context */ 46 PetscBool flg, test_lmvm = PETSC_FALSE; 47 PetscMPIInt size; /* number of processes running */ 48 AppCtx user; /* user-defined application context */ 49 TaoConvergedReason reason; 50 PetscInt its, recycled_its=0, oneshot_its=0; 51 52 /* Initialize TAO and PETSc */ 53 PetscCall(PetscInitialize(&argc,&argv,(char*)0,help)); 54 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size)); 55 PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Incorrect number of processors"); 56 57 /* Initialize problem parameters */ 58 user.n = 2; user.alpha = 99.0; user.chained = PETSC_FALSE; 59 /* Check for command line arguments to override defaults */ 60 PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&user.n,&flg)); 61 PetscCall(PetscOptionsGetReal(NULL,NULL,"-alpha",&user.alpha,&flg)); 62 PetscCall(PetscOptionsGetBool(NULL,NULL,"-chained",&user.chained,&flg)); 63 PetscCall(PetscOptionsGetBool(NULL,NULL,"-test_lmvm",&test_lmvm,&flg)); 64 65 /* Allocate vectors for the solution and gradient */ 66 PetscCall(VecCreateSeq(PETSC_COMM_SELF,user.n,&x)); 67 PetscCall(MatCreateSeqBAIJ(PETSC_COMM_SELF,2,user.n,user.n,1,NULL,&H)); 68 69 /* The TAO code begins here */ 70 71 /* Create TAO solver with desired solution method */ 72 PetscCall(TaoCreate(PETSC_COMM_SELF,&tao)); 73 PetscCall(TaoSetType(tao,TAOLMVM)); 74 75 /* Set solution vec and an initial guess */ 76 PetscCall(VecSet(x, zero)); 77 PetscCall(TaoSetSolution(tao,x)); 78 79 /* Set routines for function, gradient, hessian evaluation */ 80 PetscCall(TaoSetObjectiveAndGradient(tao,NULL,FormFunctionGradient,&user)); 81 PetscCall(TaoSetHessian(tao,H,H,FormHessian,&user)); 82 83 /* Check for TAO command line options */ 84 PetscCall(TaoSetFromOptions(tao)); 85 86 /* Solve the problem */ 87 PetscCall(TaoSetTolerances(tao, 1.e-5, 0.0, 0.0)); 88 PetscCall(TaoSetMaximumIterations(tao, 5)); 89 PetscCall(TaoLMVMRecycle(tao, PETSC_TRUE)); 90 reason = TAO_CONTINUE_ITERATING; 91 while (reason != TAO_CONVERGED_GATOL) { 92 PetscCall(TaoSolve(tao)); 93 PetscCall(TaoGetConvergedReason(tao, &reason)); 94 PetscCall(TaoGetIterationNumber(tao, &its)); 95 recycled_its += its; 96 PetscCall(PetscPrintf(PETSC_COMM_SELF, "-----------------------\n")); 97 } 98 99 /* Disable recycling and solve again! */ 100 PetscCall(TaoSetMaximumIterations(tao, 100)); 101 PetscCall(TaoLMVMRecycle(tao, PETSC_FALSE)); 102 PetscCall(VecSet(x, zero)); 103 PetscCall(TaoSolve(tao)); 104 PetscCall(TaoGetConvergedReason(tao, &reason)); 105 PetscCheck(reason == TAO_CONVERGED_GATOL,PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "Solution failed to converge!"); 106 PetscCall(TaoGetIterationNumber(tao, &oneshot_its)); 107 PetscCall(PetscPrintf(PETSC_COMM_SELF, "-----------------------\n")); 108 PetscCall(PetscPrintf(PETSC_COMM_SELF, "recycled its: %D | oneshot its: %D\n", recycled_its, oneshot_its)); 109 PetscCheck(recycled_its == oneshot_its,PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "LMVM recycling does not work!"); 110 111 PetscCall(TaoDestroy(&tao)); 112 PetscCall(VecDestroy(&x)); 113 PetscCall(MatDestroy(&H)); 114 115 PetscCall(PetscFinalize()); 116 return 0; 117 } 118 119 /* -------------------------------------------------------------------- */ 120 /* 121 FormFunctionGradient - Evaluates the function, f(X), and gradient, G(X). 122 123 Input Parameters: 124 . tao - the Tao context 125 . X - input vector 126 . ptr - optional user-defined context, as set by TaoSetFunctionGradient() 127 128 Output Parameters: 129 . G - vector containing the newly evaluated gradient 130 . f - function value 131 132 Note: 133 Some optimization methods ask for the function and the gradient evaluation 134 at the same time. Evaluating both at once may be more efficient that 135 evaluating each separately. 136 */ 137 PetscErrorCode FormFunctionGradient(Tao tao,Vec X,PetscReal *f, Vec G,void *ptr) 138 { 139 AppCtx *user = (AppCtx *) ptr; 140 PetscInt i,nn=user->n/2; 141 PetscReal ff=0,t1,t2,alpha=user->alpha; 142 PetscScalar *g; 143 const PetscScalar *x; 144 145 PetscFunctionBeginUser; 146 /* Get pointers to vector data */ 147 PetscCall(VecGetArrayRead(X,&x)); 148 PetscCall(VecGetArray(G,&g)); 149 150 /* Compute G(X) */ 151 if (user->chained) { 152 g[0] = 0; 153 for (i=0; i<user->n-1; i++) { 154 t1 = x[i+1] - x[i]*x[i]; 155 ff += PetscSqr(1 - x[i]) + alpha*t1*t1; 156 g[i] += -2*(1 - x[i]) + 2*alpha*t1*(-2*x[i]); 157 g[i+1] = 2*alpha*t1; 158 } 159 } else { 160 for (i=0; i<nn; i++) { 161 t1 = x[2*i+1]-x[2*i]*x[2*i]; t2= 1-x[2*i]; 162 ff += alpha*t1*t1 + t2*t2; 163 g[2*i] = -4*alpha*t1*x[2*i]-2.0*t2; 164 g[2*i+1] = 2*alpha*t1; 165 } 166 } 167 168 /* Restore vectors */ 169 PetscCall(VecRestoreArrayRead(X,&x)); 170 PetscCall(VecRestoreArray(G,&g)); 171 *f = ff; 172 173 PetscCall(PetscLogFlops(15.0*nn)); 174 PetscFunctionReturn(0); 175 } 176 177 /* ------------------------------------------------------------------- */ 178 /* 179 FormHessian - Evaluates Hessian matrix. 180 181 Input Parameters: 182 . tao - the Tao context 183 . x - input vector 184 . ptr - optional user-defined context, as set by TaoSetHessian() 185 186 Output Parameters: 187 . H - Hessian matrix 188 189 Note: Providing the Hessian may not be necessary. Only some solvers 190 require this matrix. 191 */ 192 PetscErrorCode FormHessian(Tao tao,Vec X,Mat H, Mat Hpre, void *ptr) 193 { 194 AppCtx *user = (AppCtx*)ptr; 195 PetscInt i, ind[2]; 196 PetscReal alpha=user->alpha; 197 PetscReal v[2][2]; 198 const PetscScalar *x; 199 PetscBool assembled; 200 201 PetscFunctionBeginUser; 202 /* Zero existing matrix entries */ 203 PetscCall(MatAssembled(H,&assembled)); 204 if (assembled) PetscCall(MatZeroEntries(H)); 205 206 /* Get a pointer to vector data */ 207 PetscCall(VecGetArrayRead(X,&x)); 208 209 /* Compute H(X) entries */ 210 if (user->chained) { 211 PetscCall(MatZeroEntries(H)); 212 for (i=0; i<user->n-1; i++) { 213 PetscScalar t1 = x[i+1] - x[i]*x[i]; 214 v[0][0] = 2 + 2*alpha*(t1*(-2) - 2*x[i]); 215 v[0][1] = 2*alpha*(-2*x[i]); 216 v[1][0] = 2*alpha*(-2*x[i]); 217 v[1][1] = 2*alpha*t1; 218 ind[0] = i; ind[1] = i+1; 219 PetscCall(MatSetValues(H,2,ind,2,ind,v[0],ADD_VALUES)); 220 } 221 } else { 222 for (i=0; i<user->n/2; i++) { 223 v[1][1] = 2*alpha; 224 v[0][0] = -4*alpha*(x[2*i+1]-3*x[2*i]*x[2*i]) + 2; 225 v[1][0] = v[0][1] = -4.0*alpha*x[2*i]; 226 ind[0]=2*i; ind[1]=2*i+1; 227 PetscCall(MatSetValues(H,2,ind,2,ind,v[0],INSERT_VALUES)); 228 } 229 } 230 PetscCall(VecRestoreArrayRead(X,&x)); 231 232 /* Assemble matrix */ 233 PetscCall(MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY)); 234 PetscCall(MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY)); 235 PetscCall(PetscLogFlops(9.0*user->n/2.0)); 236 PetscFunctionReturn(0); 237 } 238 239 /*TEST 240 241 build: 242 requires: !complex 243 244 test: 245 args: -tao_type lmvm -tao_monitor 246 requires: !single 247 248 TEST*/ 249