-
Notifications
You must be signed in to change notification settings - Fork 0
/
conclasses.py
142 lines (135 loc) · 5.54 KB
/
conclasses.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env python
"""
Class definitions for constraint set
Author: Andre Campher
"""
# Dependencies: - convertfuns
# - auxfuns
# - SciPy
from auxfuns import qhull, mat2ab, uniqm, splitAb
from convertfuns import vert2con, con2vert
from scipy import empty, vstack, dot, tile, all, zeros, sqrt, sum, c_, sign
from scipy import mat, ones, linalg, array
from scipy import all as sciall
import numpy
class ConSet:
"""
Class for constraint sets. Generated by either a constraint set [A s b] or
by a set of vertices [v].
"""
def __init__(self, *inargs):
if len(inargs) == 1:
self.vert = inargs[0]
self.A, self.s, self.b = vert2con(self.vert)
self.closed = True
elif len(inargs) == 3:
if all(sign(inargs[1]) == -1): # ensure an all -1 sign vector
self.A, self.s, self.b = inargs
else:
self.A, self.s, self.b = mat2ab(c_[inargs])
self.vert, self.closed = con2vert(self.A, self.b)
else:
exit(1) # TODO: Raise exception
self.nd = self.A.shape[1]
self.cscent = sum(self.vert, axis=0)/len(self.vert)
def vol(self):
"""Return 'volume' of feasible region."""
return qhull(self.vert,"FS")
def oi(self, conset2):
"""
Return the Operabilty Index (Vinson, 2000) of the set, where conset2
is equivalent to the DOS
"""
Vint = ConSet(*self.intersect(conset2)).vol()
return Vint/conset2.vol()
def outconlin(self, model, iss, oss):
"""
Convert constraints to another space using a linear model
e.g. calc AOS (from G and AIS).
iss [vector] - nominal steady state of current space ("from")
oss [vector] - nominal steady state of transformed space ("to")
"""
outverttemp = empty([1, self.vert.shape[1]])
# handle shifting
ishift = self.cscent - iss #input space dev
oshift = model*ishift.T #output space dev
fshift = oshift.T + oss #output space offset
# center 'input'-space around [0]
inverttemp = self.vert - self.cscent
for v in inverttemp:
x = model*v.transpose()
outverttemp = vstack((outverttemp, x.transpose()))
# remove first line of junk data from outverttemp and shift
outverttemp = outverttemp + fshift
return vert2con(outverttemp[1:, :])
def intersect(self, conset2):
"""Determine intersection between current constraint set and another"""
def remredcons(A, b, verts):
"""Reduce a constraint set by removing unnecessary constraints."""
eps = 10e-9
#1 Co-planar constraints;
# Remove as not to affect 3rd check
Ab = c_[A, b]
Abnorms = ones((Ab.shape[0], 1))
for i in range(Ab.shape[0]):
Abnorms[i] = linalg.norm(Ab[i, :])
Abn = Ab/Abnorms
Abkeep = ones((0, Ab.shape[1]))
Abtest = ones((0, Ab.shape[1]))
for r1 in range(Abn.shape[0]):
noocc = ones((1, 0))
for r2 in range(Abn.shape[0]):
#print abs(Abn[r1, :] - Abn[r2, :])
if numpy.all(abs(Abn[r1, :] - Abn[r2, :]) < eps):
noocc = c_[noocc, r2]
if noocc.size == 1:
Abtest = vstack([Abtest, Ab[r1, :]])
else:
Abkeep = vstack([Abkeep, Ab[r1, :]])
if Abkeep.shape[0] > 1:
Abkeep = uniqm(Abkeep, eps)
#2 Vert subset satisfying; no action needed (redundancy uncertain)
#3 All vert satisfying constraints;
A, b = splitAb(array(Abtest).ravel(), verts.shape[1])
keepA = ones((0, A.shape[1]))
keepb = ones((0, 1))
bt = tile(b, (1, verts.shape[0]))
k = mat(A)*mat(verts.T) - bt
kk = sum(k > eps, axis=1)
for i in range(len(kk)):
if kk[i] != 0:
keepA = vstack([keepA, A[i, :]])
keepb = vstack([keepb, b[i, :]])
outAb = vstack([c_[keepA, keepb], Abkeep])
return splitAb(outAb.ravel(), verts.shape[1])
#Combine constraints and vertices
combA = vstack((self.A, conset2.A))
combb = vstack((self.b, conset2.b))
combv = vstack((self.vert, conset2.vert))
#Remove redundant constraints
ncombA, ncombb = remredcons(combA, combb, combv)
#Calc and return intersection
intcombvert = con2vert(combA, combb)[0]
return intcombvert
def allinside(self, conset2):
"""
Determine if all vertices of self is within conset2. allvinside merely
returns True/False whereas insidenorm returns a measure of 'inside-ness'
better suited for optimisers.
"""
# Inside check
Av = dot(conset2.A, self.vert.T)
bv = tile(conset2.b, (1, self.vert.shape[0]))
eps = 1e-13
intmpvals = Av - bv
intmp = intmpvals <= eps
allvinside = sciall(intmp)
# Inside norm
insidenorm = zeros((Av.shape[0], 1))
for cons in range(Av.shape[0]):
for verts in range(Av.shape[1]):
dist = abs(intmpvals[cons, verts])/sqrt(sum(conset2.A[cons, :]**2))
if not intmp[cons, verts]: # outside
insidenorm[cons] = insidenorm[cons] - dist
# Outside volume
return allvinside, insidenorm#, outsidevol