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
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 |