easyvvuq.utils.discrete_validation
Utilities for handling discrete distribution validation in EasyVVUQ.
This module provides enhanced validation capabilities for discrete distributions when used with Stochastic Collocation (SC) and Polynomial Chaos Expansion (PCE) methods.
1""" 2Utilities for handling discrete distribution validation in EasyVVUQ. 3 4This module provides enhanced validation capabilities for discrete distributions 5when used with Stochastic Collocation (SC) and Polynomial Chaos Expansion (PCE) methods. 6""" 7import numpy as np 8import chaospy as cp 9from typing import Any, Dict, Union 10 11 12def is_integer_valued(value: Any) -> bool: 13 """ 14 Check if a value represents an integer, even if it's stored as a float. 15 16 This is crucial for handling chaospy output where discrete distributions 17 may return float arrays for numerical consistency with continuous distributions. 18 19 Parameters 20 ---------- 21 value : Any 22 The value to check 23 24 Returns 25 ------- 26 bool 27 True if the value represents an integer 28 """ 29 try: 30 # Handle numpy arrays and scalars 31 if hasattr(value, '__iter__') and not isinstance(value, (str, bytes)): 32 # For arrays, check if all elements are integer-valued 33 return all(is_integer_valued(v) for v in value) 34 35 # Convert to float first to handle various numeric types 36 float_val = float(value) 37 38 # Check if it's close to an integer 39 return abs(float_val - round(float_val)) < 1e-10 40 except (ValueError, TypeError): 41 return False 42 43 44def convert_to_integer(value: Any) -> Union[int, Any]: 45 """ 46 Convert a value to integer if it represents an integer, otherwise return as-is. 47 48 Parameters 49 ---------- 50 value : Any 51 The value to convert 52 53 Returns 54 ------- 55 Union[int, Any] 56 Integer value if conversion is valid, otherwise the original value 57 """ 58 if is_integer_valued(value): 59 return int(round(float(value))) 60 return value 61 62 63def validate_discrete_parameter(value: Any, param_def: Dict[str, Any]) -> bool: 64 """ 65 Validate a parameter value for discrete distributions. 66 67 This function handles the case where chaospy returns float values 68 for discrete distributions, especially in mixed discrete/continuous scenarios. 69 70 Parameters 71 ---------- 72 value : Any 73 The parameter value to validate 74 param_def : Dict[str, Any] 75 Parameter definition from the campaign 76 77 Returns 78 ------- 79 bool 80 True if the value is valid for this parameter 81 """ 82 param_type = param_def.get('type', 'float') 83 84 # For integer parameters, check if the value is integer-valued 85 if param_type == 'integer': 86 if not is_integer_valued(value): 87 return False 88 89 # Check bounds if specified 90 int_val = convert_to_integer(value) 91 if 'min' in param_def and int_val < param_def['min']: 92 return False 93 if 'max' in param_def and int_val > param_def['max']: 94 return False 95 96 return True 97 98 99def is_discrete_distribution(distribution) -> bool: 100 """ 101 Check if a distribution is discrete. 102 103 Parameters 104 ---------- 105 distribution 106 A chaospy distribution object 107 108 Returns 109 ------- 110 bool 111 True if the distribution is discrete 112 """ 113 return isinstance(distribution, cp.DiscreteUniform) 114 115 116def get_discrete_parameter_info(vary: Dict[str, Any]) -> Dict[str, bool]: 117 """ 118 Identify which parameters use discrete distributions. 119 120 Parameters 121 ---------- 122 vary : Dict[str, Any] 123 Dictionary of parameter names to chaospy distributions 124 125 Returns 126 ------- 127 Dict[str, bool] 128 Dictionary mapping parameter names to whether they are discrete 129 """ 130 discrete_info = {} 131 for param_name, distribution in vary.items(): 132 discrete_info[param_name] = is_discrete_distribution(distribution) 133 return discrete_info 134 135 136def process_sampler_output(run_dict: Dict[str, Any], params_spec, vary: Dict[str, Any]) -> Dict[str, Any]: 137 """ 138 Process sampler output to handle discrete distributions properly. 139 140 This function converts float values to integers for parameters that should be integers 141 but were returned as floats by chaospy due to mixed distribution scenarios. 142 143 Parameters 144 ---------- 145 run_dict : Dict[str, Any] 146 Dictionary of parameter values from the sampler 147 params_spec : ParamsSpecification 148 Parameter specification object 149 vary : Dict[str, Any] 150 Dictionary of parameter names to chaospy distributions 151 152 Returns 153 ------- 154 Dict[str, Any] 155 Processed run dictionary with correct types 156 """ 157 processed_run = run_dict.copy() 158 159 # Get discrete parameter information 160 discrete_info = get_discrete_parameter_info(vary) 161 162 for param_name, value in run_dict.items(): 163 if param_name in params_spec.params_dict: 164 param_def = params_spec.params_dict[param_name] 165 param_type = param_def.get('type', 'float') 166 167 # Convert float to int for integer parameters from discrete distributions 168 if param_type == 'integer' and discrete_info.get(param_name, False): 169 if is_integer_valued(value): 170 processed_run[param_name] = convert_to_integer(value) 171 172 return processed_run
13def is_integer_valued(value: Any) -> bool: 14 """ 15 Check if a value represents an integer, even if it's stored as a float. 16 17 This is crucial for handling chaospy output where discrete distributions 18 may return float arrays for numerical consistency with continuous distributions. 19 20 Parameters 21 ---------- 22 value : Any 23 The value to check 24 25 Returns 26 ------- 27 bool 28 True if the value represents an integer 29 """ 30 try: 31 # Handle numpy arrays and scalars 32 if hasattr(value, '__iter__') and not isinstance(value, (str, bytes)): 33 # For arrays, check if all elements are integer-valued 34 return all(is_integer_valued(v) for v in value) 35 36 # Convert to float first to handle various numeric types 37 float_val = float(value) 38 39 # Check if it's close to an integer 40 return abs(float_val - round(float_val)) < 1e-10 41 except (ValueError, TypeError): 42 return False
Check if a value represents an integer, even if it's stored as a float.
This is crucial for handling chaospy output where discrete distributions may return float arrays for numerical consistency with continuous distributions.
Parameters
- value (Any): The value to check
Returns
- bool: True if the value represents an integer
45def convert_to_integer(value: Any) -> Union[int, Any]: 46 """ 47 Convert a value to integer if it represents an integer, otherwise return as-is. 48 49 Parameters 50 ---------- 51 value : Any 52 The value to convert 53 54 Returns 55 ------- 56 Union[int, Any] 57 Integer value if conversion is valid, otherwise the original value 58 """ 59 if is_integer_valued(value): 60 return int(round(float(value))) 61 return value
Convert a value to integer if it represents an integer, otherwise return as-is.
Parameters
- value (Any): The value to convert
Returns
- Union[int, Any]: Integer value if conversion is valid, otherwise the original value
64def validate_discrete_parameter(value: Any, param_def: Dict[str, Any]) -> bool: 65 """ 66 Validate a parameter value for discrete distributions. 67 68 This function handles the case where chaospy returns float values 69 for discrete distributions, especially in mixed discrete/continuous scenarios. 70 71 Parameters 72 ---------- 73 value : Any 74 The parameter value to validate 75 param_def : Dict[str, Any] 76 Parameter definition from the campaign 77 78 Returns 79 ------- 80 bool 81 True if the value is valid for this parameter 82 """ 83 param_type = param_def.get('type', 'float') 84 85 # For integer parameters, check if the value is integer-valued 86 if param_type == 'integer': 87 if not is_integer_valued(value): 88 return False 89 90 # Check bounds if specified 91 int_val = convert_to_integer(value) 92 if 'min' in param_def and int_val < param_def['min']: 93 return False 94 if 'max' in param_def and int_val > param_def['max']: 95 return False 96 97 return True
Validate a parameter value for discrete distributions.
This function handles the case where chaospy returns float values for discrete distributions, especially in mixed discrete/continuous scenarios.
Parameters
- value (Any): The parameter value to validate
- param_def (Dict[str, Any]): Parameter definition from the campaign
Returns
- bool: True if the value is valid for this parameter
100def is_discrete_distribution(distribution) -> bool: 101 """ 102 Check if a distribution is discrete. 103 104 Parameters 105 ---------- 106 distribution 107 A chaospy distribution object 108 109 Returns 110 ------- 111 bool 112 True if the distribution is discrete 113 """ 114 return isinstance(distribution, cp.DiscreteUniform)
Check if a distribution is discrete.
Parameters
- distribution: A chaospy distribution object
Returns
- bool: True if the distribution is discrete
117def get_discrete_parameter_info(vary: Dict[str, Any]) -> Dict[str, bool]: 118 """ 119 Identify which parameters use discrete distributions. 120 121 Parameters 122 ---------- 123 vary : Dict[str, Any] 124 Dictionary of parameter names to chaospy distributions 125 126 Returns 127 ------- 128 Dict[str, bool] 129 Dictionary mapping parameter names to whether they are discrete 130 """ 131 discrete_info = {} 132 for param_name, distribution in vary.items(): 133 discrete_info[param_name] = is_discrete_distribution(distribution) 134 return discrete_info
Identify which parameters use discrete distributions.
Parameters
- vary (Dict[str, Any]): Dictionary of parameter names to chaospy distributions
Returns
- Dict[str, bool]: Dictionary mapping parameter names to whether they are discrete
137def process_sampler_output(run_dict: Dict[str, Any], params_spec, vary: Dict[str, Any]) -> Dict[str, Any]: 138 """ 139 Process sampler output to handle discrete distributions properly. 140 141 This function converts float values to integers for parameters that should be integers 142 but were returned as floats by chaospy due to mixed distribution scenarios. 143 144 Parameters 145 ---------- 146 run_dict : Dict[str, Any] 147 Dictionary of parameter values from the sampler 148 params_spec : ParamsSpecification 149 Parameter specification object 150 vary : Dict[str, Any] 151 Dictionary of parameter names to chaospy distributions 152 153 Returns 154 ------- 155 Dict[str, Any] 156 Processed run dictionary with correct types 157 """ 158 processed_run = run_dict.copy() 159 160 # Get discrete parameter information 161 discrete_info = get_discrete_parameter_info(vary) 162 163 for param_name, value in run_dict.items(): 164 if param_name in params_spec.params_dict: 165 param_def = params_spec.params_dict[param_name] 166 param_type = param_def.get('type', 'float') 167 168 # Convert float to int for integer parameters from discrete distributions 169 if param_type == 'integer' and discrete_info.get(param_name, False): 170 if is_integer_valued(value): 171 processed_run[param_name] = convert_to_integer(value) 172 173 return processed_run
Process sampler output to handle discrete distributions properly.
This function converts float values to integers for parameters that should be integers but were returned as floats by chaospy due to mixed distribution scenarios.
Parameters
- run_dict (Dict[str, Any]): Dictionary of parameter values from the sampler
- params_spec (ParamsSpecification): Parameter specification object
- vary (Dict[str, Any]): Dictionary of parameter names to chaospy distributions
Returns
- Dict[str, Any]: Processed run dictionary with correct types