1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """Implements the OPF model object used to encapsulate a given OPF
18 problem formulation.
19 """
20
21 from sys import stderr
22
23 from numpy import array, zeros, ones, Inf, dot, arange, r_
24 from numpy import flatnonzero as find
25 from scipy.sparse import lil_matrix, csr_matrix as sparse
26
27
29 """This class implements the OPF model object used to encapsulate
30 a given OPF problem formulation. It allows for access to optimization
31 variables, constraints and costs in named blocks, keeping track of the
32 ordering and indexing of the blocks as variables, constraints and costs
33 are added to the problem.
34
35 @author: Ray Zimmerman (PSERC Cornell)
36 @author: Richard Lincoln
37 """
38
40
41 self.ppc = ppc
42
43
44
45 self.var = {
46 'idx': {
47 'i1': {},
48 'iN': {},
49 'N': {}
50 },
51 'N': 0,
52 'NS': 0,
53 'data': {
54 'v0': {},
55 'vl': {},
56 'vu': {},
57 },
58 'order': []
59 }
60
61
62
63 self.nln = {
64 'idx': {
65 'i1': {},
66 'iN': {},
67 'N': {}
68 },
69 'N': 0 ,
70 'NS': 0,
71 'order': []
72 }
73
74
75
76 self.lin = {
77 'idx': {
78 'i1': {},
79 'iN': {},
80 'N': {}
81 },
82 'N': 0,
83 'NS': 0,
84 'data': {
85 'A': {},
86 'l': {},
87 'u': {},
88 'vs': {}
89 },
90 'order': []
91 }
92
93
94 self.cost = {
95 'idx': {
96 'i1': {},
97 'iN': {},
98 'N': {}
99 },
100 'N': 0,
101 'NS': 0,
102 'data': {
103 'N': {},
104 'H': {},
105 'Cw': {},
106 'dd': {},
107 'rh': {},
108 'kk': {},
109 'mm': {},
110 'vs': {}
111 },
112 'order': []
113 }
114
115 self.user_data = {}
116
117
119 """String representation of the object.
120 """
121 s = ''
122 if self.var['NS']:
123 s += '\n%-22s %5s %8s %8s %8s\n' % ('VARIABLES', 'name', 'i1', 'iN', 'N')
124 s += '%-22s %5s %8s %8s %8s\n' % ('=========', '------', '-----', '-----', '------')
125 for k in range(self.var['NS']):
126 name = self.var['order'][k]
127 idx = self.var['idx']
128 s += '%15d:%12s %8d %8d %8d\n' % (k, name, idx['i1'][name], idx['iN'][name], idx['N'][name])
129
130 s += '%15s%31s\n' % (('var[\'NS\'] = %d' % self.var['NS']), ('var[\'N\'] = %d' % self.var['N']))
131 s += '\n'
132 else:
133 s += '%s : <none>\n', 'VARIABLES'
134
135 if self.nln['NS']:
136 s += '\n%-22s %5s %8s %8s %8s\n' % ('NON-LINEAR CONSTRAINTS', 'name', 'i1', 'iN', 'N')
137 s += '%-22s %5s %8s %8s %8s\n' % ('======================', '------', '-----', '-----', '------')
138 for k in range(self.nln['NS']):
139 name = self.nln['order'][k]
140 idx = self.nln['idx']
141 s += '%15d:%12s %8d %8d %8d\n' % (k, name, idx['i1'][name], idx['iN'][name], idx['N'][name])
142
143 s += '%15s%31s\n' % (('nln.NS = %d' % self.nln['NS']), ('nln.N = %d' % self.nln['N']))
144 s += '\n'
145 else:
146 s += '%s : <none>\n', 'NON-LINEAR CONSTRAINTS'
147
148 if self.lin['NS']:
149 s += '\n%-22s %5s %8s %8s %8s\n' % ('LINEAR CONSTRAINTS', 'name', 'i1', 'iN', 'N')
150 s += '%-22s %5s %8s %8s %8s\n' % ('==================', '------', '-----', '-----', '------')
151 for k in range(self.lin['NS']):
152 name = self.lin['order'][k]
153 idx = self.lin['idx']
154 s += '%15d:%12s %8d %8d %8d\n' % (k, name, idx['i1'][name], idx['iN'][name], idx['N'][name])
155
156 s += '%15s%31s\n' % (('lin.NS = %d' % self.lin['NS']), ('lin.N = %d' % self.lin['N']))
157 s += '\n'
158 else:
159 s += '%s : <none>\n', 'LINEAR CONSTRAINTS'
160
161 if self.cost['NS']:
162 s += '\n%-22s %5s %8s %8s %8s\n' % ('COSTS', 'name', 'i1', 'iN', 'N')
163 s += '%-22s %5s %8s %8s %8s\n' % ('=====', '------', '-----', '-----', '------')
164 for k in range(self.cost['NS']):
165 name = self.cost['order'][k]
166 idx = self.cost['idx']
167 s += '%15d:%12s %8d %8d %8d\n' % (k, name, idx['i1'][name], idx['iN'][name], idx['N'][name])
168
169 s += '%15s%31s\n' % (('cost.NS = %d' % self.cost['NS']), ('cost.N = %d' % self.cost['N']))
170 s += '\n'
171 else:
172 s += '%s : <none>\n' % 'COSTS'
173
174
175
176
177
178
179
180 s += ' userdata = '
181 if len(self.user_data):
182 s += '\n'
183
184 s += str(self.user_data)
185
186 return s
187
188
190 """Adds a set of constraints to the model.
191
192 Linear constraints are of the form C{l <= A * x <= u}, where
193 C{x} is a vector made of of the vars specified in C{varsets} (in
194 the order given). This allows the C{A} matrix to be defined only
195 in terms of the relevant variables without the need to manually
196 create a lot of zero columns. If C{varsets} is empty, C{x} is taken
197 to be the full vector of all optimization variables. If C{l} or
198 C{u} are empty, they are assumed to be appropriately sized vectors
199 of C{-Inf} and C{Inf}, respectively.
200
201 For nonlinear constraints, the 3rd argument, C{N}, is the number
202 of constraints in the set. Currently, this is used internally
203 by PYPOWER, but there is no way for the user to specify
204 additional nonlinear constraints.
205 """
206 if u is None:
207
208 if name in self.nln["idx"]["N"]:
209 stderr.write("opf_model.add_constraints: nonlinear constraint set named '%s' already exists\n" % name)
210
211
212 self.nln["idx"]["i1"][name] = self.nln["N"]
213 self.nln["idx"]["iN"][name] = self.nln["N"] + AorN
214 self.nln["idx"]["N"][name] = AorN
215
216
217 self.nln["N"] = self.nln["idx"]["iN"][name]
218 self.nln["NS"] = self.nln["NS"] + 1
219
220
221
222 self.nln["order"].append(name)
223 else:
224
225 if name in self.lin["idx"]["N"]:
226 stderr.write('opf_model.add_constraints: linear constraint set named ''%s'' already exists\n' % name)
227
228 if varsets is None:
229 varsets = []
230
231 N, M = AorN.shape
232 if len(l) == 0:
233 l = -Inf * ones(N)
234
235 if len(u) == 0:
236 u = Inf * ones(N)
237
238 if len(varsets) == 0:
239 varsets = self.var["order"]
240
241
242 if (l.shape[0] != N) or (u.shape[0] != N):
243 stderr.write('opf_model.add_constraints: sizes of A, l and u must match\n')
244
245 nv = 0
246 for k in range(len(varsets)):
247 nv = nv + self.var["idx"]["N"][varsets[k]]
248
249 if M != nv:
250 stderr.write('opf_model.add_constraints: number of columns of A does not match\nnumber of variables, A is %d x %d, nv = %d\n' % (N, M, nv))
251
252
253 self.lin["idx"]["i1"][name] = self.lin["N"]
254 self.lin["idx"]["iN"][name] = self.lin["N"] + N
255 self.lin["idx"]["N"][name] = N
256 self.lin["data"]["A"][name] = AorN
257 self.lin["data"]["l"][name] = l
258 self.lin["data"]["u"][name] = u
259 self.lin["data"]["vs"][name] = varsets
260
261
262 self.lin["N"] = self.lin["idx"]["iN"][name]
263 self.lin["NS"] = self.lin["NS"] + 1
264
265
266
267 self.lin["order"].append(name)
268
269
271 """Adds a set of user costs to the model.
272
273 Adds a named block of user-defined costs to the model. Each set is
274 defined by the C{cp} dict described below. All user-defined sets of
275 costs are combined together into a single set of cost parameters in
276 a single C{cp} dict by L{build_cost_params}. This full aggregate set of
277 cost parameters can be retrieved from the model by L{get_cost_params}.
278
279 Let C{x} refer to the vector formed by combining the specified
280 C{varsets}, and C{f_u(x, cp)} be the cost at C{x} corresponding to the
281 cost parameters contained in C{cp}, where C{cp} is a dict with the
282 following fields::
283 N - nw x nx sparse matrix
284 Cw - nw x 1 vector
285 H - nw x nw sparse matrix (optional, all zeros by default)
286 dd, mm - nw x 1 vectors (optional, all ones by default)
287 rh, kk - nw x 1 vectors (optional, all zeros by default)
288
289 These parameters are used as follows to compute C{f_u(x, CP)}::
290
291 R = N*x - rh
292
293 / kk(i), R(i) < -kk(i)
294 K(i) = < 0, -kk(i) <= R(i) <= kk(i)
295 \ -kk(i), R(i) > kk(i)
296
297 RR = R + K
298
299 U(i) = / 0, -kk(i) <= R(i) <= kk(i)
300 \ 1, otherwise
301
302 DDL(i) = / 1, dd(i) = 1
303 \ 0, otherwise
304
305 DDQ(i) = / 1, dd(i) = 2
306 \ 0, otherwise
307
308 Dl = diag(mm) * diag(U) * diag(DDL)
309 Dq = diag(mm) * diag(U) * diag(DDQ)
310
311 w = (Dl + Dq * diag(RR)) * RR
312
313 f_u(x, CP) = 1/2 * w'*H*w + Cw'*w
314 """
315
316 if name in self.cost["idx"]["N"]:
317 stderr.write('opf_model.add_costs: cost set named \'%s\' already exists\n' % name)
318
319 if varsets is None:
320 varsets = []
321
322 if len(varsets) == 0:
323 varsets = self.var["order"]
324
325 nw, nx = cp["N"].shape
326
327
328 nv = 0
329 for k in range(len(varsets)):
330 nv = nv + self.var["idx"]["N"][varsets[k]]
331
332 if nx != nv:
333 if nw == 0:
334 cp["N"] = sparse(nw, nx)
335 else:
336 stderr.write('opf_model.add_costs: number of columns in N (%d x %d) does not match\nnumber of variables (%d)\n' % (nw, nx, nv))
337
338 if cp["Cw"].shape[0] != nw:
339 stderr.write('opf_model.add_costs: number of rows of Cw (%d x %d) and N (%d x %d) must match\n' % (cp["Cw"].shape[0], nw, nx))
340
341 if 'H' in cp:
342 if (cp["H"].shape[0] != nw) | (cp["H"].shape[1] != nw):
343 stderr.write('opf_model.add_costs: both dimensions of H (%d x %d) must match the number of rows in N (%d x %d)\n' % (cp["H"].shape, nw, nx))
344
345 if 'dd' in cp:
346 if cp["dd"].shape[0] != nw:
347 stderr.write('opf_model.add_costs: number of rows of dd (%d x %d) and N (%d x %d) must match\n' % (cp["dd"].shape, nw, nx))
348
349 if 'rh' in cp:
350 if cp["rh"].shape[0] != nw:
351 stderr.write('opf_model.add_costs: number of rows of rh (%d x %d) and N (%d x %d) must match\n' % (cp["rh"].shape, nw, nx))
352
353 if 'kk' in cp:
354 if cp["kk"].shape[0] != nw:
355 stderr.write('opf_model.add_costs: number of rows of kk (%d x %d) and N (%d x %d) must match\n' % (cp["kk"].shape, nw, nx))
356
357 if 'mm' in cp:
358 if cp["mm"].shape[0] != nw:
359 stderr.write('opf_model.add_costs: number of rows of mm (%d x %d) and N (%d x %d) must match\n' % (cp["mm"].shape, nw, nx))
360
361
362 self.cost["idx"]["i1"][name] = self.cost["N"]
363 self.cost["idx"]["iN"][name] = self.cost["N"] + nw
364 self.cost["idx"]["N"][name] = nw
365 self.cost["data"]["N"][name] = cp["N"]
366 self.cost["data"]["Cw"][name] = cp["Cw"]
367 self.cost["data"]["vs"][name] = varsets
368 if 'H' in cp:
369 self.cost["data"]["H"][name] = cp["H"]
370
371 if 'dd' in cp:
372 self.cost["data"]["dd"]["name"] = cp["dd"]
373
374 if 'rh' in cp:
375 self.cost["data"]["rh"]["name"] = cp["rh"]
376
377 if 'kk' in cp:
378 self.cost["data"]["kk"]["name"] = cp["kk"]
379
380 if 'mm' in cp:
381 self.cost["data"]["mm"]["name"] = cp["mm"]
382
383
384 self.cost["N"] = self.cost["idx"]["iN"][name]
385 self.cost["NS"] = self.cost["NS"] + 1
386
387
388 self.cost["order"].append(name)
389
390
391 - def add_vars(self, name, N, v0=None, vl=None, vu=None):
392 """ Adds a set of variables to the model.
393
394 Adds a set of variables to the model, where N is the number of
395 variables in the set, C{v0} is the initial value of those variables,
396 and C{vl} and C{vu} are the lower and upper bounds on the variables.
397 The defaults for the last three arguments, which are optional,
398 are for all values to be initialized to zero (C{v0 = 0}) and unbounded
399 (C{VL = -Inf, VU = Inf}).
400 """
401
402 if name in self.var["idx"]["N"]:
403 stderr.write('opf_model.add_vars: variable set named ''%s'' already exists\n' % name)
404
405 if v0 is None or len(v0) == 0:
406 v0 = zeros(N)
407
408 if vl is None or len(vl) == 0:
409 vl = -Inf * ones(N)
410
411 if vu is None or len(vu) == 0:
412 vu = Inf * ones(N)
413
414
415
416 self.var["idx"]["i1"][name] = self.var["N"]
417 self.var["idx"]["iN"][name] = self.var["N"] + N
418 self.var["idx"]["N"][name] = N
419 self.var["data"]["v0"][name] = v0
420 self.var["data"]["vl"][name] = vl
421 self.var["data"]["vu"][name] = vu
422
423
424 self.var["N"] = self.var["idx"]["iN"][name]
425 self.var["NS"] = self.var["NS"] + 1
426
427
428
429 self.var["order"].append(name)
430
431
433 """Builds and saves the full generalized cost parameters.
434
435 Builds the full set of cost parameters from the individual named
436 sub-sets added via L{add_costs}. Skips the building process if it has
437 already been done, unless a second input argument is present.
438
439 These cost parameters can be retrieved by calling L{get_cost_params}
440 and the user-defined costs evaluated by calling L{compute_cost}.
441 """
442
443 nw = self.cost["N"]
444
445
446
447
448
449
450
451
452
453 N = zeros((nw, self.var["N"]))
454 H = zeros((nw, nw))
455
456 Cw = zeros(nw)
457 dd = ones(nw)
458 rh = zeros(nw)
459 kk = zeros(nw)
460 mm = ones(nw)
461
462
463 for k in range(self.cost["NS"]):
464 name = self.cost["order"][k]
465 Nk = self.cost["data"]["N"][name]
466 i1 = self.cost["idx"]["i1"][name]
467 iN = self.cost["idx"]["iN"][name]
468 if self.cost["idx"]["N"][name]:
469 vsl = self.cost["data"]["vs"][name]
470 kN = 0
471 for v in vsl:
472 j1 = self.var["idx"]["i1"][v]
473 jN = self.var["idx"]["iN"][v]
474 k1 = kN
475 kN = kN + self.var["idx"]["N"][v]
476 N[i1:iN, j1:jN] = Nk[:, k1:kN].todense()
477
478 Cw[i1:iN] = self.cost["data"]["Cw"][name]
479 if name in self.cost["data"]["H"]:
480 H[i1:iN, i1:iN] = self.cost["data"]["H"][name].todense()
481
482 if name in self.cost["data"]["dd"]:
483 dd[i1:iN] = self.cost["data"]["dd"][name]
484
485 if name in self.cost["data"]["rh"]:
486 rh[i1:iN] = self.cost["data"]["rh"][name]
487
488 if name in self.cost["data"]["kk"]:
489 kk[i1:iN] = self.cost["data"]["kk"][name]
490
491 if name in self.cost["data"]["mm"]:
492 mm[i1:iN] = self.cost["data"]["mm"][name]
493
494 if nw:
495 N = sparse(N)
496 H = sparse(H)
497
498
499 self.cost["params"] = {
500 'N': N, 'Cw': Cw, 'H': H, 'dd': dd, 'rh': rh, 'kk': kk, 'mm': mm }
501
502
504 """ Computes a user-defined cost.
505
506 Computes the value of a user defined cost, either for all user
507 defined costs or for a named set of costs. Requires calling
508 L{build_cost_params} first to build the full set of parameters.
509
510 Let C{x} be the full set of optimization variables and C{f_u(x, cp)} be
511 the user-defined cost at C{x}, corresponding to the set of cost
512 parameters in the C{cp} dict returned by L{get_cost_params}, where
513 C{cp} is a dict with the following fields::
514 N - nw x nx sparse matrix
515 Cw - nw x 1 vector
516 H - nw x nw sparse matrix (optional, all zeros by default)
517 dd, mm - nw x 1 vectors (optional, all ones by default)
518 rh, kk - nw x 1 vectors (optional, all zeros by default)
519
520 These parameters are used as follows to compute C{f_u(x, cp)}::
521
522 R = N*x - rh
523
524 / kk(i), R(i) < -kk(i)
525 K(i) = < 0, -kk(i) <= R(i) <= kk(i)
526 \ -kk(i), R(i) > kk(i)
527
528 RR = R + K
529
530 U(i) = / 0, -kk(i) <= R(i) <= kk(i)
531 \ 1, otherwise
532
533 DDL(i) = / 1, dd(i) = 1
534 \ 0, otherwise
535
536 DDQ(i) = / 1, dd(i) = 2
537 \ 0, otherwise
538
539 Dl = diag(mm) * diag(U) * diag(DDL)
540 Dq = diag(mm) * diag(U) * diag(DDQ)
541
542 w = (Dl + Dq * diag(RR)) * RR
543
544 F_U(X, CP) = 1/2 * w'*H*w + Cw'*w
545 """
546 if name is None:
547 cp = self.get_cost_params()
548 else:
549 cp = self.get_cost_params(name)
550
551 N, Cw, H, dd, rh, kk, mm = \
552 cp["N"], cp["Cw"], cp["H"], cp["dd"], cp["rh"], cp["kk"], cp["mm"]
553 nw = N.shape[0]
554 r = N * x - rh
555 iLT = find(r < -kk)
556 iEQ = find((r == 0) & (kk == 0))
557 iGT = find(r > kk)
558 iND = r_[iLT, iEQ, iGT]
559 iL = find(dd == 1)
560 iQ = find(dd == 2)
561 LL = sparse((ones(len(iL)), (iL, iL)), (nw, nw))
562 QQ = sparse((ones(len(iQ)), (iQ, iQ)), (nw, nw))
563 kbar = sparse((r_[ ones(len(iLT)),
564 zeros(len(iEQ)),
565 -ones(len(iGT))], (iND, iND)), (nw, nw)) * kk
566 rr = r + kbar
567 M = sparse((mm[iND], (iND, iND)), (nw, nw))
568 diagrr = sparse((rr, (arange(nw), arange(nw))), (nw, nw))
569
570
571 w = M * (LL + QQ * diagrr) * rr
572
573 f = dot(w * H, w) / 2 + dot(Cw, w)
574
575 return f
576
577
579 """Returns the cost parameter struct for user-defined costs.
580
581 Requires calling L{build_cost_params} first to build the full set of
582 parameters. Returns the full cost parameter struct for all user-defined
583 costs that incorporates all of the named cost sets added via
584 L{add_costs}, or, if a name is provided it returns the cost dict
585 corresponding to the named set of cost rows (C{N} still has full number
586 of columns).
587
588 The cost parameters are returned in a dict with the following fields::
589 N - nw x nx sparse matrix
590 Cw - nw x 1 vector
591 H - nw x nw sparse matrix (optional, all zeros by default)
592 dd, mm - nw x 1 vectors (optional, all ones by default)
593 rh, kk - nw x 1 vectors (optional, all zeros by default)
594 """
595 if not 'params' in self.cost:
596 stderr.write('opf_model.get_cost_params: must call build_cost_params first\n')
597
598 cp = self.cost["params"]
599
600 if name is not None:
601 if self.getN('cost', name):
602 idx = arange(self.cost["idx"]["i1"][name], self.cost["idx"]["iN"][name])
603 cp["N"] = cp["N"][idx, :]
604 cp["Cw"] = cp["Cw"][idx]
605 cp["H"] = cp["H"][idx, :]
606 cp["dd"] = cp["dd"][idx]
607 cp["rh"] = cp["rh"][idx]
608 cp["kk"] = cp["kk"][idx]
609 cp["mm"] = cp["mm"][idx]
610
611 return cp
612
613
615 """ Returns the idx struct for vars, lin/nln constraints, costs.
616
617 Returns a structure for each with the beginning and ending
618 index value and the number of elements for each named block.
619 The 'i1' field (that's a one) is a dict with all of the
620 starting indices, 'iN' contains all the ending indices and
621 'N' contains all the sizes. Each is a dict whose keys are
622 the named blocks.
623
624 Examples::
625 [vv, ll, nn] = get_idx(om)
626
627 For a variable block named 'z' we have::
628 vv['i1']['z'] - starting index for 'z' in optimization vector x
629 vv['iN']['z'] - ending index for 'z' in optimization vector x
630 vv["N"] - number of elements in 'z'
631
632 To extract a 'z' variable from x::
633 z = x(vv['i1']['z']:vv['iN']['z'])
634
635 To extract the multipliers on a linear constraint set
636 named 'foo', where mu_l and mu_u are the full set of
637 linear constraint multipliers::
638 mu_l_foo = mu_l(ll['i1']['foo']:ll['iN']['foo'])
639 mu_u_foo = mu_u(ll['i1']['foo']:ll['iN']['foo'])
640
641 The number of nonlinear constraints in a set named 'bar'::
642 nbar = nn["N"].bar
643 (note: the following is preferable ::
644 nbar = getN(om, 'nln', 'bar')
645 ... if you haven't already called L{get_idx} to get C{nn}.)
646 """
647 vv = self.var["idx"]
648 ll = self.lin["idx"]
649 nn = self.nln["idx"]
650 cc = self.cost["idx"]
651
652 return vv, ll, nn, cc
653
654
656 """Returns the PYPOWER case dict.
657 """
658 return self.ppc
659
660
661 - def getN(self, selector, name=None):
662 """Returns the number of variables, constraints or cost rows.
663
664 Returns either the total number of variables/constraints/cost rows
665 or the number corresponding to a specified named block.
666
667 Examples::
668 N = getN(om, 'var') : total number of variables
669 N = getN(om, 'lin') : total number of linear constraints
670 N = getN(om, 'nln') : total number of nonlinear constraints
671 N = getN(om, 'cost') : total number of cost rows (in N)
672 N = getN(om, 'var', name) : number of variables in named set
673 N = getN(om, 'lin', name) : number of linear constraints in named set
674 N = getN(om, 'nln', name) : number of nonlinear cons. in named set
675 N = getN(om, 'cost', name) : number of cost rows (in N) in named set
676 """
677 if name is None:
678 N = getattr(self, selector)["N"]
679 else:
680 if name in getattr(self, selector)["idx"]["N"]:
681 N = getattr(self, selector)["idx"]["N"][name]
682 else:
683 N = 0
684 return N
685
686
687 - def getv(self, name=None):
688 """Returns initial value, lower bound and upper bound for opt variables.
689
690 Returns the initial value, lower bound and upper bound for the full
691 optimization variable vector, or for a specific named variable set.
692
693 Examples::
694 x, xmin, xmax = getv(om)
695 Pg, Pmin, Pmax = getv(om, 'Pg')
696 """
697 if name is None:
698 v0 = array([]); vl = array([]); vu = array([])
699 for k in range(self.var["NS"]):
700 name = self.var["order"][k]
701 v0 = r_[ v0, self.var["data"]["v0"][name] ]
702 vl = r_[ vl, self.var["data"]["vl"][name] ]
703 vu = r_[ vu, self.var["data"]["vu"][name] ]
704 else:
705 if name in self.var["idx"]["N"]:
706 v0 = self.var["data"]["v0"][name]
707 vl = self.var["data"]["vl"][name]
708 vu = self.var["data"]["vu"][name]
709 else:
710 v0 = array([])
711 vl = array([])
712 vu = array([])
713
714 return v0, vl, vu
715
716
718 """Builds and returns the full set of linear constraints.
719
720 Builds the full set of linear constraints based on those added by
721 L{add_constraints}::
722
723 L <= A * x <= U
724 """
725
726
727
728
729
730
731 if self.lin["N"]:
732 A = lil_matrix((self.lin["N"], self.var["N"]))
733 u = Inf * ones(self.lin["N"])
734 l = -u
735 else:
736 A = None
737 u = array([])
738 l = array([])
739
740 return A, l, u
741
742
743 for k in range(self.lin["NS"]):
744 name = self.lin["order"][k]
745 N = self.lin["idx"]["N"][name]
746 if N:
747 Ak = self.lin["data"]["A"][name]
748 i1 = self.lin["idx"]["i1"][name]
749 iN = self.lin["idx"]["iN"][name]
750 vsl = self.lin["data"]["vs"][name]
751 kN = 0
752
753 Ai = zeros((N, self.var["N"]))
754 for v in vsl:
755 j1 = self.var["idx"]["i1"][v]
756 jN = self.var["idx"]["iN"][v]
757 k1 = kN
758 kN = kN + self.var["idx"]["N"][v]
759 Ai[:, j1:jN] = Ak[:, k1:kN].todense()
760
761 A[i1:iN, :] = Ai
762
763 l[i1:iN] = self.lin["data"]["l"][name]
764 u[i1:iN] = self.lin["data"]["u"][name]
765
766 return A.tocsr(), l, u
767
768
770 """Used to save or retrieve values of user data.
771
772 This function allows the user to save any arbitrary data in the object
773 for later use. This can be useful when using a user function to add
774 variables, constraints, costs, etc. For example, suppose some special
775 indexing is constructed when adding some variables or constraints.
776 This indexing data can be stored and used later to "unpack" the results
777 of the solved case.
778 """
779 if val is not None:
780 self.user_data[name] = val
781 return self
782 else:
783 if name in self.user_data:
784 return self.user_data[name]
785 else:
786 return array([])
787