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:   Options Database Key:
148: . -name [viewertype][:...] - option name and values. See `PetscObjectViewFromOptions()` for the possible arguments

150:   Level: intermediate

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

162: /*@
163:   PetscRegressorSetFromOptions - Sets `PetscRegressor` options from the options database.

165:   Collective

167:   Input Parameter:
168: . regressor - the `PetscRegressor` context

170:   Options Database Keys:
171: . -regressor_type type - the particular type of regressor to be used; see `PetscRegressorType` for complete list

173:   Level: beginner

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

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

187:   PetscFunctionBegin;
189:   if (((PetscObject)regressor)->type_name) default_type = ((PetscObject)regressor)->type_name;
190:   PetscObjectOptionsBegin((PetscObject)regressor);
191:   /* Check for type from options */
192:   PetscCall(PetscOptionsFList("-regressor_type", "PetscRegressor type", "PetscRegressorSetType", PetscRegressorList, default_type, type, 256, &flg));
193:   if (flg) {
194:     PetscCall(PetscRegressorSetType(regressor, type));
195:   } else if (!((PetscObject)regressor)->type_name) {
196:     PetscCall(PetscRegressorSetType(regressor, default_type));
197:   }
198:   PetscCall(PetscOptionsReal("-regressor_regularizer_weight", "Weight for the regularizer", "PetscRegressorSetRegularizerWeight", regressor->regularizer_weight, &regressor->regularizer_weight, &flg));
199:   if (flg) PetscCall(PetscRegressorSetRegularizerWeight(regressor, regressor->regularizer_weight));
200:   // 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!
201:   PetscTryTypeMethod(regressor, setfromoptions, PetscOptionsObject);
202:   PetscOptionsEnd();
203:   PetscFunctionReturn(PETSC_SUCCESS);
204: }

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

209:   Collective

211:   Input Parameter:
212: . regressor - the `PetscRegressor` context

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

222:   Level: advanced

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

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

244:   Collective

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

251:   Level: beginner

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

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

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

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

286:   Collective

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

292:   Output Parameter:
293: . y - vector of predicted labels

295:   Level: beginner

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

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

315:   Collective

317:   Input Parameter:
318: . regressor - context obtained from `PetscRegressorCreate()`

320:   Level: intermediate

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

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

340:   Collective

342:   Input Parameter:
343: . regressor - the `PetscRegressor` context

345:   Level: beginner

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

359:   PetscCall(PetscRegressorReset(*regressor));
360:   PetscTryTypeMethod(*regressor, destroy);

362:   PetscCall(PetscHeaderDestroy(regressor));
363:   PetscFunctionReturn(PETSC_SUCCESS);
364: }

366: /*@C
367:   PetscRegressorSetType - Sets the type for the regressor.

369:   Collective

371:   Input Parameters:
372: + regressor - the `PetscRegressor` context
373: - type      - a known regression method

375:   Options Database Key:
376: . -regressor_type type - Sets the type of regressor; use -help for a list of available types

378:   Level: intermediate

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

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

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

398:   PetscFunctionBegin;
400:   PetscAssertPointer(type, 2);

402:   PetscCall(PetscObjectTypeCompare((PetscObject)regressor, type, &match));
403:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

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

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

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

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

430:   Not Collective

432:   Input Parameter:
433: . regressor - the `PetscRegressor` solver context

435:   Output Parameter:
436: . type - the `PetscRegressorType`

438:   Level: intermediate

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

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

454:   Logically Collective

456:   Input Parameters:
457: + regressor - the `PetscRegressor` context
458: - weight    - the regularizer weight

460:   Options Database Key:
461: . regressor_regularizer_weight weight - sets the regularizer's weight

463:   Level: beginner

465: .seealso: `PetscRegressorSetType`
466: @*/
467: PetscErrorCode PetscRegressorSetRegularizerWeight(PetscRegressor regressor, PetscReal weight)
468: {
469:   PetscFunctionBegin;
472:   regressor->regularizer_weight = weight;
473:   PetscFunctionReturn(PETSC_SUCCESS);
474: }

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

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

481:   Input Parameter:
482: . regressor - the regressor context

484:   Output Parameter:
485: . tao - the `Tao` context

487:   Level: beginner

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

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

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

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

515: /*@
516:   PetscRegressorSetOptionsPrefix - Sets the prefix used for searching for all
517:   PetscRegressor options in the database.

519:   Logically Collective

521:   Input Parameters:
522: + regressor - the `PetscRegressor` context
523: - p         - the prefix string to prepend to all PetscRegressor option requests

525:   Level: advanced

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

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

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

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

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

557:   Logically Collective

559:   Input Parameters:
560: + regressor - the `PetscRegressor` solver context
561: - p         - the prefix string to prepend to all `PetscRegressor` option requests

563:   Level: advanced

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

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

579: /*@
580:   PetscRegressorGetOptionsPrefix - Gets the prefix used for searching for all
581:   PetscRegressor options in the database

583:   Not Collective

585:   Input Parameter:
586: . regressor - the `PetscRegressor` context

588:   Output Parameter:
589: . p - pointer to the prefix string used is returned

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

594:   Level: advanced

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