Actual source code: regressor.c

  1: #include <petsc/private/regressorimpl.h>

  3: PetscBool         PetscRegressorRegisterAllCalled = PETSC_FALSE;
  4: PetscFunctionList PetscRegressorList              = NULL;

  6: PetscClassId PETSCREGRESSOR_CLASSID;

  8: /* Logging support */
  9: PetscLogEvent PetscRegressor_SetUp, PetscRegressor_Fit, PetscRegressor_Predict;

 11: /*@C
 12:   PetscRegressorRegister - Adds a method to the `PetscRegressor` package.

 14:   Not collective

 16:   Input Parameters:
 17: + sname    - name of a new user-defined regressor
 18: - function - routine to create method context

 20:   Notes:
 21:   `PetscRegressorRegister()` may be called multiple times to add several user-defined regressors.

 23:   Example Usage:
 24: .vb
 25:    PetscRegressorRegister("my_regressor",MyRegressorCreate);
 26: .ve

 28:   Then, your regressor can be chosen with the procedural interface via
 29: .vb
 30:      PetscRegressorSetType(regressor,"my_regressor")
 31: .ve
 32:   or at runtime via the option
 33: .vb
 34:     -regressor_type my_regressor
 35: .ve

 37:   Level: advanced

 39: .seealso: `PetscRegressorRegisterAll()`
 40: @*/
 41: PetscErrorCode PetscRegressorRegister(const char sname[], PetscErrorCode (*function)(PetscRegressor))
 42: {
 43:   PetscFunctionBegin;
 44:   PetscCall(PetscRegressorInitializePackage());
 45:   PetscCall(PetscFunctionListAdd(&PetscRegressorList, sname, function));
 46:   PetscFunctionReturn(PETSC_SUCCESS);
 47: }

 49: /*@
 50:   PetscRegressorCreate - Creates a `PetscRegressor` object.

 52:   Collective

 54:   Input Parameter:
 55: . comm - the MPI communicator that will share the `PetscRegressor` object

 57:   Output Parameter:
 58: . newregressor - the new `PetscRegressor` object

 60:   Level: beginner

 62: .seealso: `PetscRegressorFit()`, `PetscRegressorPredict()`, `PetscRegressor`
 63: @*/
 64: PetscErrorCode PetscRegressorCreate(MPI_Comm comm, PetscRegressor *newregressor)
 65: {
 66:   PetscRegressor regressor;

 68:   PetscFunctionBegin;
 69:   PetscAssertPointer(newregressor, 2);
 70:   *newregressor = NULL;
 71:   PetscCall(PetscRegressorInitializePackage());

 73:   PetscCall(PetscHeaderCreate(regressor, PETSCREGRESSOR_CLASSID, "PetscRegressor", "Regressor", "PetscRegressor", comm, PetscRegressorDestroy, PetscRegressorView));

 75:   regressor->setupcalled = PETSC_FALSE;
 76:   regressor->fitcalled   = PETSC_FALSE;
 77:   regressor->data        = NULL;
 78:   regressor->training    = NULL;
 79:   regressor->target      = NULL;
 80:   PetscObjectParameterSetDefault(regressor, regularizer_weight, 1.0); // Default to regularizer weight of 1.0, usually the default in SciKit-learn

 82:   *newregressor = regressor;
 83:   PetscFunctionReturn(PETSC_SUCCESS);
 84: }

 86: /*@
 87:   PetscRegressorView - Prints information about the `PetscRegressor` object

 89:   Collective

 91:   Input Parameters:
 92: + regressor - the `PetscRegressor` context
 93: - viewer    - a `PetscViewer` context

 95:   Options Database Key:
 96: . -regressor_view - Calls `PetscRegressorView()` at the end of `PetscRegressorFit()`

 98:   Level: beginner

100:   Notes:
101:   The available visualization contexts include
102: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
103: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
104:   output where only the first processor opens
105:   the file.  All other processors send their
106:   data to the first processor to print.

108: .seealso: [](ch_regressor), `PetscRegressor`, `PetscViewerASCIIOpen()`
109: @*/
110: PetscErrorCode PetscRegressorView(PetscRegressor regressor, PetscViewer viewer)
111: {
112:   PetscBool          isascii, isstring;
113:   PetscRegressorType type;

115:   PetscFunctionBegin;
117:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(((PetscObject)regressor)->comm, &viewer));
119:   PetscCheckSameComm(regressor, 1, viewer, 2);

121:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
122:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
123:   if (isascii) {
124:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)regressor, viewer));

126:     PetscCall(PetscViewerASCIIPushTab(viewer));
127:     PetscTryTypeMethod(regressor, view, viewer);
128:     if (regressor->tao) PetscCall(TaoView(regressor->tao, viewer));
129:     PetscCall(PetscViewerASCIIPopTab(viewer));
130:   } else if (isstring) {
131:     PetscCall(PetscRegressorGetType(regressor, &type));
132:     PetscCall(PetscViewerStringSPrintf(viewer, " PetscRegressorType: %-7.7s", type));
133:   }
134:   PetscFunctionReturn(PETSC_SUCCESS);
135: }

137: /*@
138:   PetscRegressorViewFromOptions - View a `PetscRegressor` object based on values in the options database

140:   Collective

142:   Input Parameters:
143: + A    - the  `PetscRegressor` context
144: . obj  - Optional object that provides the prefix for the options database
145: - name - command line option

147:   Level: intermediate

149: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorView`, `PetscObjectViewFromOptions()`, `PetscRegressorCreate()`
150: @*/
151: PetscErrorCode PetscRegressorViewFromOptions(PetscRegressor A, PetscObject obj, const char name[])
152: {
153:   PetscFunctionBegin;
155:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
156:   PetscFunctionReturn(PETSC_SUCCESS);
157: }

159: /*@
160:   PetscRegressorSetFromOptions - Sets `PetscRegressor` options from the options database.

162:   Collective

164:   Input Parameter:
165: . regressor - the `PetscRegressor` context

167:   Options Database Keys:
168: . -regressor_type <type> - the particular type of regressor to be used; see `PetscRegressorType` for complete list

170:   Level: beginner

172:   Note:
173:   This routine must be called before `PetscRegressorSetUp()` (or `PetscRegressorFit()`, which calls
174:   the former) if the user is to be allowed to set the regressor type.

176: .seealso: `PetscRegressor`, `PetscRegressorCreate()`
177: @*/
178: PetscErrorCode PetscRegressorSetFromOptions(PetscRegressor regressor)
179: {
180:   PetscBool          flg;
181:   PetscRegressorType default_type = PETSCREGRESSORLINEAR;
182:   char               type[256];

184:   PetscFunctionBegin;
186:   if (((PetscObject)regressor)->type_name) default_type = ((PetscObject)regressor)->type_name;
187:   PetscObjectOptionsBegin((PetscObject)regressor);
188:   /* Check for type from options */
189:   PetscCall(PetscOptionsFList("-regressor_type", "PetscRegressor type", "PetscRegressorSetType", PetscRegressorList, default_type, type, 256, &flg));
190:   if (flg) {
191:     PetscCall(PetscRegressorSetType(regressor, type));
192:   } else if (!((PetscObject)regressor)->type_name) {
193:     PetscCall(PetscRegressorSetType(regressor, default_type));
194:   }
195:   PetscCall(PetscOptionsReal("-regressor_regularizer_weight", "Weight for the regularizer", "PetscRegressorSetRegularizerWeight", regressor->regularizer_weight, &regressor->regularizer_weight, &flg));
196:   if (flg) PetscCall(PetscRegressorSetRegularizerWeight(regressor, regressor->regularizer_weight));
197:   // The above is a little superfluous, because we have already set regressor->regularizer_weight above, but we also need to set the flag indicating that the user has set the weight!
198:   PetscTryTypeMethod(regressor, setfromoptions, PetscOptionsObject);
199:   PetscOptionsEnd();
200:   PetscFunctionReturn(PETSC_SUCCESS);
201: }

203: /*@
204:   PetscRegressorSetUp - Sets up the internal data structures for the later use of a regressor.

206:   Collective

208:   Input Parameter:
209: . regressor - the `PetscRegressor` context

211:   Notes:
212:   For basic use of the `PetscRegressor` solvers the user need not to explicitly call
213:   `PetscRegressorSetUp()`, since these actions will automatically occur during
214:   the call to `PetscRegressorFit()`.  However, if one wishes to control this
215:   phase separately, `PetscRegressorSetUp()` should be called after `PetscRegressorCreate()`,
216:   `PetscRegressorSetUp()`, and optional routines of the form `PetscRegressorSetXXX()`,
217:   but before `PetscRegressorFit()`.

219:   Level: advanced

221: .seealso: `PetscRegressorCreate()`, `PetscRegressorFit()`, `PetscRegressorDestroy()`
222: @*/
223: PetscErrorCode PetscRegressorSetUp(PetscRegressor regressor)
224: {
225:   PetscFunctionBegin;
227:   if (regressor->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
228:   PetscCall(PetscLogEventBegin(PetscRegressor_SetUp, regressor, 0, 0, 0));
229:   //TODO is there some mat vec etc that must be set, like TaoSolution?
230:   PetscTryTypeMethod(regressor, setup);
231:   regressor->setupcalled = PETSC_TRUE;
232:   PetscCall(PetscLogEventEnd(PetscRegressor_SetUp, regressor, 0, 0, 0));
233:   PetscFunctionReturn(PETSC_SUCCESS);
234: }

236: /* NOTE: I've decided to make this take X and y, like the Scikit-learn Fit routines do.
237:  * Am I overlooking some reason that X should be set in a separate function call, a la KSPSetOperators()?. */
238: /*@
239:   PetscRegressorFit - Fit, or train, a regressor from a training dataset

241:   Collective

243:   Input Parameters:
244: + regressor - the `PetscRegressor` context
245: . X         - matrix of training data (of dimension [number of samples] x [number of features])
246: - y         - vector of target values from the training dataset

248:   Level: beginner

250: .seealso: `PetscRegressorCreate()`, `PetscRegressorSetUp()`, `PetscRegressorDestroy()`, `PetscRegressorPredict()`
251: @*/
252: PetscErrorCode PetscRegressorFit(PetscRegressor regressor, Mat X, Vec y)
253: {
254:   PetscFunctionBegin;

259:   if (X) {
260:     PetscCall(PetscObjectReference((PetscObject)X));
261:     PetscCall(MatDestroy(&regressor->training));
262:     regressor->training = X;
263:   }
264:   if (y) {
265:     PetscCall(PetscObjectReference((PetscObject)y));
266:     PetscCall(VecDestroy(&regressor->target));
267:     regressor->target = y;
268:   }
269:   PetscCall(PetscRegressorSetUp(regressor));

271:   PetscCall(PetscLogEventBegin(PetscRegressor_Fit, regressor, X, y, 0));
272:   PetscUseTypeMethod(regressor, fit);
273:   PetscCall(PetscLogEventEnd(PetscRegressor_Fit, regressor, X, y, 0));
274:   //TODO print convergence data
275:   PetscCall(PetscRegressorViewFromOptions(regressor, NULL, "-regressor_view"));
276:   regressor->fitcalled = PETSC_TRUE;
277:   PetscFunctionReturn(PETSC_SUCCESS);
278: }

280: /*@
281:   PetscRegressorPredict - Compute predictions (that is, perform inference) using a fitted regression model.

283:   Collective

285:   Input Parameters:
286: + regressor - the `PetscRegressor` context (for which `PetscRegressorFit()` must have been called)
287: - X         - data matrix of unlabeled observations

289:   Output Parameter:
290: . y - vector of predicted labels

292:   Level: beginner

294: .seealso: `PetscRegressorFit()`, `PetscRegressorDestroy()`
295: @*/
296: PetscErrorCode PetscRegressorPredict(PetscRegressor regressor, Mat X, Vec y)
297: {
298:   PetscFunctionBegin;
302:   PetscCheck(regressor->fitcalled == PETSC_TRUE, ((PetscObject)regressor)->comm, PETSC_ERR_ARG_WRONGSTATE, "PetscRegressorFit() must be called before PetscRegressorPredict()");
303:   PetscCall(PetscLogEventBegin(PetscRegressor_Predict, regressor, X, y, 0));
304:   PetscTryTypeMethod(regressor, predict, X, y);
305:   PetscCall(PetscLogEventEnd(PetscRegressor_Predict, regressor, X, y, 0));
306:   PetscFunctionReturn(PETSC_SUCCESS);
307: }

309: /*@
310:   PetscRegressorReset - Resets a `PetscRegressor` context by removing any allocated `Vec` and `Mat`. Any options set in the object remain.

312:   Collective

314:   Input Parameter:
315: . regressor - context obtained from `PetscRegressorCreate()`

317:   Level: intermediate

319: .seealso: `PetscRegressorCreate()`, `PetscRegressorSetUp()`, `PetscRegressorFit()`, `PetscRegressorPredict()`, `PetscRegressorDestroy()`
320: @*/
321: PetscErrorCode PetscRegressorReset(PetscRegressor regressor)
322: {
323:   PetscFunctionBegin;
325:   if (regressor->ops->reset) PetscTryTypeMethod(regressor, reset);
326:   PetscCall(MatDestroy(&regressor->training));
327:   PetscCall(VecDestroy(&regressor->target));
328:   PetscCall(TaoDestroy(&regressor->tao));
329:   regressor->setupcalled = PETSC_FALSE;
330:   regressor->fitcalled   = PETSC_FALSE;
331:   PetscFunctionReturn(PETSC_SUCCESS);
332: }

334: /*@C
335:   PetscRegressorDestroy - Destroys the regressor context that was created with `PetscRegressorCreate()`.

337:   Collective

339:   Input Parameter:
340: . regressor - the `PetscRegressor` context

342:   Level: beginner

344: .seealso: `PetscRegressorCreate()`, `PetscRegressorSetUp()`, `PetscRegressorReset()`, `PetscRegressor`
345: @*/
346: PetscErrorCode PetscRegressorDestroy(PetscRegressor *regressor)
347: {
348:   PetscFunctionBegin;
349:   if (!*regressor) PetscFunctionReturn(PETSC_SUCCESS);
351:   if (--((PetscObject)*regressor)->refct > 0) {
352:     *regressor = NULL;
353:     PetscFunctionReturn(PETSC_SUCCESS);
354:   }

356:   PetscCall(PetscRegressorReset(*regressor));
357:   PetscTryTypeMethod(*regressor, destroy);

359:   PetscCall(PetscHeaderDestroy(regressor));
360:   PetscFunctionReturn(PETSC_SUCCESS);
361: }

363: /*@C
364:   PetscRegressorSetType - Sets the type for the regressor.

366:   Collective

368:   Input Parameters:
369: + regressor - the `PetscRegressor` context
370: - type      - a known regression method

372:   Options Database Key:
373: . -regressor_type <type> - Sets the type of regressor; use -help for a list of available types

375:   Level: intermediate

377:   Notes:
378:   See "include/petscregressor.h" for available methods (for instance)
379: .    `PETSCREGRESSORLINEAR` - Regression model that is linear in its coefficients; supports ordinary least squares as well as regularized variants

381:   Normally, it is best to use the `PetscRegressorSetFromOptions()` command and then
382:   set the `PetscRegressor` type from the options database rather than by using
383:   this routine, as this provides maximum flexibility.
384:   The `PetscRegressorSetType()` routine is provided for those situations where it
385:   is necessary to set the nonlinear solver independently of the command
386:   line or options database.

388: .seealso: `PetscRegressorType`
389: @*/
390: PetscErrorCode PetscRegressorSetType(PetscRegressor regressor, PetscRegressorType type)
391: {
392:   PetscErrorCode (*r)(PetscRegressor);
393:   PetscBool match;

395:   PetscFunctionBegin;
397:   PetscAssertPointer(type, 2);

399:   PetscCall(PetscObjectTypeCompare((PetscObject)regressor, type, &match));
400:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

402:   PetscCall(PetscFunctionListFind(PetscRegressorList, type, &r));
403:   PetscCheck(r, PetscObjectComm((PetscObject)regressor), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested PetscRegressor type %s", type);

405:   /* Destroy the existing solver information */
406:   PetscTryTypeMethod(regressor, destroy);
407:   PetscCall(TaoDestroy(&regressor->tao));
408:   regressor->ops->setup          = NULL;
409:   regressor->ops->setfromoptions = NULL;
410:   regressor->ops->settraining    = NULL;
411:   regressor->ops->fit            = NULL;
412:   regressor->ops->predict        = NULL;
413:   regressor->ops->destroy        = NULL;
414:   regressor->ops->reset          = NULL;
415:   regressor->ops->view           = NULL;

417:   /* Call the PetscRegressorCreate_XXX routine for this particular regressor */
418:   regressor->setupcalled = PETSC_FALSE;
419:   PetscCall((*r)(regressor));
420:   PetscCall(PetscObjectChangeTypeName((PetscObject)regressor, type));
421:   PetscFunctionReturn(PETSC_SUCCESS);
422: }

424: /*@
425:   PetscRegressorGetType - Gets the current `PetscRegressorType` being used in the `PetscRegressor` object

427:   Not Collective

429:   Input Parameter:
430: . regressor - the `PetscRegressor` solver context

432:   Output Parameter:
433: . type - the `PetscRegressorType`

435:   Level: intermediate

437: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorType`, `PetscRegressorSetType()`
438: @*/
439: PetscErrorCode PetscRegressorGetType(PetscRegressor regressor, PetscRegressorType *type)
440: {
441:   PetscFunctionBegin;
443:   PetscAssertPointer(type, 2);
444:   *type = ((PetscObject)regressor)->type_name;
445:   PetscFunctionReturn(PETSC_SUCCESS);
446: }

448: /*@
449:   PetscRegressorSetRegularizerWeight - Sets the weight to be used for the regularizer for a `PetscRegressor` context

451:   Logically Collective

453:   Input Parameters:
454: + regressor - the `PetscRegressor` context
455: - weight    - the regularizer weight

457:   Options Database Key:
458: . regressor_regularizer_weight <weight> - sets the regularizer's weight

460:   Level: beginner

462: .seealso: `PetscRegressorSetType`
463: @*/
464: PetscErrorCode PetscRegressorSetRegularizerWeight(PetscRegressor regressor, PetscReal weight)
465: {
466:   PetscFunctionBegin;
469:   regressor->regularizer_weight = weight;
470:   PetscFunctionReturn(PETSC_SUCCESS);
471: }

473: /*@
474:   PetscRegressorGetTao - Returns the `Tao` context for a `PetscRegressor` object.

476:   Not Collective, but if the `PetscRegressor` is parallel, then the `Tao` object is parallel

478:   Input Parameter:
479: . regressor - the regressor context

481:   Output Parameter:
482: . tao - the `Tao` context

484:   Level: beginner

486:   Notes:
487:   The `Tao` object will be created if it does not yet exist.

489:   The user can directly manipulate the `Tao` context to set various
490:   options, etc.  Likewise, the user can then extract and manipulate the
491:   child contexts such as `KSP` or `TaoLineSearch`as well.

493:   Depending on the type of the regressor and the options that are set, the regressor may use not use a `Tao` object.

495: .seealso: `PetscRegressorLinearGetKSP()`
496: @*/
497: PetscErrorCode PetscRegressorGetTao(PetscRegressor regressor, Tao *tao)
498: {
499:   PetscFunctionBegin;
501:   PetscAssertPointer(tao, 2);
502:   // Analogous to how SNESGetKSP() operates, this routine should create the Tao if it doesn't exist.
503:   if (!regressor->tao) {
504:     PetscCall(TaoCreate(PetscObjectComm((PetscObject)regressor), &regressor->tao));
505:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)regressor->tao, (PetscObject)regressor, 1));
506:     PetscCall(PetscObjectSetOptions((PetscObject)regressor->tao, ((PetscObject)regressor)->options));
507:   }
508:   *tao = regressor->tao;
509:   PetscFunctionReturn(PETSC_SUCCESS);
510: }

512: /*@
513:   PetscRegressorSetOptionsPrefix - Sets the prefix used for searching for all
514:   PetscRegressor options in the database.

516:   Logically Collective

518:   Input Parameters:
519: + regressor - the `PetscRegressor` context
520: - p         - the prefix string to prepend to all PetscRegressor option requests

522:   Level: advanced

524:   Notes:
525:   A hyphen (-) must NOT be given at the beginning of the prefix name.
526:   The first character of all runtime options is AUTOMATICALLY the hyphen.

528:   For example, to distinguish between the runtime options for two
529:   different PetscRegressor solvers, one could call
530: .vb
531:       PetscRegressorSetOptionsPrefix(regressor1,"sys1_")
532:       PetscRegressorSetOptionsPrefix(regressor2,"sys2_")
533: .ve

535:   This would enable use of different options for each system, such as
536: .vb
537:       -sys1_regressor_method linear -sys1_regressor_regularizer_weight 1.2
538:       -sys2_regressor_method linear -sys2_regressor_regularizer_weight 1.1
539: .ve

541: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorSetFromOptions()`, `PetscRegressorAppendOptionsPrefix()`, `PetscRegressorGetOptionsPrefix()`
542: @*/
543: PetscErrorCode PetscRegressorSetOptionsPrefix(PetscRegressor regressor, const char p[])
544: {
545:   PetscFunctionBegin;
547:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)regressor, p));
548:   PetscFunctionReturn(PETSC_SUCCESS);
549: }

551: /*@
552:   PetscRegressorAppendOptionsPrefix - Appends to the prefix used for searching for all PetscRegressor options in the database.

554:   Logically Collective

556:   Input Parameters:
557: + regressor - the `PetscRegressor` solver context
558: - p         - the prefix string to prepend to all `PetscRegressor` option requests

560:   Level: advanced

562:   Note:
563:   A hyphen (-) must NOT be given at the beginning of the prefix name.
564:   The first character of all runtime options is automatically the hyphen.

566: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorSetFromOptions()`, `PetscRegressorSetOptionsPrefix()`, `PetscRegressorGetOptionsPrefix()`
567: @*/
568: PetscErrorCode PetscRegressorAppendOptionsPrefix(PetscRegressor regressor, const char p[])
569: {
570:   PetscFunctionBegin;
572:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)regressor, p));
573:   PetscFunctionReturn(PETSC_SUCCESS);
574: }

576: /*@
577:   PetscRegressorGetOptionsPrefix - Gets the prefix used for searching for all
578:   PetscRegressor options in the database

580:   Not Collective

582:   Input Parameter:
583: . regressor - the `PetscRegressor` context

585:   Output Parameter:
586: . p - pointer to the prefix string used is returned

588:   Fortran Notes:
589:   Pass in a string 'prefix' of sufficient length to hold the prefix.

591:   Level: advanced

593: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorSetFromOptions()`, `PetscRegressorSetOptionsPrefix()`, `PetscRegressorAppendOptionsPrefix()`
594: @*/
595: PetscErrorCode PetscRegressorGetOptionsPrefix(PetscRegressor regressor, const char *p[])
596: {
597:   PetscFunctionBegin;
599:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)regressor, p));
600:   PetscFunctionReturn(PETSC_SUCCESS);
601: }