134b254c5SRichard Tran Mills #include <../src/ml/regressor/impls/linear/linearimpl.h> /*I "petscregressor.h" I*/ 234b254c5SRichard Tran Mills 334b254c5SRichard Tran Mills const char *const PetscRegressorLinearTypes[] = {"ols", "lasso", "ridge", "RegressorLinearType", "REGRESSOR_LINEAR_", NULL}; 434b254c5SRichard Tran Mills 534b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorLinearSetFitIntercept_Linear(PetscRegressor regressor, PetscBool flg) 634b254c5SRichard Tran Mills { 734b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 834b254c5SRichard Tran Mills 934b254c5SRichard Tran Mills PetscFunctionBegin; 1034b254c5SRichard Tran Mills linear->fit_intercept = flg; 1134b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 1234b254c5SRichard Tran Mills } 1334b254c5SRichard Tran Mills 1434b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorLinearSetType_Linear(PetscRegressor regressor, PetscRegressorLinearType type) 1534b254c5SRichard Tran Mills { 1634b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 1734b254c5SRichard Tran Mills 1834b254c5SRichard Tran Mills PetscFunctionBegin; 1934b254c5SRichard Tran Mills linear->type = type; 2034b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 2134b254c5SRichard Tran Mills } 2234b254c5SRichard Tran Mills 2334b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorLinearGetType_Linear(PetscRegressor regressor, PetscRegressorLinearType *type) 2434b254c5SRichard Tran Mills { 2534b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 2634b254c5SRichard Tran Mills 2734b254c5SRichard Tran Mills PetscFunctionBegin; 2834b254c5SRichard Tran Mills *type = linear->type; 2934b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 3034b254c5SRichard Tran Mills } 3134b254c5SRichard Tran Mills 3234b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorLinearGetIntercept_Linear(PetscRegressor regressor, PetscScalar *intercept) 3334b254c5SRichard Tran Mills { 3434b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 3534b254c5SRichard Tran Mills 3634b254c5SRichard Tran Mills PetscFunctionBegin; 3734b254c5SRichard Tran Mills *intercept = linear->intercept; 3834b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 3934b254c5SRichard Tran Mills } 4034b254c5SRichard Tran Mills 4134b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorLinearGetCoefficients_Linear(PetscRegressor regressor, Vec *coefficients) 4234b254c5SRichard Tran Mills { 4334b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 4434b254c5SRichard Tran Mills 4534b254c5SRichard Tran Mills PetscFunctionBegin; 4634b254c5SRichard Tran Mills *coefficients = linear->coefficients; 4734b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 4834b254c5SRichard Tran Mills } 4934b254c5SRichard Tran Mills 5034b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorLinearGetKSP_Linear(PetscRegressor regressor, KSP *ksp) 5134b254c5SRichard Tran Mills { 5234b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 5334b254c5SRichard Tran Mills 5434b254c5SRichard Tran Mills PetscFunctionBegin; 5534b254c5SRichard Tran Mills if (!linear->ksp) { 5634b254c5SRichard Tran Mills PetscCall(KSPCreate(PetscObjectComm((PetscObject)regressor), &linear->ksp)); 5734b254c5SRichard Tran Mills PetscCall(PetscObjectIncrementTabLevel((PetscObject)linear->ksp, (PetscObject)regressor, 1)); 5834b254c5SRichard Tran Mills PetscCall(PetscObjectSetOptions((PetscObject)linear->ksp, ((PetscObject)regressor)->options)); 5934b254c5SRichard Tran Mills } 6034b254c5SRichard Tran Mills *ksp = linear->ksp; 6134b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 6234b254c5SRichard Tran Mills } 6334b254c5SRichard Tran Mills 6434b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorLinearSetUseKSP_Linear(PetscRegressor regressor, PetscBool flg) 6534b254c5SRichard Tran Mills { 6634b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 6734b254c5SRichard Tran Mills 6834b254c5SRichard Tran Mills PetscFunctionBegin; 6934b254c5SRichard Tran Mills linear->use_ksp = flg; 7034b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 7134b254c5SRichard Tran Mills } 7234b254c5SRichard Tran Mills 7334b254c5SRichard Tran Mills static PetscErrorCode EvaluateResidual(Tao tao, Vec x, Vec f, void *ptr) 7434b254c5SRichard Tran Mills { 7534b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)ptr; 7634b254c5SRichard Tran Mills 7734b254c5SRichard Tran Mills PetscFunctionBegin; 7834b254c5SRichard Tran Mills /* Evaluate f = A * x - b */ 7934b254c5SRichard Tran Mills PetscCall(MatMult(linear->X, x, f)); 8034b254c5SRichard Tran Mills PetscCall(VecAXPY(f, -1.0, linear->rhs)); 8134b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 8234b254c5SRichard Tran Mills } 8334b254c5SRichard Tran Mills 8434b254c5SRichard Tran Mills static PetscErrorCode EvaluateJacobian(Tao tao, Vec x, Mat J, Mat Jpre, void *ptr) 8534b254c5SRichard Tran Mills { 86540f39e1SHansol Suh /* The TAOBRGN API expects us to pass an EvaluateJacobian() routine to it, but in this case it is a dummy function. 87540f39e1SHansol Suh Denoting our data matrix as X, for linear least squares J[m][n] = df[m]/dx[n] = X[m][n]. */ 8834b254c5SRichard Tran Mills PetscFunctionBegin; 8934b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 9034b254c5SRichard Tran Mills } 9134b254c5SRichard Tran Mills 9234b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorSetUp_Linear(PetscRegressor regressor) 9334b254c5SRichard Tran Mills { 9434b254c5SRichard Tran Mills PetscInt M, N; 9534b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 9634b254c5SRichard Tran Mills KSP ksp; 9734b254c5SRichard Tran Mills Tao tao; 9834b254c5SRichard Tran Mills 9934b254c5SRichard Tran Mills PetscFunctionBegin; 10034b254c5SRichard Tran Mills PetscCall(MatGetSize(regressor->training, &M, &N)); 10134b254c5SRichard Tran Mills 10234b254c5SRichard Tran Mills if (linear->fit_intercept) { 10334b254c5SRichard Tran Mills /* If we are fitting the intercept, we need to make A a composite matrix using MATCENTERING to preserve sparsity. 10434b254c5SRichard Tran Mills * Though there might be some cases we don't want to do this for, depending on what kind of matrix is passed in. (Probably bad idea for dense?) 10534b254c5SRichard Tran Mills * We will also need to ensure that the right-hand side passed to the KSP is also mean-centered, since we 10634b254c5SRichard Tran Mills * intend to compute the intercept separately from regression coefficients (that is, we will not be adding a 10734b254c5SRichard Tran Mills * column of all 1s to our design matrix). */ 10834b254c5SRichard Tran Mills PetscCall(MatCreateCentering(PetscObjectComm((PetscObject)regressor), PETSC_DECIDE, M, &linear->C)); 10934b254c5SRichard Tran Mills PetscCall(MatCreate(PetscObjectComm((PetscObject)regressor), &linear->X)); 11034b254c5SRichard Tran Mills PetscCall(MatSetSizes(linear->X, PETSC_DECIDE, PETSC_DECIDE, M, N)); 11134b254c5SRichard Tran Mills PetscCall(MatSetType(linear->X, MATCOMPOSITE)); 11234b254c5SRichard Tran Mills PetscCall(MatCompositeSetType(linear->X, MAT_COMPOSITE_MULTIPLICATIVE)); 11334b254c5SRichard Tran Mills PetscCall(MatCompositeAddMat(linear->X, regressor->training)); 11434b254c5SRichard Tran Mills PetscCall(MatCompositeAddMat(linear->X, linear->C)); 11534b254c5SRichard Tran Mills PetscCall(VecDuplicate(regressor->target, &linear->rhs)); 11634b254c5SRichard Tran Mills PetscCall(MatMult(linear->C, regressor->target, linear->rhs)); 11734b254c5SRichard Tran Mills } else { 11834b254c5SRichard Tran Mills // When not fitting intercept, we assume that the input data are already centered. 11934b254c5SRichard Tran Mills linear->X = regressor->training; 12034b254c5SRichard Tran Mills linear->rhs = regressor->target; 12134b254c5SRichard Tran Mills 12234b254c5SRichard Tran Mills PetscCall(PetscObjectReference((PetscObject)linear->X)); 12334b254c5SRichard Tran Mills PetscCall(PetscObjectReference((PetscObject)linear->rhs)); 12434b254c5SRichard Tran Mills } 12534b254c5SRichard Tran Mills 12634b254c5SRichard Tran Mills if (linear->coefficients) PetscCall(VecDestroy(&linear->coefficients)); 12734b254c5SRichard Tran Mills 12834b254c5SRichard Tran Mills if (linear->use_ksp) { 12934b254c5SRichard Tran Mills PetscCheck(linear->type == REGRESSOR_LINEAR_OLS, PetscObjectComm((PetscObject)regressor), PETSC_ERR_ARG_WRONGSTATE, "KSP can be used to fit a linear regressor only when its type is OLS"); 13034b254c5SRichard Tran Mills 13134b254c5SRichard Tran Mills if (!linear->ksp) PetscCall(PetscRegressorLinearGetKSP(regressor, &linear->ksp)); 13234b254c5SRichard Tran Mills ksp = linear->ksp; 13334b254c5SRichard Tran Mills 13434b254c5SRichard Tran Mills PetscCall(MatCreateVecs(linear->X, &linear->coefficients, NULL)); 13534b254c5SRichard Tran Mills /* Set up the KSP to solve the least squares problem (without solving for intercept, as this is done separately) using KSPLSQR. */ 13634b254c5SRichard Tran Mills PetscCall(MatCreateNormal(linear->X, &linear->XtX)); 13734b254c5SRichard Tran Mills PetscCall(KSPSetType(ksp, KSPLSQR)); 13834b254c5SRichard Tran Mills PetscCall(KSPSetOperators(ksp, linear->X, linear->XtX)); 13934b254c5SRichard Tran Mills PetscCall(KSPSetOptionsPrefix(ksp, ((PetscObject)regressor)->prefix)); 14034b254c5SRichard Tran Mills PetscCall(KSPAppendOptionsPrefix(ksp, "regressor_linear_")); 14134b254c5SRichard Tran Mills PetscCall(KSPSetFromOptions(ksp)); 14234b254c5SRichard Tran Mills } else { 14334b254c5SRichard Tran Mills /* Note: Currently implementation creates TAO inside of implementations. 14434b254c5SRichard Tran Mills * Thus, all the prefix jobs are done inside implementations, not in interface */ 14534b254c5SRichard Tran Mills const char *prefix; 14634b254c5SRichard Tran Mills 14734b254c5SRichard Tran Mills if (!regressor->tao) PetscCall(PetscRegressorGetTao(regressor, &tao)); 14834b254c5SRichard Tran Mills 14934b254c5SRichard Tran Mills PetscCall(MatCreateVecs(linear->X, &linear->coefficients, &linear->residual)); 15034b254c5SRichard Tran Mills /* Set up the TAO object to solve the (regularized) least squares problem (without solving for intercept, which is done separately) using TAOBRGN. */ 15134b254c5SRichard Tran Mills PetscCall(TaoSetType(tao, TAOBRGN)); 15234b254c5SRichard Tran Mills PetscCall(TaoSetSolution(tao, linear->coefficients)); 15334b254c5SRichard Tran Mills PetscCall(TaoSetResidualRoutine(tao, linear->residual, EvaluateResidual, linear)); 15434b254c5SRichard Tran Mills PetscCall(TaoSetJacobianResidualRoutine(tao, linear->X, linear->X, EvaluateJacobian, linear)); 15534b254c5SRichard Tran Mills if (!linear->use_ksp) PetscCall(TaoBRGNSetRegularizerWeight(tao, regressor->regularizer_weight)); 15634b254c5SRichard Tran Mills // Set the regularization type and weight for the BRGN as linear->type dictates: 15734b254c5SRichard Tran Mills // TODO BRGN needs to be BRGNSetRegularizationType 15834b254c5SRichard Tran Mills // PetscOptionsSetValue no longer works due to functioning prefix system 15934b254c5SRichard Tran Mills PetscCall(PetscRegressorGetOptionsPrefix(regressor, &prefix)); 16034b254c5SRichard Tran Mills PetscCall(TaoSetOptionsPrefix(regressor->tao, prefix)); 16134b254c5SRichard Tran Mills PetscCall(TaoAppendOptionsPrefix(tao, "regressor_linear_")); 16234b254c5SRichard Tran Mills switch (linear->type) { 16334b254c5SRichard Tran Mills case REGRESSOR_LINEAR_OLS: 16434b254c5SRichard Tran Mills regressor->regularizer_weight = 0.0; // OLS, by definition, uses a regularizer weight of 0 16534b254c5SRichard Tran Mills break; 16634b254c5SRichard Tran Mills case REGRESSOR_LINEAR_LASSO: 167c0b7dd19SHansol Suh PetscCall(TaoBRGNSetRegularizationType(regressor->tao, TAOBRGN_REGULARIZATION_L1DICT)); 16834b254c5SRichard Tran Mills break; 16934b254c5SRichard Tran Mills case REGRESSOR_LINEAR_RIDGE: 170c0b7dd19SHansol Suh PetscCall(TaoBRGNSetRegularizationType(regressor->tao, TAOBRGN_REGULARIZATION_L2PURE)); 17134b254c5SRichard Tran Mills break; 17234b254c5SRichard Tran Mills default: 17334b254c5SRichard Tran Mills break; 17434b254c5SRichard Tran Mills } 17534b254c5SRichard Tran Mills PetscCall(TaoSetFromOptions(tao)); 17634b254c5SRichard Tran Mills } 17734b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 17834b254c5SRichard Tran Mills } 17934b254c5SRichard Tran Mills 18034b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorReset_Linear(PetscRegressor regressor) 18134b254c5SRichard Tran Mills { 18234b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 18334b254c5SRichard Tran Mills 18434b254c5SRichard Tran Mills PetscFunctionBegin; 18534b254c5SRichard Tran Mills /* Destroy the PETSc objects associated with the linear regressor implementation. */ 18634b254c5SRichard Tran Mills linear->ksp_its = 0; 18734b254c5SRichard Tran Mills linear->ksp_tot_its = 0; 18834b254c5SRichard Tran Mills 18934b254c5SRichard Tran Mills PetscCall(MatDestroy(&linear->X)); 19034b254c5SRichard Tran Mills PetscCall(MatDestroy(&linear->XtX)); 19134b254c5SRichard Tran Mills PetscCall(MatDestroy(&linear->C)); 19234b254c5SRichard Tran Mills PetscCall(KSPDestroy(&linear->ksp)); 19334b254c5SRichard Tran Mills PetscCall(VecDestroy(&linear->coefficients)); 19434b254c5SRichard Tran Mills PetscCall(VecDestroy(&linear->rhs)); 19534b254c5SRichard Tran Mills PetscCall(VecDestroy(&linear->residual)); 19634b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 19734b254c5SRichard Tran Mills } 19834b254c5SRichard Tran Mills 19934b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorDestroy_Linear(PetscRegressor regressor) 20034b254c5SRichard Tran Mills { 20134b254c5SRichard Tran Mills PetscFunctionBegin; 20234b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearSetFitIntercept_C", NULL)); 20334b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearSetUseKSP_C", NULL)); 20434b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetKSP_C", NULL)); 20534b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetCoefficients_C", NULL)); 20634b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetIntercept_C", NULL)); 20734b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearSetType_C", NULL)); 20834b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetType_C", NULL)); 20934b254c5SRichard Tran Mills PetscCall(PetscRegressorReset_Linear(regressor)); 21034b254c5SRichard Tran Mills PetscCall(PetscFree(regressor->data)); 21134b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 21234b254c5SRichard Tran Mills } 21334b254c5SRichard Tran Mills 21434b254c5SRichard Tran Mills /*@ 21534b254c5SRichard Tran Mills PetscRegressorLinearSetFitIntercept - Set a flag to indicate that the intercept (also known as the "bias" or "offset") should 21634b254c5SRichard Tran Mills be calculated; data are assumed to be mean-centered if false. 21734b254c5SRichard Tran Mills 21834b254c5SRichard Tran Mills Logically Collective 21934b254c5SRichard Tran Mills 22034b254c5SRichard Tran Mills Input Parameters: 22134b254c5SRichard Tran Mills + regressor - the `PetscRegressor` context 22234b254c5SRichard Tran Mills - flg - `PETSC_TRUE` to calculate the intercept, `PETSC_FALSE` to assume mean-centered data (default is `PETSC_TRUE`) 22334b254c5SRichard Tran Mills 22434b254c5SRichard Tran Mills Level: intermediate 22534b254c5SRichard Tran Mills 22634b254c5SRichard Tran Mills Options Database Key: 22734b254c5SRichard Tran Mills . regressor_linear_fit_intercept <true,false> - fit the intercept 22834b254c5SRichard Tran Mills 22934b254c5SRichard Tran Mills Note: 23034b254c5SRichard Tran Mills If the user indicates that the intercept should not be calculated, the intercept will be set to zero. 23134b254c5SRichard Tran Mills 23234b254c5SRichard Tran Mills .seealso: `PetscRegressor`, `PetscRegressorFit()` 23334b254c5SRichard Tran Mills @*/ 23434b254c5SRichard Tran Mills PetscErrorCode PetscRegressorLinearSetFitIntercept(PetscRegressor regressor, PetscBool flg) 23534b254c5SRichard Tran Mills { 23634b254c5SRichard Tran Mills PetscFunctionBegin; 23734b254c5SRichard Tran Mills /* TODO: Add companion PetscRegressorLinearGetFitIntercept(), and put it in the .seealso: */ 23834b254c5SRichard Tran Mills PetscValidHeaderSpecific(regressor, PETSCREGRESSOR_CLASSID, 1); 23934b254c5SRichard Tran Mills PetscValidLogicalCollectiveBool(regressor, flg, 2); 24034b254c5SRichard Tran Mills PetscTryMethod(regressor, "PetscRegressorLinearSetFitIntercept_C", (PetscRegressor, PetscBool), (regressor, flg)); 24134b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 24234b254c5SRichard Tran Mills } 24334b254c5SRichard Tran Mills 24434b254c5SRichard Tran Mills /*@ 24534b254c5SRichard Tran Mills PetscRegressorLinearSetUseKSP - Set a flag to indicate that a `KSP` object, instead of a `Tao` one, should be used 246*789736e1SBarry Smith to fit the linear regressor 24734b254c5SRichard Tran Mills 24834b254c5SRichard Tran Mills Logically Collective 24934b254c5SRichard Tran Mills 25034b254c5SRichard Tran Mills Input Parameters: 25134b254c5SRichard Tran Mills + regressor - the `PetscRegressor` context 25234b254c5SRichard Tran Mills - flg - `PETSC_TRUE` to use a `KSP`, `PETSC_FALSE` to use a `Tao` object (default is false) 25334b254c5SRichard Tran Mills 25434b254c5SRichard Tran Mills Options Database Key: 25534b254c5SRichard Tran Mills . regressor_linear_use_ksp <true,false> - use `KSP` 25634b254c5SRichard Tran Mills 25734b254c5SRichard Tran Mills Level: intermediate 25834b254c5SRichard Tran Mills 259*789736e1SBarry Smith Notes: 260*789736e1SBarry Smith `KSPLSQR` with no preconditioner is used to solve the normal equations by default. 261*789736e1SBarry Smith 262*789736e1SBarry Smith For sequential `MATSEQAIJ` sparse matrices QR factorization a `PCType` of `PCQR` can be used to solve the least-squares system with a `MatSolverType` of 263*789736e1SBarry Smith `MATSOLVERSPQR`, using, for example, 264*789736e1SBarry Smith .vb 265*789736e1SBarry Smith -ksp_type none -pc_type qr -pc_factor_mat_solver_type sp 266*789736e1SBarry Smith .ve 267*789736e1SBarry Smith if centering, `PetscRegressorLinearSetFitIntercept()`, is not used. 268*789736e1SBarry Smith 269*789736e1SBarry Smith Developer Notes: 270*789736e1SBarry Smith It should be possible to use Cholesky (and any other preconditioners) to solve the normal equations. 271*789736e1SBarry Smith 272*789736e1SBarry Smith It should be possible to use QR if centering is used. See ml/regressor/ex1.c and ex2.c 273*789736e1SBarry Smith 274*789736e1SBarry Smith It should be possible to use dense SVD `PCSVD` and dense qr directly on the rectangular matrix to solve the least squares problem. 275*789736e1SBarry Smith 276*789736e1SBarry Smith Adding the above support seems to require a refactorization of how least squares problems are solved with PETSc in `KSPLSQR` 277*789736e1SBarry Smith 278*789736e1SBarry Smith .seealso: `PetscRegressor`, `PetscRegressorLinearGetKSP()`, `KSPLSQR`, `PCQR`, `MATSOLVERSPQR`, `MatSolverType`, `MATSEQDENSE`, `PCSVD` 27934b254c5SRichard Tran Mills @*/ 28034b254c5SRichard Tran Mills PetscErrorCode PetscRegressorLinearSetUseKSP(PetscRegressor regressor, PetscBool flg) 28134b254c5SRichard Tran Mills { 28234b254c5SRichard Tran Mills PetscFunctionBegin; 28334b254c5SRichard Tran Mills /* TODO: Add companion PetscRegressorLinearGetUseKSP(), and put it in the .seealso: */ 28434b254c5SRichard Tran Mills PetscValidHeaderSpecific(regressor, PETSCREGRESSOR_CLASSID, 1); 28534b254c5SRichard Tran Mills PetscValidLogicalCollectiveBool(regressor, flg, 2); 28634b254c5SRichard Tran Mills PetscTryMethod(regressor, "PetscRegressorLinearSetUseKSP_C", (PetscRegressor, PetscBool), (regressor, flg)); 28734b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 28834b254c5SRichard Tran Mills } 28934b254c5SRichard Tran Mills 29034b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorSetFromOptions_Linear(PetscRegressor regressor, PetscOptionItems PetscOptionsObject) 29134b254c5SRichard Tran Mills { 29234b254c5SRichard Tran Mills PetscBool set, flg = PETSC_FALSE; 29334b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 29434b254c5SRichard Tran Mills 29534b254c5SRichard Tran Mills PetscFunctionBegin; 29634b254c5SRichard Tran Mills PetscOptionsHeadBegin(PetscOptionsObject, "PetscRegressor options for linear regressors"); 29734b254c5SRichard Tran Mills PetscCall(PetscOptionsBool("-regressor_linear_fit_intercept", "Calculate intercept for linear model", "PetscRegressorLinearSetFitIntercept", flg, &flg, &set)); 29834b254c5SRichard Tran Mills if (set) PetscCall(PetscRegressorLinearSetFitIntercept(regressor, flg)); 29934b254c5SRichard Tran Mills PetscCall(PetscOptionsBool("-regressor_linear_use_ksp", "Use KSP instead of TAO for linear model fitting problem", "PetscRegressorLinearSetFitIntercept", flg, &flg, &set)); 30034b254c5SRichard Tran Mills if (set) PetscCall(PetscRegressorLinearSetUseKSP(regressor, flg)); 30134b254c5SRichard Tran Mills PetscCall(PetscOptionsEnum("-regressor_linear_type", "Linear regression method", "PetscRegressorLinearTypes", PetscRegressorLinearTypes, (PetscEnum)linear->type, (PetscEnum *)&linear->type, NULL)); 30234b254c5SRichard Tran Mills PetscOptionsHeadEnd(); 30334b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 30434b254c5SRichard Tran Mills } 30534b254c5SRichard Tran Mills 30634b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorView_Linear(PetscRegressor regressor, PetscViewer viewer) 30734b254c5SRichard Tran Mills { 30834b254c5SRichard Tran Mills PetscBool isascii; 30934b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 31034b254c5SRichard Tran Mills 31134b254c5SRichard Tran Mills PetscFunctionBegin; 31234b254c5SRichard Tran Mills PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 31334b254c5SRichard Tran Mills if (isascii) { 31434b254c5SRichard Tran Mills PetscCall(PetscViewerASCIIPushTab(viewer)); 31534b254c5SRichard Tran Mills PetscCall(PetscViewerASCIIPrintf(viewer, "PetscRegressor Linear Type: %s\n", PetscRegressorLinearTypes[linear->type])); 31634b254c5SRichard Tran Mills if (linear->ksp) { 31734b254c5SRichard Tran Mills PetscCall(KSPView(linear->ksp, viewer)); 31834b254c5SRichard Tran Mills PetscCall(PetscViewerASCIIPrintf(viewer, "total KSP iterations: %" PetscInt_FMT "\n", linear->ksp_tot_its)); 31934b254c5SRichard Tran Mills } 32034b254c5SRichard Tran Mills if (linear->fit_intercept) PetscCall(PetscViewerASCIIPrintf(viewer, "Intercept=%g\n", (double)linear->intercept)); 32134b254c5SRichard Tran Mills PetscCall(PetscViewerASCIIPopTab(viewer)); 32234b254c5SRichard Tran Mills } 32334b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 32434b254c5SRichard Tran Mills } 32534b254c5SRichard Tran Mills 32634b254c5SRichard Tran Mills /*@ 32734b254c5SRichard Tran Mills PetscRegressorLinearGetKSP - Returns the `KSP` context for a `PETSCREGRESSORLINEAR` object. 32834b254c5SRichard Tran Mills 32934b254c5SRichard Tran Mills Not Collective, but if the `PetscRegressor` is parallel, then the `KSP` object is parallel 33034b254c5SRichard Tran Mills 33134b254c5SRichard Tran Mills Input Parameter: 33234b254c5SRichard Tran Mills . regressor - the `PetscRegressor` context 33334b254c5SRichard Tran Mills 33434b254c5SRichard Tran Mills Output Parameter: 33534b254c5SRichard Tran Mills . ksp - the `KSP` context 33634b254c5SRichard Tran Mills 33734b254c5SRichard Tran Mills Level: beginner 33834b254c5SRichard Tran Mills 33934b254c5SRichard Tran Mills Note: 34034b254c5SRichard Tran Mills This routine will always return a `KSP`, but, depending on the type of the linear regressor and the options that are set, the regressor may actually use a `Tao` object instead of this `KSP`. 34134b254c5SRichard Tran Mills 34234b254c5SRichard Tran Mills .seealso: `PetscRegressorGetTao()` 34334b254c5SRichard Tran Mills @*/ 34434b254c5SRichard Tran Mills PetscErrorCode PetscRegressorLinearGetKSP(PetscRegressor regressor, KSP *ksp) 34534b254c5SRichard Tran Mills { 34634b254c5SRichard Tran Mills PetscFunctionBegin; 34734b254c5SRichard Tran Mills PetscValidHeaderSpecific(regressor, PETSCREGRESSOR_CLASSID, 1); 34834b254c5SRichard Tran Mills PetscAssertPointer(ksp, 2); 34934b254c5SRichard Tran Mills PetscUseMethod(regressor, "PetscRegressorLinearGetKSP_C", (PetscRegressor, KSP *), (regressor, ksp)); 35034b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 35134b254c5SRichard Tran Mills } 35234b254c5SRichard Tran Mills 35334b254c5SRichard Tran Mills /*@ 35434b254c5SRichard Tran Mills PetscRegressorLinearGetCoefficients - Get a vector of the fitted coefficients from a linear regression model 35534b254c5SRichard Tran Mills 35634b254c5SRichard Tran Mills Not Collective but the vector is parallel 35734b254c5SRichard Tran Mills 35834b254c5SRichard Tran Mills Input Parameter: 35934b254c5SRichard Tran Mills . regressor - the `PetscRegressor` context 36034b254c5SRichard Tran Mills 36134b254c5SRichard Tran Mills Output Parameter: 36234b254c5SRichard Tran Mills . coefficients - the vector of the coefficients 36334b254c5SRichard Tran Mills 36434b254c5SRichard Tran Mills Level: beginner 36534b254c5SRichard Tran Mills 36634b254c5SRichard Tran Mills .seealso: `PetscRegressor`, `PetscRegressorLinearGetIntercept()`, `PETSCREGRESSORLINEAR`, `Vec` 36734b254c5SRichard Tran Mills @*/ 36834b254c5SRichard Tran Mills PETSC_EXTERN PetscErrorCode PetscRegressorLinearGetCoefficients(PetscRegressor regressor, Vec *coefficients) 36934b254c5SRichard Tran Mills { 37034b254c5SRichard Tran Mills PetscFunctionBegin; 37134b254c5SRichard Tran Mills PetscValidHeaderSpecific(regressor, PETSCREGRESSOR_CLASSID, 1); 37234b254c5SRichard Tran Mills PetscAssertPointer(coefficients, 2); 37334b254c5SRichard Tran Mills PetscUseMethod(regressor, "PetscRegressorLinearGetCoefficients_C", (PetscRegressor, Vec *), (regressor, coefficients)); 37434b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 37534b254c5SRichard Tran Mills } 37634b254c5SRichard Tran Mills 37734b254c5SRichard Tran Mills /*@ 37834b254c5SRichard Tran Mills PetscRegressorLinearGetIntercept - Get the intercept from a linear regression model 37934b254c5SRichard Tran Mills 38034b254c5SRichard Tran Mills Not Collective 38134b254c5SRichard Tran Mills 38234b254c5SRichard Tran Mills Input Parameter: 38334b254c5SRichard Tran Mills . regressor - the `PetscRegressor` context 38434b254c5SRichard Tran Mills 38534b254c5SRichard Tran Mills Output Parameter: 38634b254c5SRichard Tran Mills . intercept - the intercept 38734b254c5SRichard Tran Mills 38834b254c5SRichard Tran Mills Level: beginner 38934b254c5SRichard Tran Mills 39034b254c5SRichard Tran Mills .seealso: `PetscRegressor`, `PetscRegressorLinearSetFitIntercept()`, `PetscRegressorLinearGetCoefficients()`, `PETSCREGRESSORLINEAR` 39134b254c5SRichard Tran Mills @*/ 39234b254c5SRichard Tran Mills PETSC_EXTERN PetscErrorCode PetscRegressorLinearGetIntercept(PetscRegressor regressor, PetscScalar *intercept) 39334b254c5SRichard Tran Mills { 39434b254c5SRichard Tran Mills PetscFunctionBegin; 39534b254c5SRichard Tran Mills PetscValidHeaderSpecific(regressor, PETSCREGRESSOR_CLASSID, 1); 39634b254c5SRichard Tran Mills PetscAssertPointer(intercept, 2); 39734b254c5SRichard Tran Mills PetscUseMethod(regressor, "PetscRegressorLinearGetIntercept_C", (PetscRegressor, PetscScalar *), (regressor, intercept)); 39834b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 39934b254c5SRichard Tran Mills } 40034b254c5SRichard Tran Mills 40134b254c5SRichard Tran Mills /*@C 40234b254c5SRichard Tran Mills PetscRegressorLinearSetType - Sets the type of linear regression to be performed 40334b254c5SRichard Tran Mills 40434b254c5SRichard Tran Mills Logically Collective 40534b254c5SRichard Tran Mills 40634b254c5SRichard Tran Mills Input Parameters: 40734b254c5SRichard Tran Mills + regressor - the `PetscRegressor` context (should be of type `PETSCREGRESSORLINEAR`) 40834b254c5SRichard Tran Mills - type - a known linear regression method 40934b254c5SRichard Tran Mills 41034b254c5SRichard Tran Mills Options Database Key: 41134b254c5SRichard Tran Mills . -regressor_linear_type - Sets the linear regression method; use -help for a list of available methods 41234b254c5SRichard Tran Mills (for instance "-regressor_linear_type ols" or "-regressor_linear_type lasso") 41334b254c5SRichard Tran Mills 41434b254c5SRichard Tran Mills Level: intermediate 41534b254c5SRichard Tran Mills 416*789736e1SBarry Smith .seealso: `PetscRegressorLinearGetType()`, `PetscRegressorLinearType`, `PetscRegressorSetType()`, `REGRESSOR_LINEAR_OLS`, 417*789736e1SBarry Smith `REGRESSOR_LINEAR_LASSO`, `REGRESSOR_LINEAR_RIDGE` 41834b254c5SRichard Tran Mills @*/ 41934b254c5SRichard Tran Mills PetscErrorCode PetscRegressorLinearSetType(PetscRegressor regressor, PetscRegressorLinearType type) 42034b254c5SRichard Tran Mills { 42134b254c5SRichard Tran Mills PetscFunctionBegin; 42234b254c5SRichard Tran Mills PetscValidHeaderSpecific(regressor, PETSCREGRESSOR_CLASSID, 1); 42334b254c5SRichard Tran Mills PetscValidLogicalCollectiveEnum(regressor, type, 2); 42434b254c5SRichard Tran Mills PetscTryMethod(regressor, "PetscRegressorLinearSetType_C", (PetscRegressor, PetscRegressorLinearType), (regressor, type)); 42534b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 42634b254c5SRichard Tran Mills } 42734b254c5SRichard Tran Mills 42834b254c5SRichard Tran Mills /*@ 42934b254c5SRichard Tran Mills PetscRegressorLinearGetType - Return the type for the `PETSCREGRESSORLINEAR` solver 43034b254c5SRichard Tran Mills 43134b254c5SRichard Tran Mills Input Parameter: 43234b254c5SRichard Tran Mills . regressor - the `PetscRegressor` solver context 43334b254c5SRichard Tran Mills 43434b254c5SRichard Tran Mills Output Parameter: 43534b254c5SRichard Tran Mills . type - `PETSCREGRESSORLINEAR` type 43634b254c5SRichard Tran Mills 43734b254c5SRichard Tran Mills Level: advanced 43834b254c5SRichard Tran Mills 43934b254c5SRichard Tran Mills .seealso: `PetscRegressor`, `PETSCREGRESSORLINEAR`, `PetscRegressorLinearSetType()`, `PetscRegressorLinearType` 44034b254c5SRichard Tran Mills @*/ 44134b254c5SRichard Tran Mills PetscErrorCode PetscRegressorLinearGetType(PetscRegressor regressor, PetscRegressorLinearType *type) 44234b254c5SRichard Tran Mills { 44334b254c5SRichard Tran Mills PetscFunctionBegin; 44434b254c5SRichard Tran Mills PetscValidHeaderSpecific(regressor, PETSCREGRESSOR_CLASSID, 1); 44534b254c5SRichard Tran Mills PetscAssertPointer(type, 2); 44634b254c5SRichard Tran Mills PetscUseMethod(regressor, "PetscRegressorLinearGetType_C", (PetscRegressor, PetscRegressorLinearType *), (regressor, type)); 44734b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 44834b254c5SRichard Tran Mills } 44934b254c5SRichard Tran Mills 45034b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorFit_Linear(PetscRegressor regressor) 45134b254c5SRichard Tran Mills { 45234b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 45334b254c5SRichard Tran Mills KSP ksp; 45434b254c5SRichard Tran Mills PetscScalar target_mean, *column_means_global, *column_means_local, column_means_dot_coefficients; 45534b254c5SRichard Tran Mills Vec column_means; 45634b254c5SRichard Tran Mills PetscInt m, N, istart, i, kspits; 45734b254c5SRichard Tran Mills 45834b254c5SRichard Tran Mills PetscFunctionBegin; 45934b254c5SRichard Tran Mills if (linear->use_ksp) PetscCall(PetscRegressorLinearGetKSP(regressor, &linear->ksp)); 46034b254c5SRichard Tran Mills ksp = linear->ksp; 46134b254c5SRichard Tran Mills 46234b254c5SRichard Tran Mills /* Solve the least-squares problem (previously set up in PetscRegressorSetUp_Linear()) without finding the intercept. */ 46334b254c5SRichard Tran Mills if (linear->use_ksp) { 46434b254c5SRichard Tran Mills PetscCall(KSPSolve(ksp, linear->rhs, linear->coefficients)); 46534b254c5SRichard Tran Mills PetscCall(KSPGetIterationNumber(ksp, &kspits)); 46634b254c5SRichard Tran Mills linear->ksp_its += kspits; 46734b254c5SRichard Tran Mills linear->ksp_tot_its += kspits; 46834b254c5SRichard Tran Mills } else { 46934b254c5SRichard Tran Mills PetscCall(TaoSolve(regressor->tao)); 47034b254c5SRichard Tran Mills } 47134b254c5SRichard Tran Mills 47234b254c5SRichard Tran Mills /* Calculate the intercept. */ 47334b254c5SRichard Tran Mills if (linear->fit_intercept) { 47434b254c5SRichard Tran Mills PetscCall(MatGetSize(regressor->training, NULL, &N)); 47534b254c5SRichard Tran Mills PetscCall(PetscMalloc1(N, &column_means_global)); 47634b254c5SRichard Tran Mills PetscCall(VecMean(regressor->target, &target_mean)); 47734b254c5SRichard Tran Mills /* We need the means of all columns of regressor->training, placed into a Vec compatible with linear->coefficients. 47834b254c5SRichard Tran Mills * Note the potential scalability issue: MatGetColumnMeans() computes means of ALL colummns. */ 47934b254c5SRichard Tran Mills PetscCall(MatGetColumnMeans(regressor->training, column_means_global)); 48034b254c5SRichard Tran Mills /* TODO: Calculation of the Vec and matrix column means should probably go into the SetUp phase, and also be placed 48134b254c5SRichard Tran Mills * into a routine that is callable from outside of PetscRegressorFit_Linear(), because we'll want to do the same 48234b254c5SRichard Tran Mills * thing for other models, such as ridge and LASSO regression, and should avoid code duplication. 48334b254c5SRichard Tran Mills * What we are calling 'target_mean' and 'column_means' should be stashed in the base linear regressor struct, 48434b254c5SRichard Tran Mills * and perhaps renamed to make it clear they are offsets that should be applied (though the current naming 48534b254c5SRichard Tran Mills * makes sense since it makes it clear where these come from.) */ 48634b254c5SRichard Tran Mills PetscCall(VecDuplicate(linear->coefficients, &column_means)); 48734b254c5SRichard Tran Mills PetscCall(VecGetLocalSize(column_means, &m)); 48834b254c5SRichard Tran Mills PetscCall(VecGetOwnershipRange(column_means, &istart, NULL)); 48934b254c5SRichard Tran Mills PetscCall(VecGetArrayWrite(column_means, &column_means_local)); 49034b254c5SRichard Tran Mills for (i = 0; i < m; i++) column_means_local[i] = column_means_global[istart + i]; 49134b254c5SRichard Tran Mills PetscCall(VecRestoreArrayWrite(column_means, &column_means_local)); 49234b254c5SRichard Tran Mills PetscCall(VecDot(column_means, linear->coefficients, &column_means_dot_coefficients)); 49334b254c5SRichard Tran Mills PetscCall(VecDestroy(&column_means)); 49434b254c5SRichard Tran Mills PetscCall(PetscFree(column_means_global)); 49534b254c5SRichard Tran Mills linear->intercept = target_mean - column_means_dot_coefficients; 49634b254c5SRichard Tran Mills } else { 49734b254c5SRichard Tran Mills linear->intercept = 0.0; 49834b254c5SRichard Tran Mills } 49934b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 50034b254c5SRichard Tran Mills } 50134b254c5SRichard Tran Mills 50234b254c5SRichard Tran Mills static PetscErrorCode PetscRegressorPredict_Linear(PetscRegressor regressor, Mat X, Vec y) 50334b254c5SRichard Tran Mills { 50434b254c5SRichard Tran Mills PetscRegressor_Linear *linear = (PetscRegressor_Linear *)regressor->data; 50534b254c5SRichard Tran Mills 50634b254c5SRichard Tran Mills PetscFunctionBegin; 50734b254c5SRichard Tran Mills PetscCall(MatMult(X, linear->coefficients, y)); 50834b254c5SRichard Tran Mills PetscCall(VecShift(y, linear->intercept)); 50934b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 51034b254c5SRichard Tran Mills } 51134b254c5SRichard Tran Mills 51234b254c5SRichard Tran Mills /*MC 51334b254c5SRichard Tran Mills PETSCREGRESSORLINEAR - Linear regression model (ordinary least squares or regularized variants) 51434b254c5SRichard Tran Mills 51534b254c5SRichard Tran Mills Options Database: 51634b254c5SRichard Tran Mills + -regressor_linear_fit_intercept - Calculate the intercept for the linear model 51734b254c5SRichard Tran Mills - -regressor_linear_use_ksp - Use `KSP` instead of `Tao` for linear model fitting (non-regularized variants only) 51834b254c5SRichard Tran Mills 51934b254c5SRichard Tran Mills Level: beginner 52034b254c5SRichard Tran Mills 52134b254c5SRichard Tran Mills Note: 52234b254c5SRichard Tran Mills This is the default regressor in `PetscRegressor`. 52334b254c5SRichard Tran Mills 52434b254c5SRichard Tran Mills .seealso: `PetscRegressorCreate()`, `PetscRegressor`, `PetscRegressorSetType()` 52534b254c5SRichard Tran Mills M*/ 52634b254c5SRichard Tran Mills PETSC_EXTERN PetscErrorCode PetscRegressorCreate_Linear(PetscRegressor regressor) 52734b254c5SRichard Tran Mills { 52834b254c5SRichard Tran Mills PetscRegressor_Linear *linear; 52934b254c5SRichard Tran Mills 53034b254c5SRichard Tran Mills PetscFunctionBegin; 53134b254c5SRichard Tran Mills PetscCall(PetscNew(&linear)); 53234b254c5SRichard Tran Mills regressor->data = (void *)linear; 53334b254c5SRichard Tran Mills 53434b254c5SRichard Tran Mills regressor->ops->setup = PetscRegressorSetUp_Linear; 53534b254c5SRichard Tran Mills regressor->ops->reset = PetscRegressorReset_Linear; 53634b254c5SRichard Tran Mills regressor->ops->destroy = PetscRegressorDestroy_Linear; 53734b254c5SRichard Tran Mills regressor->ops->setfromoptions = PetscRegressorSetFromOptions_Linear; 53834b254c5SRichard Tran Mills regressor->ops->view = PetscRegressorView_Linear; 53934b254c5SRichard Tran Mills regressor->ops->fit = PetscRegressorFit_Linear; 54034b254c5SRichard Tran Mills regressor->ops->predict = PetscRegressorPredict_Linear; 54134b254c5SRichard Tran Mills 54234b254c5SRichard Tran Mills linear->intercept = 0.0; 54334b254c5SRichard Tran Mills linear->fit_intercept = PETSC_TRUE; /* Default to calculating the intercept. */ 54434b254c5SRichard Tran Mills linear->use_ksp = PETSC_FALSE; /* Do not default to using KSP for solving the model-fitting problem (use TAO instead). */ 54534b254c5SRichard Tran Mills linear->type = REGRESSOR_LINEAR_OLS; 54634b254c5SRichard Tran Mills /* Above, manually set the default linear regressor type. 54734b254c5SRichard Tran Mills We don't use PetscRegressorLinearSetType() here, because that expects the SetUp event to already have happened. */ 54834b254c5SRichard Tran Mills 54934b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearSetFitIntercept_C", PetscRegressorLinearSetFitIntercept_Linear)); 55034b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearSetUseKSP_C", PetscRegressorLinearSetUseKSP_Linear)); 55134b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetKSP_C", PetscRegressorLinearGetKSP_Linear)); 55234b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetCoefficients_C", PetscRegressorLinearGetCoefficients_Linear)); 55334b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetIntercept_C", PetscRegressorLinearGetIntercept_Linear)); 55434b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearSetType_C", PetscRegressorLinearSetType_Linear)); 55534b254c5SRichard Tran Mills PetscCall(PetscObjectComposeFunction((PetscObject)regressor, "PetscRegressorLinearGetType_C", PetscRegressorLinearGetType_Linear)); 55634b254c5SRichard Tran Mills PetscFunctionReturn(PETSC_SUCCESS); 55734b254c5SRichard Tran Mills } 558