@@ -1988,6 +1988,11 @@ def region_diff(poly, reg, abs_tol=ABS_TOL, intersect_tol=ABS_TOL,
1988
1988
save = False ):
1989
1989
"""Subtract a region from a polytope
1990
1990
1991
+ For a discription of the algorithm, see algorithm 2 in:
1992
+ Mato Baotić "Polytopic computations in constrained optimal control"
1993
+ Automatika, 2009, Vol. 50, No. 3--4, pp. 119--134, 2009.
1994
+ https://hrcak.srce.hr/46543
1995
+
1991
1996
@param poly: polytope from which to subtract a region
1992
1997
@param reg: region which should be subtracted
1993
1998
@param abs_tol: absolute tolerance
@@ -2076,20 +2081,33 @@ def region_diff(poly, reg, abs_tol=ABS_TOL, intersect_tol=ABS_TOL,
2076
2081
ax .figure .savefig ('./img/res' + str (res_count ) + '.pdf' )
2077
2082
res_count += 1
2078
2083
if counter [level ] == 0 :
2084
+ # This is the first visit to this level
2079
2085
if save :
2080
2086
logger .debug ('counter[level] is 0' )
2081
2087
2088
+ # Go through all remaining polytopes that we want to remove and
2089
+ # check whether any of them removes anything from the current set
2090
+ # of hyperplanes (constraints)
2082
2091
for j in xrange (level , N ):
2092
+ # Construct a set of constraints with the current hyperplanes
2093
+ # and the hyperplanes of polytope j.
2094
+ # This is the intersection of the current hyperplanes and
2095
+ # polytope j
2083
2096
auxINDICES = np .hstack ([
2084
2097
INDICES ,
2085
2098
range (beg_mi [j ], beg_mi [j ] + mi [j ])
2086
2099
])
2087
2100
Adummy = A [auxINDICES , :]
2088
2101
bdummy = B [auxINDICES ]
2102
+ # Will polytope j remove anything from the current set of
2103
+ # hyperplanes?
2089
2104
R , _ = cheby_ball (Polytope (Adummy , bdummy ))
2090
2105
if R > abs_tol :
2106
+ # Yes, constrain the set of constraints with the negation
2107
+ # of one of polytope j's hyperplanes
2091
2108
level = j
2092
2109
counter [level ] = 1
2110
+ # Offset M negates hyperplanes
2093
2111
INDICES = np .hstack ([INDICES , beg_mi [level ] + M ])
2094
2112
break
2095
2113
if R < abs_tol :
@@ -2107,25 +2125,40 @@ def region_diff(poly, reg, abs_tol=ABS_TOL, intersect_tol=ABS_TOL,
2107
2125
range (beg_mi [level ], beg_mi [level ] + mi [level ])
2108
2126
])
2109
2127
else :
2128
+ # We have been at this level before
2110
2129
if save :
2111
2130
logger .debug ('counter[level] > 0' )
2112
2131
# counter(level) > 0
2113
2132
nzcount = np .nonzero (counter )[0 ]
2133
+ # Start from the deepest level and pop out of it if we are done at
2134
+ # that level
2114
2135
for jj in xrange (len (nzcount ) - 1 , - 1 , - 1 ):
2115
2136
level = nzcount [jj ]
2116
2137
counter [level ] += 1
2138
+ # Have we checked all hyperplanes?
2117
2139
if counter [level ] <= mi [level ]:
2140
+ # No
2141
+ # We have already handled the negative side of the last
2142
+ # hyperplane, so negate it to get the
2143
+ # positive side
2118
2144
INDICES [- 1 ] -= M
2145
+ # Add the next negative hyperplane of the polytope of the
2146
+ # current level
2119
2147
INDICES = np .hstack ([
2120
2148
INDICES ,
2121
2149
beg_mi [level ] + counter [level ] + M - 1
2122
2150
])
2151
+ # Stay at this level, since we haven't checked all
2152
+ # hyperplanes yet
2123
2153
break
2124
2154
else :
2155
+ # We have checked all hyperplanes at this level
2156
+ # Pop out of this level by resetting our states
2125
2157
counter [level ] = 0
2126
2158
INDICES = INDICES [0 :m + np .sum (counter )]
2127
2159
level -= 1
2128
2160
if level == - 1 :
2161
+ # We're done at all levels, return
2129
2162
if save :
2130
2163
if res :
2131
2164
ax = res .plot ()
@@ -2137,10 +2170,17 @@ def region_diff(poly, reg, abs_tol=ABS_TOL, intersect_tol=ABS_TOL,
2137
2170
return res
2138
2171
test_poly = Polytope (A [INDICES , :], B [INDICES ])
2139
2172
rc , _ = cheby_ball (test_poly )
2173
+ # Do we have a non-empty diff at this level?
2140
2174
if rc > abs_tol :
2141
2175
if level == N - 1 :
2176
+ # The diff is non-empty, and we have no more polytopes to
2177
+ # remove.
2178
+ # Add the current set of constraints to the result.
2142
2179
res = union (res , reduce (test_poly ), False )
2143
2180
else :
2181
+ # The diff is non-empty, but we need to check whether the
2182
+ # remaining polytopes remove anything.
2183
+ # Go one level deeper to continue the search.
2144
2184
level += 1
2145
2185
logger .debug ('returning res from end' )
2146
2186
return res
0 commit comments