Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

from __future__ import absolute_import 

from __future__ import division 

from builtins import range 

from builtins import object 

import numpy as np 

from gpkit import Variable, Monomial 

from gpkit.nomials import NomialMap 

from gpkit.small_classes import HashVector 

 

from robust.robust_gp_tools import RobustGPTools 

 

 

class EquivalentPosynomials(object): 

""" 

replaces a posynomial by an equivalent set of posynomials 

""" 

 

main_p = None 

p_uncertain_vars = [] 

p_indirect_uncertain_vars = [] 

m = None 

simple_model = None 

dependent_uncertainties = None 

 

no_data_constraints = [] 

data_constraints = [] 

 

def __init__(self, p, m, simple_model, dependent_uncertainties): 

""" 

:param p: the posynomial to be simplified 

:param m: the index of the posynomial 

:param simple_model: if a simple model is preferred 

:param dependent_uncertainties: if the uncertainty set is dependent or not 

""" 

self.simple_model = simple_model 

self.m = m 

self.dependent_uncertainties = dependent_uncertainties 

direct_p_uncertain_vars = [var for var in p.varkeys if RobustGPTools.is_directly_uncertain(var)] 

self.p_indirect_uncertain_vars = [var for var in p.varkeys if RobustGPTools.is_indirectly_uncertain(var)] 

 

new_direct_uncertain_vars = [] 

for var in self.p_indirect_uncertain_vars: 

new_direct_uncertain_vars += list(RobustGPTools.\ 

replace_indirect_uncertain_variable_by_equivalent(var.key.rel, 1).keys()) 

 

new_direct_uncertain_vars = [var for var in new_direct_uncertain_vars 

if RobustGPTools.is_directly_uncertain(var)] 

 

self.p_uncertain_vars = list(set(direct_p_uncertain_vars) | set(new_direct_uncertain_vars)) 

 

self.no_data_constraints = [] 

self.data_constraints = [] 

 

if len(p.exps[0]) == 0: 

self.main_p = p 

return 

 

number_of_p_uncertain_vars = len(self.p_uncertain_vars) 

if number_of_p_uncertain_vars == 0: 

self.no_data_constraints += [p <= 1] 

self.main_p = p 

return 

 

uncertain_vars_exps = [] 

uncertain_vars_exps_mons = [] 

 

# Determines the exponents and the location of exponents 

# of uncertain variables 

for i in range(len(p.exps)): 

m_uncertain_vars_exps = {} 

only_uncertain_vars_monomial_exps = RobustGPTools.\ 

only_uncertain_vars_monomial(p.exps[i]) 

 

for var in list(only_uncertain_vars_monomial_exps.keys()): 

if RobustGPTools.is_directly_uncertain(var): 

m_uncertain_vars_exps[var] = only_uncertain_vars_monomial_exps[var] 

if m_uncertain_vars_exps in uncertain_vars_exps: # if a given exponent on a variable exists 

index = uncertain_vars_exps.index(m_uncertain_vars_exps) 

uncertain_vars_exps_mons[index].append(i) 

else: 

uncertain_vars_exps.append(m_uncertain_vars_exps) # exponents 

uncertain_vars_exps_mons.append([i]) # locations 

 

all_data_mons = [] 

monomials = p.chop() 

for i, mon_list in enumerate(uncertain_vars_exps_mons): 

if len(mon_list) > 1 and uncertain_vars_exps[i]: 

# Really clunky way of creating monomials from exponents... 

# Should streamline/speed up in the future. 

new_no_data_posynomial = 0 

hmap = NomialMap({HashVector(uncertain_vars_exps[i]): 1.0}) 

unitarr = [k.units**v for k, v in uncertain_vars_exps[i].items() if k.units] 

try: 

hmap.units = np.prod(unitarr) 

except: 

hmap.units = unitarr[0].units 

uncertain_monomial = Monomial(hmap) 

for j in mon_list: 

new_no_data_posynomial += monomials[j]/uncertain_monomial 

com_variable = Variable('com_%s^%s' % (m, i)) 

# Add to no_data_constraints the constraints with zero uncertain variables 

self.no_data_constraints += [new_no_data_posynomial <= com_variable] 

all_data_mons.append(uncertain_monomial*com_variable) 

else: 

temp = sum([monomials[mon_ind] for mon_ind in mon_list]) 

all_data_mons.append(temp) 

 

# Redefine main_p and chop 

self.main_p = sum(all_data_mons) 

 

if len(self.main_p.exps) == 1: 

self.data_constraints += [self.main_p <= 1] 

return 

 

# if all(len(i) == 1 for i in uncertain_vars_exps_mons) and all(): 

# self.dependent_uncertainties = False 

 

if not simple_model: 

coupled_monomial_partitions = self.correlated_monomials() 

else: 

coupled_monomial_partitions = [] 

 

# Check if all the monomials are related: 

if len(coupled_monomial_partitions) != 0 and len(coupled_monomial_partitions[0]) == len(self.main_p.exps): 

self.data_constraints += [self.main_p <= 1] 

return 

 

ts = [] 

 

elements = list(range(len(self.main_p.exps))) 

singleton_monomials = [element for element in elements if 

not EquivalentPosynomials.check_if_in_list_of_lists(element, 

coupled_monomial_partitions)] 

main_monomials = self.main_p.chop() 

 

super_script = 0 

for i in singleton_monomials: 

 

if RobustGPTools.\ 

check_if_no_data(self.p_uncertain_vars + self.p_indirect_uncertain_vars, self.main_p.exps[i]): 

ts.append(main_monomials[i]) 

else: 

t = Variable('t_%s^%s' % (m, super_script)) 

super_script += 1 

ts.append(t) 

self.data_constraints += [main_monomials[i] <= t] 

 

for i in range(len(coupled_monomial_partitions)): 

if coupled_monomial_partitions[i]: 

posynomial = 0 

t = Variable('t_%s^%s' % (m, super_script)) 

super_script += 1 

ts.append(t) 

for j in coupled_monomial_partitions[i]: 

posynomial += main_monomials[j] 

self.data_constraints += [posynomial <= t] 

 

self.no_data_constraints += [sum(ts) <= 1] 

 

return 

 

@staticmethod 

def merge_intersected_lists(coupled_partition): 

""" 

merges a list of lists so that the resulting list of lists is a partition 

:param coupled_partition: the list of lists to be merged 

:return: the partition 

""" 

l = len(coupled_partition) 

if l <= 1: 

return coupled_partition 

 

half = int(np.floor(l / 2.0)) 

 

first_half_partitions = EquivalentPosynomials.merge_intersected_lists(coupled_partition[0:half]) 

second_half_partitions = EquivalentPosynomials.merge_intersected_lists(coupled_partition[half:l]) 

 

len_first, len_second = len(first_half_partitions), len(second_half_partitions) 

 

relations, path = {}, {} 

 

first_to_delete, second_to_delete = set(), set() 

 

i = 0 

while i < len_first: 

j = 0 

while j < len_second: 

if list(set(first_half_partitions[i]) & set(second_half_partitions[j])): 

second_to_delete.add(j) 

temp_one = i 

while temp_one in path: 

temp_one = path[temp_one] # i] 

first_half_partitions[temp_one] = \ 

list(set(first_half_partitions[temp_one]) | set(second_half_partitions[j])) 

if j in relations: 

temp_two = relations[j] 

while temp_two in path: 

temp_two = path[temp_two] # i] 

if temp_two != temp_one: 

first_to_delete.add(temp_one) 

path[temp_one] = temp_two 

first_half_partitions[temp_two] = \ 

list(set(first_half_partitions[temp_two]) | set(first_half_partitions[temp_one])) 

else: 

relations[j] = temp_one 

j += 1 

i += 1 

 

first_to_delete = list(first_to_delete) 

first_to_delete.reverse() 

second_to_delete = list(second_to_delete) 

second_to_delete.reverse() 

 

for k in first_to_delete: 

del first_half_partitions[k] 

for k in second_to_delete: 

del second_half_partitions[k] 

 

return first_half_partitions + second_half_partitions 

 

@staticmethod 

def same_sign(a): 

""" 

Checks if the elements of a have the same sign 

:param a: the list to be checked 

:return: True or False 

""" 

j = 0 

while j < len(a): 

if a[j] == 0: 

j += 1 

else: 

break 

 

if j == len(a): 

return True 

 

for i in range(len(a) - 1): 

if a[j] * a[i + 1] < 0: 

return False 

return True 

 

def correlated_monomials(self): 

""" 

Creates partitions of correlated monomials 

:return: the list of coupled partitions 

""" 

number_of_monomials = len(self.main_p.exps) 

coupled_partition = [] 

 

if self.dependent_uncertainties: 

for j in range(number_of_monomials): 

 

only_uncertain_vars_monomial_exps = RobustGPTools.\ 

only_uncertain_vars_monomial(self.main_p.exps[j]) 

 

for var in self.p_uncertain_vars: 

if var.key in only_uncertain_vars_monomial_exps: 

coupled_partition.append(j) 

break 

return [coupled_partition] 

 

else: 

for var in self.p_uncertain_vars: 

partition = [] 

check_sign = [] 

 

for j in range(number_of_monomials): 

 

only_uncertain_vars_monomial_exps = RobustGPTools.\ 

only_uncertain_vars_monomial(self.main_p.exps[j]) 

 

if var in only_uncertain_vars_monomial_exps: 

 

partition.append(j) 

check_sign.append(only_uncertain_vars_monomial_exps.get(var.key)) 

 

if not EquivalentPosynomials.same_sign(check_sign): 

coupled_partition.append(partition) 

 

coupled_partition = EquivalentPosynomials.merge_intersected_lists(coupled_partition) 

return coupled_partition 

 

@staticmethod 

def check_if_in_list_of_lists(element, list_of_lists): 

for i in range(len(list_of_lists)): 

if element in list_of_lists[i]: 

return True 

return False 

 

if __name__ == '__main__': 

pass