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: /*@
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 viewer_specification - Calls `PetscRegressorView()` at the end of `PetscRegressorFit()`, see `PetscOptionsCreateViewer()` for the format of `viewer_specification`
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()`, `PetscRegressorViewFromOptions()`, `PetscRegressorFit()`, `PetscOptionsCreateViewer()`
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, pass `NULL` to use the options prefix of `A`
145: - name - command line option
147: Options Database Key:
148: . -name viewer_specification - See `PetscOptionsCreateViewer()` for the values of `viewer_specification`
150: Level: intermediate
152: Note:
153: This checks the options database, creates the viewer on-the-fly, uses it and then destroys it. Hence it should not be called in heavily used routines,
154: rather `PetscOptionsCreateViewer()` should be used to construct the viewer once which can then be utilized in the heavily used routine.
156: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorView()`, `PetscObjectViewFromOptions()`, `PetscRegressorCreate()`, `PetscOptionsCreateViewer()`
157: @*/
158: PetscErrorCode PetscRegressorViewFromOptions(PetscRegressor A, PetscObject obj, const char name[])
159: {
160: PetscFunctionBegin;
162: PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
163: PetscFunctionReturn(PETSC_SUCCESS);
164: }
166: /*@
167: PetscRegressorSetFromOptions - Sets `PetscRegressor` options from the options database.
169: Collective
171: Input Parameter:
172: . regressor - the `PetscRegressor` context
174: Options Database Keys:
175: . -regressor_type (linear) - the particular type of regressor to be used
177: Level: beginner
179: Note:
180: This routine must be called before `PetscRegressorSetUp()` (or `PetscRegressorFit()`, which calls
181: the former) if the user is to be allowed to set the regressor type.
183: .seealso: `PetscRegressor`, `PetscRegressorCreate()`
184: @*/
185: PetscErrorCode PetscRegressorSetFromOptions(PetscRegressor regressor)
186: {
187: PetscBool flg;
188: PetscRegressorType default_type = PETSCREGRESSORLINEAR;
189: char type[256];
191: PetscFunctionBegin;
193: if (((PetscObject)regressor)->type_name) default_type = ((PetscObject)regressor)->type_name;
194: PetscObjectOptionsBegin((PetscObject)regressor);
195: /* Check for type from options */
196: PetscCall(PetscOptionsFList("-regressor_type", "PetscRegressor type", "PetscRegressorSetType", PetscRegressorList, default_type, type, sizeof(type), &flg));
197: if (flg) {
198: PetscCall(PetscRegressorSetType(regressor, type));
199: } else if (!((PetscObject)regressor)->type_name) {
200: PetscCall(PetscRegressorSetType(regressor, default_type));
201: }
202: PetscCall(PetscOptionsReal("-regressor_regularizer_weight", "Weight for the regularizer", "PetscRegressorSetRegularizerWeight", regressor->regularizer_weight, ®ressor->regularizer_weight, &flg));
203: if (flg) PetscCall(PetscRegressorSetRegularizerWeight(regressor, regressor->regularizer_weight));
204: // 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!
205: PetscTryTypeMethod(regressor, setfromoptions, PetscOptionsObject);
206: PetscOptionsEnd();
207: PetscFunctionReturn(PETSC_SUCCESS);
208: }
210: /*@
211: PetscRegressorSetUp - Sets up the internal data structures for the later use of a regressor.
213: Collective
215: Input Parameter:
216: . regressor - the `PetscRegressor` context
218: Notes:
219: For basic use of the `PetscRegressor` solvers the user need not to explicitly call
220: `PetscRegressorSetUp()`, since these actions will automatically occur during
221: the call to `PetscRegressorFit()`. However, if one wishes to control this
222: phase separately, `PetscRegressorSetUp()` should be called after `PetscRegressorCreate()`,
223: `PetscRegressorSetUp()`, and optional routines of the form `PetscRegressorSetXXX()`,
224: but before `PetscRegressorFit()`.
226: Level: advanced
228: .seealso: `PetscRegressorCreate()`, `PetscRegressorFit()`, `PetscRegressorDestroy()`
229: @*/
230: PetscErrorCode PetscRegressorSetUp(PetscRegressor regressor)
231: {
232: PetscFunctionBegin;
234: if (regressor->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
235: PetscCall(PetscLogEventBegin(PetscRegressor_SetUp, regressor, 0, 0, 0));
236: //TODO is there some mat vec etc that must be set, like TaoSolution?
237: PetscTryTypeMethod(regressor, setup);
238: regressor->setupcalled = PETSC_TRUE;
239: PetscCall(PetscLogEventEnd(PetscRegressor_SetUp, regressor, 0, 0, 0));
240: PetscFunctionReturn(PETSC_SUCCESS);
241: }
243: /* NOTE: I've decided to make this take X and y, like the Scikit-learn Fit routines do.
244: * Am I overlooking some reason that X should be set in a separate function call, a la KSPSetOperators()?. */
245: /*@
246: PetscRegressorFit - Fit, or train, a regressor from a training dataset
248: Collective
250: Input Parameters:
251: + regressor - the `PetscRegressor` context
252: . X - matrix of training data (of dimension [number of samples] x [number of features])
253: - y - vector of target values from the training dataset
255: Level: beginner
257: .seealso: `PetscRegressorCreate()`, `PetscRegressorSetUp()`, `PetscRegressorDestroy()`, `PetscRegressorPredict()`
258: @*/
259: PetscErrorCode PetscRegressorFit(PetscRegressor regressor, Mat X, Vec y)
260: {
261: PetscFunctionBegin;
266: if (X) {
267: PetscCall(PetscObjectReference((PetscObject)X));
268: PetscCall(MatDestroy(®ressor->training));
269: regressor->training = X;
270: }
271: if (y) {
272: PetscCall(PetscObjectReference((PetscObject)y));
273: PetscCall(VecDestroy(®ressor->target));
274: regressor->target = y;
275: }
276: PetscCall(PetscRegressorSetUp(regressor));
278: PetscCall(PetscLogEventBegin(PetscRegressor_Fit, regressor, X, y, 0));
279: PetscUseTypeMethod(regressor, fit);
280: PetscCall(PetscLogEventEnd(PetscRegressor_Fit, regressor, X, y, 0));
281: //TODO print convergence data
282: PetscCall(PetscRegressorViewFromOptions(regressor, NULL, "-regressor_view"));
283: regressor->fitcalled = PETSC_TRUE;
284: PetscFunctionReturn(PETSC_SUCCESS);
285: }
287: /*@
288: PetscRegressorPredict - Compute predictions (that is, perform inference) using a fitted regression model.
290: Collective
292: Input Parameters:
293: + regressor - the `PetscRegressor` context (for which `PetscRegressorFit()` must have been called)
294: - X - data matrix of unlabeled observations
296: Output Parameter:
297: . y - vector of predicted labels
299: Level: beginner
301: .seealso: `PetscRegressorFit()`, `PetscRegressorDestroy()`
302: @*/
303: PetscErrorCode PetscRegressorPredict(PetscRegressor regressor, Mat X, Vec y)
304: {
305: PetscFunctionBegin;
309: PetscCheck(regressor->fitcalled == PETSC_TRUE, ((PetscObject)regressor)->comm, PETSC_ERR_ARG_WRONGSTATE, "PetscRegressorFit() must be called before PetscRegressorPredict()");
310: PetscCall(PetscLogEventBegin(PetscRegressor_Predict, regressor, X, y, 0));
311: PetscTryTypeMethod(regressor, predict, X, y);
312: PetscCall(PetscLogEventEnd(PetscRegressor_Predict, regressor, X, y, 0));
313: PetscFunctionReturn(PETSC_SUCCESS);
314: }
316: /*@
317: PetscRegressorReset - Resets a `PetscRegressor` context by removing any allocated `Vec` and `Mat`. Any options set in the object remain.
319: Collective
321: Input Parameter:
322: . regressor - context obtained from `PetscRegressorCreate()`
324: Level: intermediate
326: .seealso: `PetscRegressorCreate()`, `PetscRegressorSetUp()`, `PetscRegressorFit()`, `PetscRegressorPredict()`, `PetscRegressorDestroy()`
327: @*/
328: PetscErrorCode PetscRegressorReset(PetscRegressor regressor)
329: {
330: PetscFunctionBegin;
332: if (regressor->ops->reset) PetscTryTypeMethod(regressor, reset);
333: PetscCall(MatDestroy(®ressor->training));
334: PetscCall(VecDestroy(®ressor->target));
335: PetscCall(TaoDestroy(®ressor->tao));
336: regressor->setupcalled = PETSC_FALSE;
337: regressor->fitcalled = PETSC_FALSE;
338: PetscFunctionReturn(PETSC_SUCCESS);
339: }
341: /*@
342: PetscRegressorDestroy - Destroys the regressor context that was created with `PetscRegressorCreate()`.
344: Collective
346: Input Parameter:
347: . regressor - the `PetscRegressor` context
349: Level: beginner
351: .seealso: `PetscRegressorCreate()`, `PetscRegressorSetUp()`, `PetscRegressorReset()`, `PetscRegressor`
352: @*/
353: PetscErrorCode PetscRegressorDestroy(PetscRegressor *regressor)
354: {
355: PetscFunctionBegin;
356: if (!*regressor) PetscFunctionReturn(PETSC_SUCCESS);
358: if (--((PetscObject)*regressor)->refct > 0) {
359: *regressor = NULL;
360: PetscFunctionReturn(PETSC_SUCCESS);
361: }
363: PetscCall(PetscRegressorReset(*regressor));
364: PetscTryTypeMethod(*regressor, destroy);
366: PetscCall(PetscHeaderDestroy(regressor));
367: PetscFunctionReturn(PETSC_SUCCESS);
368: }
370: /*@
371: PetscRegressorSetType - Sets the type for the regressor.
373: Collective
375: Input Parameters:
376: + regressor - the `PetscRegressor` context
377: - type - a known regression method
379: Options Database Key:
380: . -regressor_type type - Sets the type of regressor; use -help for a list of available types
382: Level: intermediate
384: Notes:
385: See "include/petscregressor.h" for available methods (for instance)
386: . `PETSCREGRESSORLINEAR` - Regression model that is linear in its coefficients; supports ordinary least squares as well as regularized variants
388: Normally, it is best to use the `PetscRegressorSetFromOptions()` command and then
389: set the `PetscRegressor` type from the options database rather than by using
390: this routine, as this provides maximum flexibility.
391: The `PetscRegressorSetType()` routine is provided for those situations where it
392: is necessary to set the nonlinear solver independently of the command
393: line or options database.
395: .seealso: `PetscRegressorType`
396: @*/
397: PetscErrorCode PetscRegressorSetType(PetscRegressor regressor, PetscRegressorType type)
398: {
399: PetscErrorCode (*r)(PetscRegressor);
400: PetscBool match;
402: PetscFunctionBegin;
404: PetscAssertPointer(type, 2);
406: PetscCall(PetscObjectTypeCompare((PetscObject)regressor, type, &match));
407: if (match) PetscFunctionReturn(PETSC_SUCCESS);
409: PetscCall(PetscFunctionListFind(PetscRegressorList, type, &r));
410: PetscCheck(r, PetscObjectComm((PetscObject)regressor), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested PetscRegressor type %s", type);
412: /* Destroy the existing solver information */
413: PetscTryTypeMethod(regressor, destroy);
414: PetscCall(TaoDestroy(®ressor->tao));
415: regressor->ops->setup = NULL;
416: regressor->ops->setfromoptions = NULL;
417: regressor->ops->settraining = NULL;
418: regressor->ops->fit = NULL;
419: regressor->ops->predict = NULL;
420: regressor->ops->destroy = NULL;
421: regressor->ops->reset = NULL;
422: regressor->ops->view = NULL;
424: /* Call the PetscRegressorCreate_XXX routine for this particular regressor */
425: regressor->setupcalled = PETSC_FALSE;
426: PetscCall((*r)(regressor));
427: PetscCall(PetscObjectChangeTypeName((PetscObject)regressor, type));
428: PetscFunctionReturn(PETSC_SUCCESS);
429: }
431: /*@
432: PetscRegressorGetType - Gets the current `PetscRegressorType` being used in the `PetscRegressor` object
434: Not Collective
436: Input Parameter:
437: . regressor - the `PetscRegressor` solver context
439: Output Parameter:
440: . type - the `PetscRegressorType`
442: Level: intermediate
444: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorType`, `PetscRegressorSetType()`
445: @*/
446: PetscErrorCode PetscRegressorGetType(PetscRegressor regressor, PetscRegressorType *type)
447: {
448: PetscFunctionBegin;
450: PetscAssertPointer(type, 2);
451: *type = ((PetscObject)regressor)->type_name;
452: PetscFunctionReturn(PETSC_SUCCESS);
453: }
455: /*@
456: PetscRegressorSetRegularizerWeight - Sets the weight to be used for the regularizer for a `PetscRegressor` context
458: Logically Collective
460: Input Parameters:
461: + regressor - the `PetscRegressor` context
462: - weight - the regularizer weight
464: Options Database Key:
465: . regressor_regularizer_weight weight - sets the regularizer's weight
467: Level: beginner
469: .seealso: `PetscRegressorSetType`
470: @*/
471: PetscErrorCode PetscRegressorSetRegularizerWeight(PetscRegressor regressor, PetscReal weight)
472: {
473: PetscFunctionBegin;
476: regressor->regularizer_weight = weight;
477: PetscFunctionReturn(PETSC_SUCCESS);
478: }
480: /*@
481: PetscRegressorGetTao - Returns the `Tao` context for a `PetscRegressor` object.
483: Not Collective, but if the `PetscRegressor` is parallel, then the `Tao` object is parallel
485: Input Parameter:
486: . regressor - the regressor context
488: Output Parameter:
489: . tao - the `Tao` context
491: Level: beginner
493: Notes:
494: The `Tao` object will be created if it does not yet exist.
496: The user can directly manipulate the `Tao` context to set various
497: options, etc. Likewise, the user can then extract and manipulate the
498: child contexts such as `KSP` or `TaoLineSearch`as well.
500: Depending on the type of the regressor and the options that are set, the regressor may use not use a `Tao` object.
502: .seealso: `PetscRegressorLinearGetKSP()`
503: @*/
504: PetscErrorCode PetscRegressorGetTao(PetscRegressor regressor, Tao *tao)
505: {
506: PetscFunctionBegin;
508: PetscAssertPointer(tao, 2);
509: // Analogous to how SNESGetKSP() operates, this routine should create the Tao if it doesn't exist.
510: if (!regressor->tao) {
511: PetscCall(TaoCreate(PetscObjectComm((PetscObject)regressor), ®ressor->tao));
512: PetscCall(PetscObjectIncrementTabLevel((PetscObject)regressor->tao, (PetscObject)regressor, 1));
513: PetscCall(PetscObjectSetOptions((PetscObject)regressor->tao, ((PetscObject)regressor)->options));
514: }
515: *tao = regressor->tao;
516: PetscFunctionReturn(PETSC_SUCCESS);
517: }
519: /*@
520: PetscRegressorSetOptionsPrefix - Sets the prefix used for searching for all
521: PetscRegressor options in the database.
523: Logically Collective
525: Input Parameters:
526: + regressor - the `PetscRegressor` context
527: - p - the prefix string to prepend to all PetscRegressor option requests
529: Level: advanced
531: Notes:
532: A hyphen (-) must NOT be given at the beginning of the prefix name.
533: The first character of all runtime options is AUTOMATICALLY the hyphen.
535: For example, to distinguish between the runtime options for two
536: different PetscRegressor solvers, one could call
537: .vb
538: PetscRegressorSetOptionsPrefix(regressor1,"sys1_")
539: PetscRegressorSetOptionsPrefix(regressor2,"sys2_")
540: .ve
542: This would enable use of different options for each system, such as
543: .vb
544: -sys1_regressor_method linear -sys1_regressor_regularizer_weight 1.2
545: -sys2_regressor_method linear -sys2_regressor_regularizer_weight 1.1
546: .ve
548: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorSetFromOptions()`, `PetscRegressorAppendOptionsPrefix()`, `PetscRegressorGetOptionsPrefix()`
549: @*/
550: PetscErrorCode PetscRegressorSetOptionsPrefix(PetscRegressor regressor, const char p[])
551: {
552: PetscFunctionBegin;
554: PetscCall(PetscObjectSetOptionsPrefix((PetscObject)regressor, p));
555: PetscFunctionReturn(PETSC_SUCCESS);
556: }
558: /*@
559: PetscRegressorAppendOptionsPrefix - Appends to the prefix used for searching for all PetscRegressor options in the database.
561: Logically Collective
563: Input Parameters:
564: + regressor - the `PetscRegressor` solver context
565: - p - the prefix string to prepend to all `PetscRegressor` option requests
567: Level: advanced
569: Note:
570: A hyphen (-) must NOT be given at the beginning of the prefix name.
571: The first character of all runtime options is automatically the hyphen.
573: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorSetFromOptions()`, `PetscRegressorSetOptionsPrefix()`, `PetscRegressorGetOptionsPrefix()`
574: @*/
575: PetscErrorCode PetscRegressorAppendOptionsPrefix(PetscRegressor regressor, const char p[])
576: {
577: PetscFunctionBegin;
579: PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)regressor, p));
580: PetscFunctionReturn(PETSC_SUCCESS);
581: }
583: /*@
584: PetscRegressorGetOptionsPrefix - Gets the prefix used for searching for all
585: PetscRegressor options in the database
587: Not Collective
589: Input Parameter:
590: . regressor - the `PetscRegressor` context
592: Output Parameter:
593: . p - pointer to the prefix string used is returned
595: Fortran Notes:
596: Pass in a string 'prefix' of sufficient length to hold the prefix.
598: Level: advanced
600: .seealso: [](ch_regressor), `PetscRegressor`, `PetscRegressorSetFromOptions()`, `PetscRegressorSetOptionsPrefix()`, `PetscRegressorAppendOptionsPrefix()`
601: @*/
602: PetscErrorCode PetscRegressorGetOptionsPrefix(PetscRegressor regressor, const char *p[])
603: {
604: PetscFunctionBegin;
606: PetscCall(PetscObjectGetOptionsPrefix((PetscObject)regressor, p));
607: PetscFunctionReturn(PETSC_SUCCESS);
608: }