Skip to content

Commit

Permalink
setting up example for direct call of BCS
Browse files Browse the repository at this point in the history
  • Loading branch information
bjdebus committed Feb 3, 2023
1 parent d300ff4 commit 546ffd4
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 1 deletion.
2 changes: 1 addition & 1 deletion PyUQTk/PyPCE/pce_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ def UQTkEvalBCS(pc_model, f_evaluations, samplepts, sigma, eta, regparams, verbo
# Return coefficients and their locations with respect to the basis terms
return c_k, used_mi_np
################################################################################
def UQTkCallBCSDirectNOTTESTEDYET(vdm_np, rhs_np, sigma, eta, regparams_np, verbose=False):
def UQTkCallBCSDirect(vdm_np, rhs_np, sigma, eta, regparams_np, verbose=False):
"""
Calls the C++ BCS routines directly with a VanderMonde Matrix and Right Hand
Side (Rather than relying on a PCE Model to provide the basis)
Expand Down
9 changes: 9 additions & 0 deletions examples/bare_bcs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
project (UQTk)

SET(copy_EX_FILES
bare_bcs.ipynb
readme.md)

INSTALL(FILES ${copy_EX_FILES}
PERMISSIONS OWNER_WRITE OWNER_READ
DESTINATION examples/bare_bcs)
211 changes: 211 additions & 0 deletions examples/bare_bcs/bare_bcs.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "c32c8012-f3bf-4f96-9aff-e8b20eca1ec7",
"metadata": {},
"source": [
"# Surrogate Construction for Genz Functions: BCS"
]
},
{
"cell_type": "markdown",
"id": "6e289260-b35a-4113-90d9-6f0c2eb4bc92",
"metadata": {},
"source": [
"This notebook constructs a PC surrogate for Genz functions and gives the normalized root mean square error between the surrogate and the actual function. Both the Genz function and PCE are defined on [-1,1]."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "f74bf835-9ef7-452b-85cc-7fd3ebbe7dd3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"PyMC is required for some of the MCMC postprocessing codes.\n",
"Will proceed without, but some convergence tests will not be available.\n"
]
}
],
"source": [
"import numpy as np\n",
"import math \n",
"from scipy.stats import qmc\n",
"import pandas as pd\n",
"\n",
"import PyUQTk.pce as uqtkpce\n",
"import PyUQTk.PyPCE.pce_tools as pce_tools\n",
"from PyUQTk.utils.func import *"
]
},
{
"cell_type": "markdown",
"id": "532e0f3a-c607-4877-b64f-4a9cf1c40556",
"metadata": {},
"source": [
"We define our input parameters. BCS is best for undetermined models and/or large basis sets."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "aa0bbccd-c5e7-40ab-a720-9ccf740514e9",
"metadata": {},
"outputs": [],
"source": [
"# PC parameters\n",
"nord = 8 # Order of the final PCE basis\n",
"ndim = 2 # Number of dimensions\n",
"pc_type = \"LU\" # Polynomial type\n",
"pc_alpha = 0.0 # Free parameter > -1 for Gamma-Laguerre and Beta-Jacobi PCs\n",
"pc_beta = 1.0 # Free parameter > -1 for Gamma-Laguerre and Beta-Jacobi PCs\n",
"\n",
"# BCS parameters\n",
"niter = 3 # Number of iterations to run, must be > 0\n",
"eta = 1/np.power(10,[i for i in range(1,16)]) # Threshold for stopping the algorithm\n",
"ntry = 5 # Number of splits for cross-validation of the retained basis terms \n",
"eta_folds = 5 # Number of folds to use for eta cross-validation \n",
"mindex_growth = 'nonconservative' # Method for basis growth; options are \"conservative,\" \"nonconservative,\" or None\n",
"regparams = None # Regularization weights (provide an array or value); if None, they are autopopulated\n",
"sigma = 1e-8 # Inital noise variance; updated in BCS\n",
"trval_frac = None # Fraction of total data to use in each split\n",
"npccut = None # Maximum number of PC coefficients to retain\n",
"pcf_thr = None # Minimum value (by magnitude) for PC coefficients\n",
"verbose = 0 # Flag for print statements\n",
"\n",
"# Model Choice \n",
"model = 'genz_osc' # Choices are 'genz_osc', 'genz_exp', 'genz_cont','genz_gaus','genz_cpeak', 'genz_ppeak'"
]
},
{
"cell_type": "markdown",
"id": "e17570ae-1ebd-4b8d-a9e8-7b1b26ec1809",
"metadata": {},
"source": [
"We randomly generate training and testing data."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "38790a1d-574d-427b-b5e3-44eb3408aa0e",
"metadata": {},
"outputs": [],
"source": [
"# PC model with a full basis set\n",
"pc_model = uqtkpce.PCSet(\"NISPnoq\", nord, ndim, pc_type, pc_alpha, pc_beta)\n",
"\n",
"# Random number generator\n",
"rng = qmc.LatinHypercube(d=ndim, seed=42)\n",
"\n",
"#Training\n",
"nTrain = int(pc_model.GetNumberPCTerms()*0.75) # Number of training samples\n",
"x_train = 2*rng.random(n=nTrain)-1\n",
"y_train = func(x_train, model, np.ones(ndim+1))\n",
"\n",
"#Testing\n",
"nTest = 10000 # Number of testing samples\n",
"x_test = 2*rng.random(n=nTest)-1\n",
"y_test = func(x_test, model, np.ones(ndim+1))"
]
},
{
"cell_type": "markdown",
"id": "b7fc4f66-eb0d-4a35-a7f6-b3acfa40afb5",
"metadata": {},
"source": [
"We perform BCS."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9de91054-432f-468a-8664-af6e54ddc454",
"metadata": {},
"outputs": [],
"source": [
"# PC object with the starting basis\n",
"\n",
"# determine order of the starting basis\n",
"if mindex_growth == None:\n",
" start_ord = nord # if no basis growth, order of the final basis = order of the starting basis\n",
"else:\n",
" start_ord = nord-niter+1 # if basis growth, shrink starting basis to allow for growth niter-1 times\n",
" \n",
"pc_start = uqtkpce.PCSet(\"NISPnoq\", start_ord, ndim, pc_type, pc_alpha, pc_beta)\n",
"\n",
"# Determine coefficients through BCS\n",
"pc_final, c_k = pce_tools.UQTkBCS(pc_start, x_train, y_train, niter, eta, ntry, eta_folds, mindex_growth, regparams, sigma, trval_frac, npccut, pcf_thr, verbose)"
]
},
{
"cell_type": "markdown",
"id": "26eba228-1435-4d87-bf60-a98a33026144",
"metadata": {},
"source": [
"Finally, we calculate the error."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "850871ba-2c45-4f5c-a0d4-1ce0fd98502d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The NRMS error between a 2 -dimensional genz_osc function and a BCS-based PC surrogate of order 8 is\n"
]
},
{
"data": {
"text/plain": [
"0.173903885535867"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Evaluate the PCE\n",
"pce_evals = pce_tools.UQTkEvaluatePCE(pc_final, c_k, x_test)\n",
"\n",
"# Calculate error metric\n",
"MSE = np.square(np.subtract(y_test, pce_evals)).mean()\n",
"NRMSE=math.sqrt(MSE)/np.linalg.norm(y_test)\n",
"print(\"The NRMS error between a\", ndim, \"-dimensional\", model, \"function and a BCS-based PC surrogate of \\\n",
"order\", nord, \"is\")\n",
"NRMSE"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
4 changes: 4 additions & 0 deletions examples/bare_bcs/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Example that calls BCS directly on an arbitrary set of basis functions

The basis functions do not need to be part of a PCE Set
So this is more general than the wiBCS interface that is set up specifically for PCEs

0 comments on commit 546ffd4

Please sign in to comment.