xref: /petsc/src/tao/bound/utils/isutil.c (revision 2f75a4aaab0e3f692f7125f85b5f5852e7ceb6cb)
1 #include <petsctao.h> /*I "petsctao.h" I*/
2 #include <petsc/private/taoimpl.h>
3 #include <../src/tao/matrix/submatfree.h>
4 
5 /*@C
6   TaoVecGetSubVec - Gets a subvector using the IS
7 
8   Input Parameters:
9 + vfull - the full matrix
10 . is - the index set for the subvector
11 . reduced_type - the method TAO is using for subsetting (TAO_SUBSET_SUBVEC, TAO_SUBSET_MASK,  TAO_SUBSET_MATRIXFREE)
12 - maskvalue - the value to set the unused vector elements to (for TAO_SUBSET_MASK or TAO_SUBSET_MATRIXFREE)
13 
14   Output Parameters:
15 . vreduced - the subvector
16 
17   Notes:
18   maskvalue should usually be 0.0, unless a pointwise divide will be used.
19 
20 @*/
21 PetscErrorCode TaoVecGetSubVec(Vec vfull, IS is, TaoSubsetType reduced_type, PetscReal maskvalue, Vec *vreduced)
22 {
23   PetscErrorCode ierr;
24   PetscInt       nfull,nreduced,nreduced_local,rlow,rhigh,flow,fhigh;
25   PetscInt       i,nlocal;
26   PetscReal      *fv,*rv;
27   const PetscInt *s;
28   IS             ident;
29   VecType        vtype;
30   VecScatter     scatter;
31   MPI_Comm       comm;
32 
33   PetscFunctionBegin;
34   PetscValidHeaderSpecific(vfull,VEC_CLASSID,1);
35   PetscValidHeaderSpecific(is,IS_CLASSID,2);
36 
37   ierr = VecGetSize(vfull, &nfull);CHKERRQ(ierr);
38   ierr = ISGetSize(is, &nreduced);CHKERRQ(ierr);
39 
40   if (nreduced == nfull) {
41     ierr = VecDestroy(vreduced);CHKERRQ(ierr);
42     ierr = VecDuplicate(vfull,vreduced);CHKERRQ(ierr);
43     ierr = VecCopy(vfull,*vreduced);CHKERRQ(ierr);
44   } else {
45     switch (reduced_type) {
46     case TAO_SUBSET_SUBVEC:
47       ierr = VecGetType(vfull,&vtype);CHKERRQ(ierr);
48       ierr = VecGetOwnershipRange(vfull,&flow,&fhigh);CHKERRQ(ierr);
49       ierr = ISGetLocalSize(is,&nreduced_local);CHKERRQ(ierr);
50       ierr = PetscObjectGetComm((PetscObject)vfull,&comm);CHKERRQ(ierr);
51       if (*vreduced) {
52         ierr = VecDestroy(vreduced);CHKERRQ(ierr);
53       }
54       ierr = VecCreate(comm,vreduced);CHKERRQ(ierr);
55       ierr = VecSetType(*vreduced,vtype);CHKERRQ(ierr);
56 
57       ierr = VecSetSizes(*vreduced,nreduced_local,nreduced);CHKERRQ(ierr);
58       ierr = VecGetOwnershipRange(*vreduced,&rlow,&rhigh);CHKERRQ(ierr);
59       ierr = ISCreateStride(comm,nreduced_local,rlow,1,&ident);CHKERRQ(ierr);
60       ierr = VecScatterCreate(vfull,is,*vreduced,ident,&scatter);CHKERRQ(ierr);
61       ierr = VecScatterBegin(scatter,vfull,*vreduced,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
62       ierr = VecScatterEnd(scatter,vfull,*vreduced,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
63       ierr = VecScatterDestroy(&scatter);CHKERRQ(ierr);
64       ierr = ISDestroy(&ident);CHKERRQ(ierr);
65       break;
66 
67     case TAO_SUBSET_MASK:
68     case TAO_SUBSET_MATRIXFREE:
69       /* vr[i] = vf[i]   if i in is
70        vr[i] = 0       otherwise */
71       if (!*vreduced) {
72         ierr = VecDuplicate(vfull,vreduced);CHKERRQ(ierr);
73       }
74 
75       ierr = VecSet(*vreduced,maskvalue);CHKERRQ(ierr);
76       ierr = ISGetLocalSize(is,&nlocal);CHKERRQ(ierr);
77       ierr = VecGetOwnershipRange(vfull,&flow,&fhigh);CHKERRQ(ierr);
78       ierr = VecGetArray(vfull,&fv);CHKERRQ(ierr);
79       ierr = VecGetArray(*vreduced,&rv);CHKERRQ(ierr);
80       ierr = ISGetIndices(is,&s);CHKERRQ(ierr);
81       if (nlocal > (fhigh-flow)) SETERRQ2(PETSC_COMM_WORLD,1,"IS local size %d > Vec local size %d",nlocal,fhigh-flow);
82       for (i=0;i<nlocal;i++) {
83         rv[s[i]-flow] = fv[s[i]-flow];
84       }
85       ierr = ISRestoreIndices(is,&s);CHKERRQ(ierr);
86       ierr = VecRestoreArray(vfull,&fv);CHKERRQ(ierr);
87       ierr = VecRestoreArray(*vreduced,&rv);CHKERRQ(ierr);
88       break;
89     }
90   }
91   PetscFunctionReturn(0);
92 }
93 
94 /*@C
95   TaoMatGetSubMat - Gets a submatrix using the IS
96 
97   Input Parameters:
98 + M - the full matrix (n x n)
99 . is - the index set for the submatrix (both row and column index sets need to be the same)
100 . v1 - work vector of dimension n, needed for TAO_SUBSET_MASK option
101 - subset_type - the method TAO is using for subsetting (TAO_SUBSET_SUBVEC, TAO_SUBSET_MASK,
102   TAO_SUBSET_MATRIXFREE)
103 
104   Output Parameters:
105 . Msub - the submatrix
106 @*/
107 PetscErrorCode TaoMatGetSubMat(Mat M, IS is, Vec v1, TaoSubsetType subset_type, Mat *Msub)
108 {
109   PetscErrorCode ierr;
110   IS             iscomp;
111   PetscBool      flg = PETSC_FALSE;
112 
113   PetscFunctionBegin;
114   PetscValidHeaderSpecific(M,MAT_CLASSID,1);
115   PetscValidHeaderSpecific(is,IS_CLASSID,2);
116   ierr = MatDestroy(Msub);CHKERRQ(ierr);
117   switch (subset_type) {
118   case TAO_SUBSET_SUBVEC:
119     ierr = MatCreateSubMatrix(M, is, is, MAT_INITIAL_MATRIX, Msub);CHKERRQ(ierr);
120     break;
121 
122   case TAO_SUBSET_MASK:
123     /* Get Reduced Hessian
124      Msub[i,j] = M[i,j] if i,j in Free_Local or i==j
125      Msub[i,j] = 0      if i!=j and i or j not in Free_Local
126      */
127     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)M),NULL,NULL,NULL);CHKERRQ(ierr);
128     ierr = PetscOptionsBool("-different_submatrix","use separate hessian matrix when computing submatrices","TaoSubsetType",flg,&flg,NULL);CHKERRQ(ierr);
129     ierr = PetscOptionsEnd();CHKERRQ(ierr);
130     if (flg) {
131       ierr = MatDuplicate(M, MAT_COPY_VALUES, Msub);CHKERRQ(ierr);
132     } else {
133       /* Act on hessian directly (default) */
134       ierr = PetscObjectReference((PetscObject)M);CHKERRQ(ierr);
135       *Msub = M;
136     }
137     /* Save the diagonal to temporary vector */
138     ierr = MatGetDiagonal(*Msub,v1);CHKERRQ(ierr);
139 
140     /* Zero out rows and columns */
141     ierr = ISComplementVec(is,v1,&iscomp);CHKERRQ(ierr);
142 
143     /* Use v1 instead of 0 here because of PETSc bug */
144     ierr = MatZeroRowsColumnsIS(*Msub,iscomp,1.0,v1,v1);CHKERRQ(ierr);
145 
146     ierr = ISDestroy(&iscomp);CHKERRQ(ierr);
147     break;
148   case TAO_SUBSET_MATRIXFREE:
149     ierr = ISComplementVec(is,v1,&iscomp);CHKERRQ(ierr);
150     ierr = MatCreateSubMatrixFree(M,iscomp,iscomp,Msub);CHKERRQ(ierr);
151     ierr = ISDestroy(&iscomp);CHKERRQ(ierr);
152     break;
153   }
154   PetscFunctionReturn(0);
155 }
156 
157 /*@C
158   TaoEstimateActiveBounds - Generates index sets for variables at the lower and upper
159   bounds, as well as fixed variables where lower and upper bounds equal each other.
160 
161   Input Parameters:
162 + X - solution vector
163 . XL - lower bound vector
164 . XU - upper bound vector
165 . G - unprojected gradient
166 - S - step direction with which the active bounds will be estimated
167 
168   Output Parameters:
169 . bound_tol - tolerance for for the bound estimation
170 . active_lower - index set for active variables at the lower bound
171 . active_upper - index set for active variables at the upper bound
172 . active_fixed - index set for fixed variables
173 . active - index set for all active variables
174 . inactive - complementary index set for inactive variables
175 @*/
176 PetscErrorCode TaoEstimateActiveBounds(Vec X, Vec XL, Vec XU, Vec G, Vec S, PetscReal *bound_tol,
177                                        IS *active_lower, IS *active_upper, IS *active_fixed, IS *active, IS *inactive)
178 {
179   PetscErrorCode               ierr;
180 
181   Vec                          W;
182   PetscReal                    wnorm;
183   PetscInt                     i, n_isl=0, n_isu=0, n_isf=0;
184   PetscInt                     n, low, high;
185   PetscInt                     *isl=NULL, *isu=NULL, *isf=NULL;
186   const PetscScalar            *xl, *xu, *x, *g;
187 
188   PetscFunctionBegin;
189   /* Update the tolerance for bound detection (this is based on Bertsekas' method) */
190   ierr = VecDuplicate(S, &W);CHKERRQ(ierr);
191   ierr = VecCopy(S, W);CHKERRQ(ierr);
192   ierr = VecAXPBY(W, 1.0, 0.001, X);CHKERRQ(ierr);
193   ierr = VecMedian(XL, W, XU, W);CHKERRQ(ierr);
194   ierr = VecAXPBY(W, 1.0, -1.0, X);CHKERRQ(ierr);
195   ierr = VecNorm(W, NORM_2, &wnorm);CHKERRQ(ierr);
196   *bound_tol = PetscMin(*bound_tol, wnorm);
197 
198   ierr = VecGetOwnershipRange(X, &low, &high);CHKERRQ(ierr);
199   ierr = VecGetLocalSize(X, &n);CHKERRQ(ierr);
200   if (n>0){
201     ierr = VecGetArrayRead(X, &x);CHKERRQ(ierr);
202     ierr = VecGetArrayRead(XL, &xl);CHKERRQ(ierr);
203     ierr = VecGetArrayRead(XU, &xu);CHKERRQ(ierr);
204     ierr = VecGetArrayRead(G, &g);CHKERRQ(ierr);
205 
206     /* Loop over variables and categorize the indexes */
207     ierr = PetscMalloc1(n, &isl);CHKERRQ(ierr);
208     ierr = PetscMalloc1(n, &isu);CHKERRQ(ierr);
209     ierr = PetscMalloc1(n, &isf);CHKERRQ(ierr);
210     for (i=0; i<n; i++) {
211       if (xl[i] == xu[i]) {
212         /* Fixed variables here */
213         isf[n_isf]=low+i; ++n_isf;
214       } else if ((x[i] <= xl[i] + *bound_tol) && (g[i] > 0.0)) {
215         /* Lower bounded variables here */
216         isl[n_isl]=low+i; ++n_isl;
217       } else if ((x[i] >= xu[i] - *bound_tol) && (g[i] < 0.0)) {
218         /* Upper bounded variables here */
219         isu[n_isu]=low+i; ++n_isu;
220       }
221     }
222 
223     ierr = VecRestoreArrayRead(X, &x);CHKERRQ(ierr);
224     ierr = VecRestoreArrayRead(XL, &xl);CHKERRQ(ierr);
225     ierr = VecRestoreArrayRead(XU, &xu);CHKERRQ(ierr);
226     ierr = VecRestoreArrayRead(G, &g);CHKERRQ(ierr);
227   }
228 
229   /* Create index set for lower bounded variables */
230   ierr = ISDestroy(active_lower);CHKERRQ(ierr);
231   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)X), n_isl, isl, PETSC_OWN_POINTER, active_lower);CHKERRQ(ierr);
232   /* Create index set for upper bounded variables */
233   ierr = ISDestroy(active_upper);CHKERRQ(ierr);
234   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)X), n_isu, isu, PETSC_OWN_POINTER, active_upper);CHKERRQ(ierr);
235   /* Create index set for fixed variables */
236   ierr = ISDestroy(active_fixed);CHKERRQ(ierr);
237   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)X), n_isf, isf, PETSC_OWN_POINTER, active_fixed);CHKERRQ(ierr);
238 
239   /* Create the combined active set */
240   ierr = ISDestroy(active);CHKERRQ(ierr);
241   if (*active_lower && *active_upper && *active_fixed) {
242     /* All three types of active variables exist */
243     const IS islist[3] = {*active_lower, *active_upper, *active_fixed};
244     ierr = ISConcatenate(PetscObjectComm((PetscObject)X), 3, islist, active);CHKERRQ(ierr);
245     ierr = ISSort(*active);CHKERRQ(ierr);
246   } else if (*active_lower && *active_upper) {
247     /* Only lower and upper bounded active variables exist */
248     ierr = ISSum(*active_lower, *active_upper, active);CHKERRQ(ierr);
249   } else if (*active_lower && *active_fixed) {
250     /* Only lower bounded and fixed active variables exist */
251     ierr = ISSum(*active_lower, *active_fixed, active);CHKERRQ(ierr);
252   } else if (*active_upper && *active_fixed) {
253     /* Only upper bounded and fixed active variables exist */
254     ierr = ISSum(*active_upper, *active_fixed, active);CHKERRQ(ierr);
255   } else if (*active_lower) {
256     /* Only lower bounded active variables exist */
257     *active = *active_lower;
258   } else if (*active_upper) {
259     /* Only upper bounded active variables exist */
260     *active = *active_upper;
261   } else if (*active_fixed) {
262     /* Only fixed active variables exist */
263     *active = *active_fixed;
264   }
265   /* Create the inactive set */
266   ierr = ISDestroy(inactive);CHKERRQ(ierr);
267   if (*active) { ierr = ISComplementVec(*active, X, inactive);CHKERRQ(ierr); }
268 
269   /* Clean up and exit */
270   ierr = VecDestroy(&W);CHKERRQ(ierr);
271   PetscFunctionReturn(0);
272 }
273 
274 /*@C
275   TaoBoundStep - Ensures the correct zero or adjusted step direction
276   values for active variables.
277 
278   Input Parameters:
279 + X - solution vector
280 . XL - lower bound vector
281 . XU - upper bound vector
282 . active_lower - index set for lower bounded active variables
283 . active_upper - index set for lower bounded active variables
284 - active_fixed - index set for fixed active variables
285 
286   Output Parameters:
287 . S - step direction to be modified
288 @*/
289 PetscErrorCode TaoBoundStep(Vec X, Vec XL, Vec XU, IS active_lower, IS active_upper, IS active_fixed, Vec S)
290 {
291   PetscErrorCode               ierr;
292 
293   Vec                          step_lower, step_upper, step_fixed;
294   Vec                          x_lower, x_upper;
295   Vec                          bound_lower, bound_upper;
296 
297   PetscFunctionBegin;
298   /* Adjust step for variables at the estimated lower bound */
299   if (active_lower) {
300     ierr = VecGetSubVector(S, active_lower, &step_lower);CHKERRQ(ierr);
301     ierr = VecGetSubVector(X, active_lower, &x_lower);CHKERRQ(ierr);
302     ierr = VecGetSubVector(XL, active_lower, &bound_lower);CHKERRQ(ierr);
303     ierr = VecCopy(bound_lower, step_lower);CHKERRQ(ierr);
304     ierr = VecAXPY(step_lower, -1.0, x_lower);CHKERRQ(ierr);
305     ierr = VecRestoreSubVector(S, active_lower, &step_lower);CHKERRQ(ierr);
306     ierr = VecRestoreSubVector(X, active_lower, &x_lower);CHKERRQ(ierr);
307     ierr = VecRestoreSubVector(XL, active_lower, &bound_lower);CHKERRQ(ierr);
308   }
309 
310   /* Adjust step for the variables at the estimated upper bound */
311   if (active_upper) {
312     ierr = VecGetSubVector(S, active_upper, &step_upper);CHKERRQ(ierr);
313     ierr = VecGetSubVector(X, active_upper, &x_upper);CHKERRQ(ierr);
314     ierr = VecGetSubVector(XU, active_upper, &bound_upper);CHKERRQ(ierr);
315     ierr = VecCopy(bound_upper, step_upper);CHKERRQ(ierr);
316     ierr = VecAXPY(step_upper, -1.0, x_upper);CHKERRQ(ierr);
317     ierr = VecRestoreSubVector(S, active_upper, &step_upper);CHKERRQ(ierr);
318     ierr = VecRestoreSubVector(X, active_upper, &x_upper);CHKERRQ(ierr);
319     ierr = VecRestoreSubVector(XU, active_upper, &bound_upper);CHKERRQ(ierr);
320   }
321 
322   /* Zero out step for fixed variables */
323   if (active_fixed) {
324     ierr = VecGetSubVector(S, active_fixed, &step_fixed);CHKERRQ(ierr);
325     ierr = VecSet(step_fixed, 0.0);CHKERRQ(ierr);
326     ierr = VecRestoreSubVector(S, active_fixed, &step_fixed);CHKERRQ(ierr);
327   }
328   PetscFunctionReturn(0);
329 }
330