Skip to content

Commit 11d5bc7

Browse files
committed
Adding max_n and predetermined tests to test_optimizers.py, deleting comments from _gqr.py,spatially_constrained_qr.ipynb and _norm_calc-py,adding kwargs documentation to _custom.py to address Josh comments
1 parent 370e9e4 commit 11d5bc7

File tree

5 files changed

+143
-121
lines changed

5 files changed

+143
-121
lines changed

examples/spatially_constrained_qr.ipynb

Lines changed: 91 additions & 105 deletions
Large diffs are not rendered by default.

pysensors/basis/_custom.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ class Custom(InvertibleBasis, MatrixMixin):
2727
"""
2828

2929
def __init__(self, U, n_basis_modes=10, **kwargs):
30+
'''
31+
kwargs : Not defined but added to remain consistent with prior basis functions.
32+
'''
3033
if isinstance(n_basis_modes, int) and n_basis_modes > 0:
3134
super(Custom, self).__init__()#n_components=n_basis_modes, **kwargs
3235
self._n_basis_modes = n_basis_modes

pysensors/optimizers/_gqr.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class GQR(QR):
2626
"Data-driven sparse sensor placement for reconstruction:
2727
Demonstrating the benefits of exploiting known patterns."
2828
IEEE Control Systems Magazine 38.3 (2018): 63-86.
29+
30+
Niharika Karnik, Mohammad G. Abdo, Carlos E. Estrada Perez, Jun Soo Yoo, Joshua J. Cogliati, Richard S. Skifton,
31+
Pattrick Calderoni, Steven L. Brunton, and Krithika Manohar.
32+
Optimal Sensor Placement with Adaptive Constraints for Nuclear Digital Twins. 2023. arXiv: 2306 . 13637 [math.OC].
2933
3034
@ authors: Niharika Karnik (@nkarnik2999), Mohammad Abdo (@Jimmy-INL), and Krithika Manohar (@kmanohar)
3135
"""
@@ -76,13 +80,6 @@ def fit(self,basis_matrix,**optimizer_kws):
7680
n_features, n_samples = basis_matrix.shape # We transpose basis_matrix below
7781
max_const_sensors = len(self.idx_constrained) # Maximum number of sensors allowed in the constrained region
7882

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-
8683
# Initialize helper variables
8784
R = basis_matrix.conj().T.copy()
8885
p = np.arange(n_features)

pysensors/utils/_norm_calc.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
def unconstrained(lin_idx, dlens, piv, j, n_const_sensors, **kwargs):
88
return dlens
99

10-
def exact_n(lin_idx, dlens, piv, j, n_const_sensors, **kwargs): ##Will first force sensors into constrained region
11-
# num_sensors should be fixed for each custom constraint (for now)
12-
# num_sensors must be <= size of constraint region
10+
def exact_n(lin_idx, dlens, piv, j, n_const_sensors, **kwargs):
1311
"""
1412
Function for mapping constrained sensor locations with the QR procedure.
1513

tests/optimizers/test_optimizers.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,50 @@ def test_gqr_exact_constrainted_case1(data_random):
107107

108108
# Get ranked sensors from GQR
109109
sensors_GQR = GQR().fit(x.T, idx_constrained=forbidden_sensors,n_sensors=total_sensors,n_const_sensors=exact_n_const_sensors, constraint_option='exact_n_const_sensors').get_sensors()[:total_sensors]
110+
assert sensors_GQR.intersection(forbidden_sensors) == 3
111+
110112

111-
# try to compare these using the validation metrics
113+
def test_gqr_max_constrained_case1(data_random):
114+
## In this case we want to place a total of 10 sensors
115+
# with a constrained region that is allowed to have a maximum of 3 sensors
116+
# but 4 of the first 10 are in the constrained region
117+
x = data_random
118+
# unconstrained sensors (optimal)
119+
sensors_QR = QR().fit(x.T).get_sensors()
120+
# exact number of sensors allowed in the constrained region
121+
total_sensors = 10
122+
max_n_const_sensors = 3
123+
forbidden_sensors = [8,5,2,6]
124+
totally_forbidden_sensors = [x for x in forbidden_sensors if x in sensors_QR][:max_n_const_sensors]
125+
totally_forbidden_sensors = [y for y in forbidden_sensors if y not in totally_forbidden_sensors]
126+
costs = np.zeros(x.shape[1])
127+
costs[totally_forbidden_sensors] = 100
128+
# Get ranked sensors
129+
sensors = CCQR(sensor_costs=costs).fit(x.T).get_sensors()[:total_sensors]
112130

113-
## TODO
114-
def test_gqr_max_constrained():
115-
pass
131+
# Forbidden sensors should not be included
132+
chosen_sensors = set(sensors[: (x.shape[1] - len(totally_forbidden_sensors))])
133+
assert chosen_sensors.isdisjoint(set(totally_forbidden_sensors))
134+
135+
136+
# Get ranked sensors from GQR
137+
sensors_GQR = GQR().fit(x.T, idx_constrained=forbidden_sensors,n_sensors=total_sensors,n_const_sensors=max_n_const_sensors, constraint_option='max_n_const_sensors').get_sensors()[:total_sensors]
138+
assert sensors_GQR.intersection(forbidden_sensors) == 3
139+
140+
def test_gqr_predetermined_case1(data_random):
141+
## In this case we want to place a total of 10 sensors
142+
# 2 of the sensors are predetermined by the user
143+
x = data_random
144+
# unconstrained sensors (optimal)
145+
sensors_QR = QR().fit(x.T).get_sensors()
146+
# Predtermined sensors
147+
total_sensors = 10
148+
n_sensors_pre = 2
149+
predetermined_sensors = [8,5]
150+
151+
# Predetermined sensors shopuld be included
152+
# Get ranked sensors from GQR
153+
sensors_GQR = GQR().fit(x.T, idx_constrained=predetermined_sensors,n_sensors=total_sensors,n_const_sensors=n_sensors_pre, constraint_option='predetermined').get_sensors()[:total_sensors]
154+
assert sensors_GQR.intersection(predetermined_sensors) == 2
155+
116156

117-
def test_gqr_radii_constrained():
118-
pass

0 commit comments

Comments
 (0)