/*@C TaoMatGetSubMat - Gets a submatrix using the IS Input Parameters: + M - the full matrix (n x n) . is - the index set for the submatrix (both row and column index sets need to be the same) . v1 - work vector of dimension n, needed for TAO_SUBSET_MASK option - subset_type - the method TAO is using for subsetting (TAO_SUBSET_SUBVEC, TAO_SUBSET_MASK, TAO_SUBSET_MATRIXFREE) Output Parameters: . Msub - the submatrix @*/ PetscErrorCode TaoMatGetSubMat(Mat M, IS is, Vec v1, TaoSubsetType subset_type, Mat *Msub) { PetscErrorCode ierr; IS iscomp; PetscBool flg = PETSC_FALSE; PetscFunctionBegin; PetscValidHeaderSpecific(M,MAT_CLASSID,1); PetscValidHeaderSpecific(is,IS_CLASSID,2); ierr = MatDestroy(Msub);CHKERRQ(ierr); switch (subset_type) { case TAO_SUBSET_SUBVEC: ierr = MatGetSubMatrix(M, is, is, MAT_INITIAL_MATRIX, Msub);CHKERRQ(ierr); break; case TAO_SUBSET_MASK: /* Get Reduced Hessian Msub[i,j] = M[i,j] if i,j in Free_Local or i==j Msub[i,j] = 0 if i!=j and i or j not in Free_Local */ ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)M),NULL,NULL,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-different_submatrix","use separate hessian matrix when computing submatrices","TaoSubsetType",flg,&flg,NULL);CHKERRQ(ierr); ierr = PetscOptionsEnd();CHKERRQ(ierr); if (flg) { ierr = MatDuplicate(M, MAT_COPY_VALUES, Msub);CHKERRQ(ierr); } else { /* Act on hessian directly (default) */ ierr = PetscObjectReference((PetscObject)M);CHKERRQ(ierr); *Msub = M; } /* Save the diagonal to temporary vector */ ierr = MatGetDiagonal(*Msub,v1);CHKERRQ(ierr); /* Zero out rows and columns */ ierr = ISComplementVec(is,v1,&iscomp);CHKERRQ(ierr); /* Use v1 instead of 0 here because of PETSc bug */ ierr = MatZeroRowsColumnsIS(*Msub,iscomp,1.0,v1,v1);CHKERRQ(ierr); ierr = ISDestroy(&iscomp);CHKERRQ(ierr); break; case TAO_SUBSET_MATRIXFREE: ierr = ISComplementVec(is,v1,&iscomp);CHKERRQ(ierr); ierr = MatCreateSubMatrixFree(M,iscomp,iscomp,Msub);CHKERRQ(ierr); ierr = ISDestroy(&iscomp);CHKERRQ(ierr); break; } PetscFunctionReturn(0); }
PETSC_EXTERN void PETSC_STDCALL iscomplementvec_(IS S,Vec V,IS *T, int *__ierr ){ *__ierr = ISComplementVec( (IS)PetscToPointer((S) ), (Vec)PetscToPointer((V) ),T); }
static PetscErrorCode TaoSolve_ASILS(Tao tao) { TAO_SSLS *asls = (TAO_SSLS *)tao->data; PetscReal psi,ndpsi, normd, innerd, t=0; PetscInt iter=0, nf; PetscErrorCode ierr; TaoConvergedReason reason; TaoLineSearchConvergedReason ls_reason; PetscFunctionBegin; /* Assume that Setup has been called! Set the structure for the Jacobian and create a linear solver. */ ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr); ierr = TaoLineSearchSetObjectiveAndGradientRoutine(tao->linesearch,Tao_ASLS_FunctionGradient,tao);CHKERRQ(ierr); ierr = TaoLineSearchSetObjectiveRoutine(tao->linesearch,Tao_SSLS_Function,tao);CHKERRQ(ierr); /* Calculate the function value and fischer function value at the current iterate */ ierr = TaoLineSearchComputeObjectiveAndGradient(tao->linesearch,tao->solution,&psi,asls->dpsi);CHKERRQ(ierr); ierr = VecNorm(asls->dpsi,NORM_2,&ndpsi);CHKERRQ(ierr); while (1) { /* Check the termination criteria */ ierr = PetscInfo3(tao,"iter %D, merit: %g, ||dpsi||: %g\n",iter, (double)asls->merit, (double)ndpsi);CHKERRQ(ierr); ierr = TaoMonitor(tao, iter++, asls->merit, ndpsi, 0.0, t, &reason);CHKERRQ(ierr); if (TAO_CONTINUE_ITERATING != reason) break; /* We are going to solve a linear system of equations. We need to set the tolerances for the solve so that we maintain an asymptotic rate of convergence that is superlinear. Note: these tolerances are for the reduced system. We really need to make sure that the full system satisfies the full-space conditions. This rule gives superlinear asymptotic convergence asls->atol = min(0.5, asls->merit*sqrt(asls->merit)); asls->rtol = 0.0; This rule gives quadratic asymptotic convergence asls->atol = min(0.5, asls->merit*asls->merit); asls->rtol = 0.0; Calculate a free and fixed set of variables. The fixed set of variables are those for the d_b is approximately equal to zero. The definition of approximately changes as we approach the solution to the problem. No one rule is guaranteed to work in all cases. The following definition is based on the norm of the Jacobian matrix. If the norm is large, the tolerance becomes smaller. */ ierr = MatNorm(tao->jacobian,NORM_1,&asls->identifier);CHKERRQ(ierr); asls->identifier = PetscMin(asls->merit, 1e-2) / (1 + asls->identifier); ierr = VecSet(asls->t1,-asls->identifier);CHKERRQ(ierr); ierr = VecSet(asls->t2, asls->identifier);CHKERRQ(ierr); ierr = ISDestroy(&asls->fixed);CHKERRQ(ierr); ierr = ISDestroy(&asls->free);CHKERRQ(ierr); ierr = VecWhichBetweenOrEqual(asls->t1, asls->db, asls->t2, &asls->fixed);CHKERRQ(ierr); ierr = ISComplementVec(asls->fixed,asls->t1, &asls->free);CHKERRQ(ierr); ierr = ISGetSize(asls->fixed,&nf);CHKERRQ(ierr); ierr = PetscInfo1(tao,"Number of fixed variables: %D\n", nf);CHKERRQ(ierr); /* We now have our partition. Now calculate the direction in the fixed variable space. */ ierr = TaoVecGetSubVec(asls->ff, asls->fixed, tao->subset_type, 0.0, &asls->r1); ierr = TaoVecGetSubVec(asls->da, asls->fixed, tao->subset_type, 1.0, &asls->r2); ierr = VecPointwiseDivide(asls->r1,asls->r1,asls->r2);CHKERRQ(ierr); ierr = VecSet(tao->stepdirection,0.0);CHKERRQ(ierr); ierr = VecISAXPY(tao->stepdirection, asls->fixed,1.0,asls->r1);CHKERRQ(ierr); /* Our direction in the Fixed Variable Set is fixed. Calculate the information needed for the step in the Free Variable Set. To do this, we need to know the diagonal perturbation and the right hand side. */ ierr = TaoVecGetSubVec(asls->da, asls->free, tao->subset_type, 0.0, &asls->r1);CHKERRQ(ierr); ierr = TaoVecGetSubVec(asls->ff, asls->free, tao->subset_type, 0.0, &asls->r2);CHKERRQ(ierr); ierr = TaoVecGetSubVec(asls->db, asls->free, tao->subset_type, 1.0, &asls->r3);CHKERRQ(ierr); ierr = VecPointwiseDivide(asls->r1,asls->r1, asls->r3);CHKERRQ(ierr); ierr = VecPointwiseDivide(asls->r2,asls->r2, asls->r3);CHKERRQ(ierr); /* r1 is the diagonal perturbation r2 is the right hand side r3 is no longer needed Now need to modify r2 for our direction choice in the fixed variable set: calculate t1 = J*d, take the reduced vector of t1 and modify r2. */ ierr = MatMult(tao->jacobian, tao->stepdirection, asls->t1);CHKERRQ(ierr); ierr = TaoVecGetSubVec(asls->t1,asls->free,tao->subset_type,0.0,&asls->r3);CHKERRQ(ierr); ierr = VecAXPY(asls->r2, -1.0, asls->r3);CHKERRQ(ierr); /* Calculate the reduced problem matrix and the direction */ if (!asls->w && (tao->subset_type == TAO_SUBSET_MASK || tao->subset_type == TAO_SUBSET_MATRIXFREE)) { ierr = VecDuplicate(tao->solution, &asls->w);CHKERRQ(ierr); } ierr = TaoMatGetSubMat(tao->jacobian, asls->free, asls->w, tao->subset_type,&asls->J_sub);CHKERRQ(ierr); if (tao->jacobian != tao->jacobian_pre) { ierr = TaoMatGetSubMat(tao->jacobian_pre, asls->free, asls->w, tao->subset_type, &asls->Jpre_sub);CHKERRQ(ierr); } else { ierr = MatDestroy(&asls->Jpre_sub);CHKERRQ(ierr); asls->Jpre_sub = asls->J_sub; ierr = PetscObjectReference((PetscObject)(asls->Jpre_sub));CHKERRQ(ierr); } ierr = MatDiagonalSet(asls->J_sub, asls->r1,ADD_VALUES);CHKERRQ(ierr); ierr = TaoVecGetSubVec(tao->stepdirection, asls->free, tao->subset_type, 0.0, &asls->dxfree);CHKERRQ(ierr); ierr = VecSet(asls->dxfree, 0.0);CHKERRQ(ierr); /* Calculate the reduced direction. (Really negative of Newton direction. Therefore, rest of the code uses -d.) */ ierr = KSPReset(tao->ksp); ierr = KSPSetOperators(tao->ksp, asls->J_sub, asls->Jpre_sub);CHKERRQ(ierr); ierr = KSPSolve(tao->ksp, asls->r2, asls->dxfree);CHKERRQ(ierr); /* Add the direction in the free variables back into the real direction. */ ierr = VecISAXPY(tao->stepdirection, asls->free, 1.0,asls->dxfree);CHKERRQ(ierr); /* Check the real direction for descent and if not, use the negative gradient direction. */ ierr = VecNorm(tao->stepdirection, NORM_2, &normd);CHKERRQ(ierr); ierr = VecDot(tao->stepdirection, asls->dpsi, &innerd);CHKERRQ(ierr); if (innerd <= asls->delta*pow(normd, asls->rho)) { ierr = PetscInfo1(tao,"Gradient direction: %5.4e.\n", (double)innerd);CHKERRQ(ierr); ierr = PetscInfo1(tao, "Iteration %D: newton direction not descent\n", iter);CHKERRQ(ierr); ierr = VecCopy(asls->dpsi, tao->stepdirection);CHKERRQ(ierr); ierr = VecDot(asls->dpsi, tao->stepdirection, &innerd);CHKERRQ(ierr); } ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); innerd = -innerd; /* We now have a correct descent direction. Apply a linesearch to find the new iterate. */ ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr); ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &psi,asls->dpsi, tao->stepdirection, &t, &ls_reason);CHKERRQ(ierr); ierr = VecNorm(asls->dpsi, NORM_2, &ndpsi);CHKERRQ(ierr); } PetscFunctionReturn(0); }