Skip to content

Commit 434903b

Browse files
committed
Merge branch 'niharika-krithika-mohammad-regionConstraints' of https://github.com/niharika2999/pysensors into niharika-krithika-mohammad-regionConstraints
2 parents 16b8427 + 772b525 commit 434903b

File tree

4 files changed

+4683
-299
lines changed

4 files changed

+4683
-299
lines changed

examples/region_optimal.ipynb

Lines changed: 4417 additions & 133 deletions
Large diffs are not rendered by default.

pysensors/optimizers/_gqr.py

Lines changed: 130 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class GQR(QR):
2727
2828
@ authors: Niharika Karnik (@nkarnik2999), Mohammad Abdo (@Jimmy-INL), and Krithika Manohar (@kmanohar)
2929
"""
30-
def __init__(self,idx_constrained,n_sensors,const_sensors,all_sensors):
30+
def __init__(self,idx_constrained,n_sensors,n_const_sensors,all_sensors):
3131
"""
3232
Attributes
3333
----------
@@ -37,13 +37,14 @@ def __init__(self,idx_constrained,n_sensors,const_sensors,all_sensors):
3737
Column Indices of the sensors in the constrained locations.
3838
n_sensors : integer,
3939
Total number of sensors
40-
const_sensors : integer,
40+
n_const_sensors : integer,
4141
Total number of sensors required by the user in the constrained region.
4242
"""
4343
self.pivots_ = None
44+
self.optimality = None
4445
self.constrainedIndices = idx_constrained
4546
self.nSensors = n_sensors
46-
self.nConstrainedSensors = const_sensors
47+
self.nConstrainedSensors = n_const_sensors
4748
self.all_sensorloc = all_sensors
4849

4950
def fit(
@@ -71,8 +72,8 @@ def fit(
7172
if self.nSensors > n_features - max_const_sensors + self.nConstrainedSensors:
7273
raise IOError ("n_sensors cannot be larger than n_features - all possible locations in the constrained area + allowed constrained sensors")
7374
if self.nSensors > n_samples + self.nConstrainedSensors: ## Handling zero constraint?
74-
raise IOError ("Currently n_sensors should be less than number of samples + number of constrained sensors,\
75-
got: n_sensors = {}, n_samples + const_sensors = {} + {} = {}".format(n_sensors,n_samples,self.nConstrainedSensors,n_samples+self.nConstrainedSensors))
75+
raise IOError ("Currently n_sensors should be less than min(number of samples, number of modes) + number of constrained sensors,\
76+
got: n_sensors = {}, n_samples + const_sensors = {} + {} = {}".format(self.nSensors,n_samples,self.nConstrainedSensors,n_samples+self.nConstrainedSensors))
7677

7778
# Initialize helper variables
7879
R = basis_matrix.conj().T.copy()
@@ -85,6 +86,7 @@ def fit(
8586
# Norm of each column
8687
dlens = np.sqrt(np.sum(np.abs(r) ** 2, axis=0))
8788
dlens_updated = f_region_optimal(self.constrainedIndices,dlens,p,j, self.nConstrainedSensors,self.all_sensorloc,self.nSensors) #Handling constrained region sensor placement problem
89+
#dlens_updated = f_region(self.constrainedIndices,dlens,p,j,self.nConstrainedSensors)
8890

8991
# Choose pivot
9092
i_piv = np.argmax(dlens_updated)
@@ -111,14 +113,15 @@ def fit(
111113
R[j + 1 :, j] = 0
112114

113115
self.pivots_ = p
114-
116+
self.optimality = np.trace(np.real(R))
117+
print("The trace(R) = {}".format(self.optimality))
115118

116119
return self
117120

118121
## TODO: why not a part of the class?
119122

120123
#function for mapping sensor locations with constraints
121-
def f_region(lin_idx, dlens, piv, j, const_sensors):
124+
def f_region(lin_idx, dlens, piv, j, n_const_sensors): ##Will first force sensors into constrained region
122125
#num_sensors should be fixed for each custom constraint (for now)
123126
#num_sensors must be <= size of constraint region
124127
"""
@@ -132,7 +135,7 @@ def f_region(lin_idx, dlens, piv, j, const_sensors):
132135
Array which contains the norm of columns of basis matrix.
133136
piv: np.ndarray, shape [n_features]
134137
Ranked list of sensor locations.
135-
const_sensors: int,
138+
n_const_sensors: int,
136139
Number of sensors to be placed in the constrained area.
137140
j: int,
138141
Iterative variable in the QR algorithm.
@@ -141,7 +144,7 @@ def f_region(lin_idx, dlens, piv, j, const_sensors):
141144
-------
142145
dlens : np.darray, shape [Variable based on j] with constraints mapped into it.
143146
"""
144-
if j < const_sensors: # force sensors into constraint region
147+
if j < n_const_sensors: # force sensors into constraint region
145148
#idx = np.arange(dlens.shape[0])
146149
#dlens[np.delete(idx, lin_idx)] = 0
147150

@@ -152,7 +155,31 @@ def f_region(lin_idx, dlens, piv, j, const_sensors):
152155
dlens[didx] = 0
153156
return dlens
154157

155-
def f_region_optimal(lin_idx, dlens, piv, j, const_sensors,all_sensors,n_sensors):
158+
def f_region_optimal(lin_idx, dlens, piv, j, const_sensors,all_sensors,n_sensors): ##Optimal sensor placement with constraints (will place sensors in the order of QR)
159+
"""
160+
Function for mapping constrained sensor locations with the QR procedure (Optimally).
161+
162+
Parameters
163+
----------
164+
lin_idx: np.ndarray, shape [No. of constrained locations]
165+
Array which contains the constrained locationsof the grid in terms of column indices of basis_matrix.
166+
dlens: np.ndarray, shape [Variable based on j]
167+
Array which contains the norm of columns of basis matrix.
168+
piv: np.ndarray, shape [n_features]
169+
Ranked list of sensor locations.
170+
j: int,
171+
Iterative variable in the QR algorithm.
172+
const_sensors: int,
173+
Number of sensors to be placed in the constrained area.
174+
all_sensors: np.ndarray, shape [n_features]
175+
Ranked list of sensor locations.
176+
n_sensors: integer,
177+
Total number of sensors
178+
179+
Returns
180+
-------
181+
dlens : np.darray, shape [Variable based on j] with constraints mapped into it.
182+
"""
156183
counter = 0
157184
mask = np.isin(all_sensors,lin_idx,invert=False)
158185
const_idx = all_sensors[mask]
@@ -168,159 +195,97 @@ def f_region_optimal(lin_idx, dlens, piv, j, const_sensors,all_sensors,n_sensors
168195
return dlens
169196

170197

171-
def getConstraindSensorsIndices(xmin, xmax, ymin, ymax, nx, ny, all_sensors):
172-
"""
173-
Function for mapping constrained sensor locations on the grid with the column indices of the basis_matrix.
174-
175-
Parameters
176-
----------
177-
xmin: int,
178-
Lower bound for the x-axis constraint
179-
xmax : int,
180-
Upper bound for the x-axis constraint
181-
ymin : int,
182-
Lower bound for the y-axis constraint
183-
ymax : int
184-
Upper bound for the y-axis constraint
185-
all_sensors : np.ndarray, shape [n_features]
186-
Ranked list of sensor locations.
187198

188-
Returns
189-
-------
190-
idx_constrained : np.darray, shape [No. of constrained locations]
191-
Array which contains the constrained locationsof the grid in terms of column indices of basis_matrix.
192-
"""
193-
n_features = len(all_sensors)
194-
imageSize = int(np.sqrt(n_features))
195-
a = np.unravel_index(all_sensors, (nx,ny))
196-
constrained_sensorsx = []
197-
constrained_sensorsy = []
198-
for i in range(n_features):
199-
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
200-
constrained_sensorsx.append(a[0][i])
201-
constrained_sensorsy.append(a[1][i])
202-
203-
constrained_sensorsx = np.array(constrained_sensorsx)
204-
constrained_sensorsy = np.array(constrained_sensorsy)
205-
constrained_sensors_array = np.stack((constrained_sensorsy, constrained_sensorsx), axis=1)
206-
constrained_sensors_tuple = np.transpose(constrained_sensors_array)
207-
if len(constrained_sensorsx) == 0: ##Check to handle condition when number of sensors in the constrained region = 0
208-
idx_constrained = []
209-
else:
210-
idx_constrained = np.ravel_multi_index(constrained_sensors_tuple, (nx,ny))
211-
return idx_constrained
212-
213-
def getConstrainedSensorsIndicesLinear(xmin,xmax,ymin,ymax,df):
214-
x = df['X (m)'].to_numpy()
215-
n_features = x.shape[0]
216-
y = df['Y (m)'].to_numpy()
217-
idx_constrained = []
218-
for i in range(n_features):
219-
if (x[i] >= xmin and x[i] <= xmax) and (y[i] >= ymin and y[i] <= ymax):
220-
idx_constrained.append(i)
221-
return idx_constrained
222-
223-
def boxConstraints(position,lowerBound,upperBound,):
224-
for i,xi in enumerate(position):
225-
f1 = position[i] - lowerBound[i]
226-
f2 = upperBound[i] - position [i]
227-
return +1 if (f1 and f2 > 0) else -1
228-
229-
def functionalConstraint(position, func_response,func_input, freeTerm):
230-
g = func_response + func_input + freeTerm
231-
return g
232-
233-
234-
if __name__ == '__main__':
235-
faces = datasets.fetch_olivetti_faces(shuffle=True)
236-
X = faces.data
237-
238-
n_samples, n_features = X.shape
239-
print('Number of samples:', n_samples)
240-
print('Number of features (sensors):', n_features)
241-
242-
# Global centering
243-
X = X - X.mean(axis=0)
244-
245-
# Local centering
246-
X -= X.mean(axis=1).reshape(n_samples, -1)
247-
248-
n_row, n_col = 2, 3
249-
n_components = n_row * n_col
250-
image_shape = (64, 64)
251-
nx = 64
252-
ny = 64
253-
254-
def plot_gallery(title, images, n_col=n_col, n_row=n_row, cmap=plt.cm.gray):
255-
'''Function for plotting faces'''
256-
plt.figure(figsize=(2. * n_col, 2.26 * n_row))
257-
plt.suptitle(title, size=16)
258-
for i, comp in enumerate(images):
259-
plt.subplot(n_row, n_col, i + 1)
260-
vmax = max(comp.max(), -comp.min())
261-
plt.imshow(comp.reshape(image_shape), cmap=cmap,
262-
interpolation='nearest',
263-
vmin=-vmax, vmax=vmax)
264-
plt.xticks(())
265-
plt.yticks(())
266-
plt.subplots_adjust(0.01, 0.05, 0.99, 0.93, 0.04, 0.)
267-
268-
# plot_gallery("First few centered faces", X[:n_components])
269-
270-
#Find all sensor locations using built in QR optimizer
271-
max_const_sensors = 230
272-
n_const_sensors = 2
273-
n_sensors = 200
274-
optimizer = ps.optimizers.QR()
275-
model = ps.SSPOR(optimizer=optimizer, n_sensors=n_sensors)
276-
model.fit(X)
277-
278-
all_sensors = model.get_all_sensors()
279-
280-
##Constrained sensor location on the grid:
281-
xmin = 20
282-
xmax = 40
283-
ymin = 25
284-
ymax = 45
285-
sensors_constrained = getConstraindSensorsIndices(xmin,xmax,ymin,ymax,nx,ny,all_sensors) #Constrained column indices
286-
287-
# didx = np.isin(all_sensors,sensors_constrained,invert=False)
288-
# const_index = np.nonzero(didx)
289-
# j =
290-
291-
292-
##Plotting the constrained region
293-
# ax = plt.subplot()
294-
# #Plot constrained space
295-
# img = np.zeros(n_features)
296-
# img[sensors_constrained] = 1
297-
# im = plt.imshow(img.reshape(image_shape),cmap=plt.cm.binary)
298-
# # create an axes on the right side of ax. The width of cax will be 5%
299-
# # of ax and the padding between cax and ax will be fixed at 0.05 inch.
300-
# divider = make_axes_locatable(ax)
301-
# cax = divider.append_axes("right", size="5%", pad=0.05)
302-
# plt.colorbar(im, cax=cax)
303-
# plt.title('Constrained region');
304-
305-
## Fit the dataset with the optimizer GQR
306-
optimizer1 = GQR(sensors_constrained,n_sensors,n_const_sensors,all_sensors)
307-
model1 = ps.SSPOR(optimizer = optimizer1, n_sensors = n_sensors)
308-
model1.fit(X)
309-
all_sensors1 = model1.get_all_sensors()
310-
311-
top_sensors = model1.get_selected_sensors()
312-
print(top_sensors)
313-
## TODO: this can be done using ravel and unravel more elegantly
314-
#yConstrained = np.floor(top_sensors[:n_const_sensors]/np.sqrt(n_features))
315-
#xConstrained = np.mod(top_sensors[:n_const_sensors],np.sqrt(n_features))
316-
317-
img = np.zeros(n_features)
318-
img[top_sensors] = 16
319-
#plt.plot(xConstrained,yConstrained,'*r')
320-
plt.plot([xmin,xmin],[ymin,ymax],'r')
321-
plt.plot([xmin,xmax],[ymax,ymax],'r')
322-
plt.plot([xmax,xmax],[ymin,ymax],'r')
323-
plt.plot([xmin,xmax],[ymin,ymin],'r')
324-
plt.imshow(img.reshape(image_shape),cmap=plt.cm.binary)
325-
plt.title('n_sensors = {}, n_constr_sensors = {}'.format(n_sensors,n_const_sensors))
326-
plt.show()
199+
# if __name__ == '__main__':
200+
# faces = datasets.fetch_olivetti_faces(shuffle=True)
201+
# X = faces.data
202+
203+
# n_samples, n_features = X.shape
204+
# print('Number of samples:', n_samples)
205+
# print('Number of features (sensors):', n_features)
206+
207+
# # Global centering
208+
# X = X - X.mean(axis=0)
209+
210+
# # Local centering
211+
# X -= X.mean(axis=1).reshape(n_samples, -1)
212+
213+
# n_row, n_col = 2, 3
214+
# n_components = n_row * n_col
215+
# image_shape = (64, 64)
216+
# nx = 64
217+
# ny = 64
218+
219+
# def plot_gallery(title, images, n_col=n_col, n_row=n_row, cmap=plt.cm.gray):
220+
# '''Function for plotting faces'''
221+
# plt.figure(figsize=(2. * n_col, 2.26 * n_row))
222+
# plt.suptitle(title, size=16)
223+
# for i, comp in enumerate(images):
224+
# plt.subplot(n_row, n_col, i + 1)
225+
# vmax = max(comp.max(), -comp.min())
226+
# plt.imshow(comp.reshape(image_shape), cmap=cmap,
227+
# interpolation='nearest',
228+
# vmin=-vmax, vmax=vmax)
229+
# plt.xticks(())
230+
# plt.yticks(())
231+
# plt.subplots_adjust(0.01, 0.05, 0.99, 0.93, 0.04, 0.)
232+
233+
# # plot_gallery("First few centered faces", X[:n_components])
234+
235+
# #Find all sensor locations using built in QR optimizer
236+
# max_const_sensors = 230
237+
# n_const_sensors = 2
238+
# n_sensors = 200
239+
# optimizer = ps.optimizers.QR()
240+
# model = ps.SSPOR(optimizer=optimizer, n_sensors=n_sensors)
241+
# model.fit(X)
242+
243+
# all_sensors = model.get_all_sensors()
244+
245+
# ##Constrained sensor location on the grid:
246+
# xmin = 20
247+
# xmax = 40
248+
# ymin = 25
249+
# ymax = 45
250+
# sensors_constrained = getConstraindSensorsIndices(xmin,xmax,ymin,ymax,nx,ny,all_sensors) #Constrained column indices
251+
252+
# # didx = np.isin(all_sensors,sensors_constrained,invert=False)
253+
# # const_index = np.nonzero(didx)
254+
# # j =
255+
256+
257+
# ##Plotting the constrained region
258+
# # ax = plt.subplot()
259+
# # #Plot constrained space
260+
# # img = np.zeros(n_features)
261+
# # img[sensors_constrained] = 1
262+
# # im = plt.imshow(img.reshape(image_shape),cmap=plt.cm.binary)
263+
# # # create an axes on the right side of ax. The width of cax will be 5%
264+
# # # of ax and the padding between cax and ax will be fixed at 0.05 inch.
265+
# # divider = make_axes_locatable(ax)
266+
# # cax = divider.append_axes("right", size="5%", pad=0.05)
267+
# # plt.colorbar(im, cax=cax)
268+
# # plt.title('Constrained region');
269+
270+
# ## Fit the dataset with the optimizer GQR
271+
# optimizer1 = GQR(sensors_constrained,n_sensors,n_const_sensors,all_sensors)
272+
# model1 = ps.SSPOR(optimizer = optimizer1, n_sensors = n_sensors)
273+
# model1.fit(X)
274+
# all_sensors1 = model1.get_all_sensors()
275+
276+
# top_sensors = model1.get_selected_sensors()
277+
# print(top_sensors)
278+
# ## TODO: this can be done using ravel and unravel more elegantly
279+
# #yConstrained = np.floor(top_sensors[:n_const_sensors]/np.sqrt(n_features))
280+
# #xConstrained = np.mod(top_sensors[:n_const_sensors],np.sqrt(n_features))
281+
282+
# img = np.zeros(n_features)
283+
# img[top_sensors] = 16
284+
# #plt.plot(xConstrained,yConstrained,'*r')
285+
# plt.plot([xmin,xmin],[ymin,ymax],'r')
286+
# plt.plot([xmin,xmax],[ymax,ymax],'r')
287+
# plt.plot([xmax,xmax],[ymin,ymax],'r')
288+
# plt.plot([xmin,xmax],[ymin,ymin],'r')
289+
# plt.imshow(img.reshape(image_shape),cmap=plt.cm.binary)
290+
# plt.title('n_sensors = {}, n_constr_sensors = {}'.format(n_sensors,n_const_sensors))
291+
# plt.show()

pysensors/utils/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
from ._base import validate_input
22
from ._optimizers import constrained_binary_solve
33
from ._optimizers import constrained_multiclass_solve
4-
4+
from ._constraints import get_constraind_sensors_indices
5+
from ._constraints import get_constrained_sensors_indices_linear
6+
from ._constraints import box_constraints
7+
from ._constraints import functional_constraints
58

69
__all__ = [
710
"constrained_binary_solve",
811
"constrained_multiclass_solve",
912
"validate_input",
13+
"get_constraind_sensors_indices",
14+
"get_constrained_sensors_indices_linear",
15+
"box_constraints",
16+
"functional_constraints"
1017
]

0 commit comments

Comments
 (0)