Skip to content

Commit daee413

Browse files
author
niharika2999
committed
Adding Script for gqr
1 parent 0e5f9ca commit daee413

File tree

1 file changed

+143
-24
lines changed

1 file changed

+143
-24
lines changed

pysensors/optimizers/_gqr.py

Lines changed: 143 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import numpy as np
22

3-
from ._qr import QR
3+
from pysensors.optimizers._qr import QR
4+
5+
import matplotlib.pyplot as plt
6+
from sklearn import datasets
7+
from sklearn import metrics
8+
from mpl_toolkits.axes_grid1 import make_axes_locatable
9+
10+
import pysensors as ps
411

512

613
class GQR(QR):
@@ -9,8 +16,15 @@ class GQR(QR):
916
Ranks sensors in descending order of "importance" based on
1017
reconstruction performance. This is an extension that requires a more intrusive
1118
access to the QR optimizer to facilitate a more adaptive optimization. This is a generalized version of cost constraints
12-
in the sense that users can allow n consttrained sensors in the constrained area.
19+
in the sense that users can allow n constrained sensors in the constrained area.
1320
if n = 0 this converges to the CCQR results.
21+
22+
See the following reference for more information
23+
Manohar, Krithika, et al.
24+
"Data-driven sparse sensor placement for reconstruction:
25+
Demonstrating the benefits of exploiting known patterns."
26+
IEEE Control Systems Magazine 38.3 (2018): 63-86.
27+
1428
@ authors: Niharika Karnik (@nkarnik2999), Mohammad Abdo (@Jimmy-INL), and Krithika Manohar (@kmanohar)
1529
"""
1630
def __init__(self,idx_constrained,n_sensors,const_sensors):
@@ -19,6 +33,12 @@ def __init__(self,idx_constrained,n_sensors,const_sensors):
1933
----------
2034
pivots_ : np.ndarray, shape [n_features]
2135
Ranked list of sensor locations.
36+
idx_constrained : np.ndarray, shape [No. of constrained locations]
37+
Column Indices of the sensors in the constrained locations.
38+
n_sensors : integer,
39+
Total number of sensors
40+
const_sensors : integer,
41+
Total number of sensors required by the user in the constrained region.
2242
"""
2343
self.pivots_ = None
2444
self.constrainedIndices = idx_constrained
@@ -40,41 +60,34 @@ def fit(
4060
4161
Returns
4262
-------
43-
self: a fitted :class:`pysensors.optimizers.CCQR` instance
63+
self: a fitted :class:`pysensors.optimizers.QR` instance
4464
"""
4565

4666
n_features, n_samples = basis_matrix.shape # We transpose basis_matrix below
47-
max_const_sensors = len(self.constrainedIndices)
67+
max_const_sensors = len(self.constrainedIndices) #Maximum number of sensors allowed in the constrained region
4868

4969
## Assertions and checks:
5070
if self.nSensors > n_features - max_const_sensors + self.nConstrainedSensors:
5171
raise IOError ("n_sensors cannot be larger than n_features - all possible locations in the constrained area + allowed constrained sensors")
52-
if self.nSensors > n_samples + self.nConstrainedSensors:
72+
if self.nSensors > n_samples + self.nConstrainedSensors: ## Handling zero constraint?
5373
raise IOError ("Currently n_sensors should be less than number of samples + number of constrained sensors,\
54-
got: n_sensors = {}, n_samples + const_sensors = {} + {} = {}".format(n_sensors,n_samples,const_sensors,n_samples+const_sensors))
74+
got: n_sensors = {}, n_samples + const_sensors = {} + {} = {}".format(n_sensors,n_samples,self.nConstrainedSensors,n_samples+self.nConstrainedSensors))
5575

5676
# Initialize helper variables
5777
R = basis_matrix.conj().T.copy()
58-
#print(R.shape)
5978
p = np.arange(n_features)
60-
#print(p)
6179
k = min(n_samples, n_features)
6280

6381

6482
for j in range(k):
6583
r = R[j:, j:]
6684
# Norm of each column
6785
dlens = np.sqrt(np.sum(np.abs(r) ** 2, axis=0))
68-
69-
# if j < const_sensors:
70-
dlens_updated = f_region(self.constrainedIndices,dlens,p,j, self.nConstrainedSensors)
71-
# else:
72-
# dlens_updated = dlens
86+
dlens_updated = f_region(self.constrainedIndices,dlens,p,j, self.nConstrainedSensors) #Handling constrained region sensor placement problem
87+
7388
# Choose pivot
7489
i_piv = np.argmax(dlens_updated)
75-
#print(i_piv)
76-
77-
90+
7891
dlen = dlens_updated[i_piv]
7992

8093
if dlen > 0:
@@ -87,10 +100,7 @@ def fit(
87100

88101
# Track column pivots
89102
i_piv += j # true permutation index is i_piv shifted by the iteration counter j
90-
# print(i_piv) # Niharika's debugging line
91103
p[[j, i_piv]] = p[[i_piv, j]]
92-
# print(p)
93-
94104

95105
# Switch columns
96106
R[:, [j, i_piv]] = R[:, [i_piv, j]]
@@ -105,6 +115,7 @@ def fit(
105115
return self
106116

107117
## TODO: why not a part of the class?
118+
108119
#function for mapping sensor locations with constraints
109120
def f_region(lin_idx, dlens, piv, j, const_sensors):
110121
#num_sensors should be fixed for each custom constraint (for now)
@@ -115,10 +126,12 @@ def f_region(lin_idx, dlens, piv, j, const_sensors):
115126
Parameters
116127
----------
117128
lin_idx: np.ndarray, shape [No. of constrained locations]
118-
Array which contains the constrained locations mapped on the grid.
129+
Array which contains the constrained locationsof the grid in terms of column indices of basis_matrix.
119130
dlens: np.ndarray, shape [Variable based on j]
120131
Array which contains the norm of columns of basis matrix.
121-
num_sensors: int,
132+
piv: np.ndarray, shape [n_features]
133+
Ranked list of sensor locations.
134+
const_sensors: int,
122135
Number of sensors to be placed in the constrained area.
123136
j: int,
124137
Iterative variable in the QR algorithm.
@@ -138,22 +151,43 @@ def f_region(lin_idx, dlens, piv, j, const_sensors):
138151
dlens[didx] = 0
139152
return dlens
140153

141-
def getConstraindSensorsIndices(xmin, xmax,ymin,ymax, all_sensors):
154+
def getConstraindSensorsIndices(xmin, xmax, ymin, ymax, all_sensors):
155+
"""
156+
Function for mapping constrained sensor locations on the grid with the column indices of the basis_matrix.
157+
158+
Parameters
159+
----------
160+
xmin: int,
161+
"Fill"
162+
xmax : int,
163+
"Fill"
164+
ymin : int,
165+
"Fill"
166+
ymax : int
167+
"Fill"
168+
all_sensors : np.ndarray, shape [n_features]
169+
Ranked list of sensor locations.
170+
171+
Returns
172+
-------
173+
idx_constrained : np.darray, shape [No. of constrained locations]
174+
Array which contains the constrained locationsof the grid in terms of column indices of basis_matrix.
175+
"""
142176
n_features = len(all_sensors)
143177
imageSize = int(np.sqrt(n_features))
144178
a = np.unravel_index(all_sensors, (imageSize,imageSize))
145179
constrained_sensorsx = []
146180
constrained_sensorsy = []
147181
for i in range(n_features):
148-
if (a[0][i] > xmin and a[0][i] < xmax) and (a[1][i] > ymin and a[1][i] < ymax): # x<10 and y>40
182+
if (a[0][i] >= xmin and a[0][i] <= xmax) and (a[1][i] >= ymin and a[1][i] <= ymax): # x<10 and y>40
149183
constrained_sensorsx.append(a[0][i])
150184
constrained_sensorsy.append(a[1][i])
151185

152186
constrained_sensorsx = np.array(constrained_sensorsx)
153187
constrained_sensorsy = np.array(constrained_sensorsy)
154188
constrained_sensors_array = np.stack((constrained_sensorsy, constrained_sensorsx), axis=1)
155189
constrained_sensors_tuple = np.transpose(constrained_sensors_array)
156-
if len(constrained_sensorsx) == 0:
190+
if len(constrained_sensorsx) == 0: ##Check to handle condition when number of sensors in the constrained region = 0
157191
idx_constrained = []
158192
else:
159193
idx_constrained = np.ravel_multi_index(constrained_sensors_tuple, (imageSize,imageSize))
@@ -172,3 +206,88 @@ def functionalConstraint(position, func_response,func_input, freeTerm):
172206

173207
if __name__ == '__main__':
174208
pass
209+
faces = datasets.fetch_olivetti_faces(shuffle=True)
210+
X = faces.data
211+
212+
n_samples, n_features = X.shape
213+
print('Number of samples:', n_samples)
214+
print('Number of features (sensors):', n_features)
215+
216+
# Global centering
217+
X = X - X.mean(axis=0)
218+
219+
# Local centering
220+
X -= X.mean(axis=1).reshape(n_samples, -1)
221+
222+
n_row, n_col = 2, 3
223+
n_components = n_row * n_col
224+
image_shape = (64, 64)
225+
226+
def plot_gallery(title, images, n_col=n_col, n_row=n_row, cmap=plt.cm.gray):
227+
'''Function for plotting faces'''
228+
plt.figure(figsize=(2. * n_col, 2.26 * n_row))
229+
plt.suptitle(title, size=16)
230+
for i, comp in enumerate(images):
231+
plt.subplot(n_row, n_col, i + 1)
232+
vmax = max(comp.max(), -comp.min())
233+
plt.imshow(comp.reshape(image_shape), cmap=cmap,
234+
interpolation='nearest',
235+
vmin=-vmax, vmax=vmax)
236+
plt.xticks(())
237+
plt.yticks(())
238+
plt.subplots_adjust(0.01, 0.05, 0.99, 0.93, 0.04, 0.)
239+
240+
# plot_gallery("First few centered faces", X[:n_components])
241+
242+
#Find all sensor locations using built in QR optimizer
243+
max_const_sensors = 230
244+
n_const_sensors = 7
245+
n_sensors = 50
246+
optimizer = ps.optimizers.QR()
247+
model = ps.SSPOR(optimizer=optimizer, n_sensors=n_sensors)
248+
model.fit(X)
249+
250+
all_sensors = model.get_all_sensors()
251+
252+
##Constrained sensor location on the grid:
253+
xmin = 20
254+
xmax = 40
255+
ymin = 25
256+
ymax = 45
257+
sensors_constrained = getConstraindSensorsIndices(xmin,xmax,ymin,ymax,all_sensors) #Constrained column indices
258+
259+
##Plotting the constrained region
260+
# ax = plt.subplot()
261+
# #Plot constrained space
262+
# img = np.zeros(n_features)
263+
# img[sensors_constrained] = 1
264+
# im = plt.imshow(img.reshape(image_shape),cmap=plt.cm.binary)
265+
# # create an axes on the right side of ax. The width of cax will be 5%
266+
# # of ax and the padding between cax and ax will be fixed at 0.05 inch.
267+
# divider = make_axes_locatable(ax)
268+
# cax = divider.append_axes("right", size="5%", pad=0.05)
269+
# plt.colorbar(im, cax=cax)
270+
# plt.title('Constrained region');
271+
272+
## Fit the dataset with the optimizer GQR
273+
optimizer1 = GQR(sensors_constrained,n_sensors,n_const_sensors)
274+
model1 = ps.SSPOR(optimizer = optimizer1, n_sensors = n_sensors)
275+
model1.fit(X)
276+
all_sensors1 = model1.get_all_sensors()
277+
278+
top_sensors = model1.get_selected_sensors()
279+
print(top_sensors)
280+
## TODO: this can be done using ravel and unravel more elegantly
281+
yConstrained = np.floor(top_sensors[:n_const_sensors]/np.sqrt(n_features))
282+
xConstrained = np.mod(top_sensors[:n_const_sensors],np.sqrt(n_features))
283+
284+
img = np.zeros(n_features)
285+
img[top_sensors[n_const_sensors:]] = 16
286+
plt.plot(xConstrained,yConstrained,'*r')
287+
plt.plot([xmin,xmin],[ymin,ymax],'r')
288+
plt.plot([xmin,xmax],[ymax,ymax],'r')
289+
plt.plot([xmax,xmax],[ymin,ymax],'r')
290+
plt.plot([xmin,xmax],[ymin,ymin],'r')
291+
plt.imshow(img.reshape(image_shape),cmap=plt.cm.binary)
292+
plt.title('n_sensors = {}, n_constr_sensors = {}'.format(n_sensors,n_const_sensors))
293+
plt.show()

0 commit comments

Comments
 (0)