Skip to content

Commit f558ff5

Browse files
committed
fixing and adding validation
1 parent 0a1787f commit f558ff5

File tree

4 files changed

+89
-13
lines changed

4 files changed

+89
-13
lines changed

pysensors/optimizers/_gqr.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ class GQR(QR):
1616
"""
1717
General QR optimizer for sensor selection.
1818
Ranks sensors in descending order of "importance" based on
19-
reconstruction performance. This is an extension that requires a more intrusive
19+
reconstruction accuracy. This is an extension that requires a more intrusive
2020
access to the QR optimizer to facilitate a more adaptive optimization. This is a generalized version of cost constraints
21-
in the sense that users can allow n constrained sensors in the constrained area.
22-
if n = 0 this converges to the CCQR results. If no constraints it converges to QR results.
21+
in the sense that users can allow `n_const_sensors` in the constrained area.
22+
if n = 0 this converges to the CCQR results. and if no constrained region it should converge to the results from QR optimizer.
2323
2424
See the following reference for more information
2525
Manohar, Krithika, et al.
@@ -46,8 +46,6 @@ def __init__(self):
4646
constraint_option : string,
4747
max_n_const_sensors : The number of sensors in the constrained region should be less than or equal to n_const_sensors.
4848
exact_n_const_sensors : The number of sensors in the constrained region should be exactly equal to n_const_sensors.
49-
nx, ny : integer,
50-
X, Y dimensions of the grid.
5149
"""
5250
self.pivots_ = None
5351
self.idx_constrained = []
@@ -59,7 +57,7 @@ def __init__(self):
5957
self.ny = None
6058
self.r = 1
6159

62-
def fit(self,basis_matrix=None,**optimizer_kws):
60+
def fit(self,basis_matrix,**optimizer_kws):
6361
"""
6462
Parameters
6563
----------
@@ -78,6 +76,13 @@ def fit(self,basis_matrix=None,**optimizer_kws):
7876
n_features, n_samples = basis_matrix.shape # We transpose basis_matrix below
7977
max_const_sensors = len(self.idx_constrained) # Maximum number of sensors allowed in the constrained region
8078

79+
## Assertions and checks:
80+
# if self.n_sensors > n_features - max_const_sensors + self.nConstrainedSensors:
81+
# raise IOError ("n_sensors cannot be larger than n_features - all possible locations in the constrained area + allowed constrained sensors")
82+
# if self.n_sensors > n_samples + self.nConstrainedSensors: ## Handling zero constraint?
83+
# raise IOError ("Currently n_sensors should be less than min(number of samples, number of modes) + number of constrained sensors,\
84+
# got: n_sensors = {}, n_samples + const_sensors = {} + {} = {}".format(self.n_sensors,n_samples,self.nConstrainedSensors,n_samples+self.nConstrainedSensors))
85+
8186
# Initialize helper variables
8287
R = basis_matrix.conj().T.copy()
8388
p = np.arange(n_features)

pysensors/utils/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from ._norm_calc import exact_n
77
from ._norm_calc import max_n
88
from ._norm_calc import predetermined
9+
from ._validation import determinant
10+
from ._validation import relative_reconstruction_error
911

1012
__all__ = [
1113
"constrained_binary_solve",
@@ -17,5 +19,7 @@
1719
"functional_constraints",
1820
"exact_n",
1921
"max_n",
20-
"predetermined"
22+
"predetermined",
23+
"determinant",
24+
"relative_reconstruction_error"
2125
]

pysensors/utils/_norm_calc.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,23 @@ def exact_n(lin_idx, dlens, piv, j, n_const_sensors, **kwargs): ##Will first for
3030
-------
3131
dlens : np.darray, shape [Variable based on j] with constraints mapped into it.
3232
"""
33-
didx = np.isin(piv[j:],lin_idx,invert=j<n_const_sensors)
34-
dlens[didx] = 0
35-
return dlens
33+
if 'all_sensors' in kwargs.keys():
34+
all_sensors = kwargs['all_sensors']
35+
else:
36+
all_sensors = []
37+
if 'n_sensors' in kwargs.keys():
38+
n_sensors = kwargs['n_sensors']
39+
else:
40+
n_sensors = len(all_sensors)
41+
for i in range(n_sensors):
42+
if np.isin(all_sensors[:n_sensors],lin_idx,invert=False).sum() < n_const_sensors:
43+
if n_sensors >= j > (n_sensors - (n_const_sensors-1)):
44+
didx = np.isin(piv[j:],lin_idx,invert=True)
45+
dlens[didx] = 0
46+
else:
47+
max_n(lin_idx, dlens, piv, j, n_const_sensors, **kwargs)
48+
return(dlens)
49+
3650

3751
def max_n(lin_idx, dlens, piv, j, n_const_sensors, **kwargs):
3852
"""
@@ -109,9 +123,9 @@ def predetermined(lin_idx, dlens, piv, j, n_const_sensors, **kwargs):
109123

110124
__norm_calc_type = {}
111125
__norm_calc_type[''] = unconstrained
112-
__norm_calc_type['exact_n_const_sensors'] = exact_n
113-
__norm_calc_type['max_n_const_sensors'] = max_n
114-
__norm_calc_type['predetermined_norm_calc'] = predetermined
126+
__norm_calc_type['exact_n'] = exact_n
127+
__norm_calc_type['max_n'] = max_n
128+
__norm_calc_type['predetermined'] = predetermined
115129

116130
def returnInstance(cls, name):
117131
"""

pysensors/utils/_validation.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Various utility functions for validation and computing reconstruction scores and errors.
3+
"""
4+
import numpy as np
5+
from scipy.sparse import csr_matrix
6+
7+
def determinant(top_sensors, n_features, basis_matrix):
8+
"""
9+
Function for calculating |C.T phi.T C phi|.
10+
11+
Parameters
12+
----------
13+
top_sensors: np.darray,
14+
Column indices of choosen sensor locations
15+
n_features : int,
16+
No. of features of dataset
17+
basis_matrix : np.darray,
18+
The basis matrix calculated by model.basis_matrix_
19+
Returns
20+
-------
21+
optimality : Float,
22+
The dterminant value obtained.
23+
"""
24+
25+
p = len(top_sensors) # Number of sensors
26+
n,r = np.shape(basis_matrix) # state dimension X Number of modes
27+
c = csr_matrix((p,n),dtype=np.int8)
28+
29+
for i in range(p):
30+
c[i,top_sensors[i]] = 1
31+
phi = basis_matrix
32+
# optimality = np.linalg.det(( c @ phi).T @ (c@phi)) #np.log(np.linalg.det(phi.T @ c.T)) np.log(np.linalg.det((c@phi).T @ (c@phi)))
33+
optimality = abs(np.linalg.det(c @ phi)) if p==r else abs(np.linalg.det(( c @ phi).T @ (c @ phi)))
34+
# optimality = abs(np.linalg.det(c @ phi))
35+
return optimality
36+
37+
def relative_reconstruction_error(data, prediction):
38+
"""
39+
Function for calculating relative error between actual data and the reconstruction
40+
41+
Parameters
42+
----------
43+
data: np.darray,
44+
The actual data from the dataset evaluated
45+
prediction : np.darray,
46+
The predicted values from model.predict(X[:,top_sensors])
47+
Returns
48+
-------
49+
error_val : Float,
50+
The relative error calculated.
51+
"""
52+
error_val = (np.linalg.norm((data - prediction)/np.linalg.norm(data)))*100
53+
return (error_val)

0 commit comments

Comments
 (0)