def sympy_solver(expr): # Sympy is buggy and slow. Use Transforms. symbols = get_symbols(expr) if len(symbols) != 1: raise ValueError('Expression "%s" needs exactly one symbol.' % (expr, )) if isinstance(expr, Relational): result = sympy.solveset(expr, domain=sympy.Reals) elif isinstance(expr, sympy.Or): subexprs = expr.args intervals = [sympy_solver(e) for e in subexprs] result = sympy.Union(*intervals) elif isinstance(expr, sympy.And): subexprs = expr.args intervals = [sympy_solver(e) for e in subexprs] result = sympy.Intersection(*intervals) elif isinstance(expr, sympy.Not): (notexpr, ) = expr.args interval = sympy_solver(notexpr) result = interval.complement(sympy.Reals) else: raise ValueError('Expression "%s" has unknown type.' % (expr, )) if isinstance(result, sympy.ConditionSet): raise ValueError('Expression "%s" is not invertible.' % (expr, )) return result
def transform_set(x, expr, sympy_set): """ Transform a sympy_set by an expression >>> x = sympy.Symbol('x') >>> domain = sympy.Interval(-sympy.pi / 4, -sympy.pi / 6, False, True) | sympy.Interval(sympy.pi / 6, sympy.pi / 4, True, False) >>> transform_set(x, -2 * x, domain) [-pi/2, -pi/3) U (pi/3, pi/2] """ if isinstance(sympy_set, sympy.Union): return sympy.Union( transform_set(x, expr, arg) for arg in sympy_set.args) if isinstance(sympy_set, sympy.Intersection): return sympy.Intersection( transform_set(x, expr, arg) for arg in sympy_set.args) f = sympy.Lambda(x, expr) if isinstance(sympy_set, sympy.Interval): left, right = f(sympy_set.left), f(sympy_set.right) if left < right: new_left_open = sympy_set.left_open new_right_open = sympy_set.right_open else: new_left_open = sympy_set.right_open new_right_open = sympy_set.left_open return sympy.Interval(sympy.Min(left, right), sympy.Max(left, right), new_left_open, new_right_open) if isinstance(sympy_set, sympy.FiniteSet): return sympy.FiniteSet(list(map(f, sympy_set)))
def get_domain(self, vector): """Combine the constraints into a single domain.""" domain = self.global_domain for cond in self.constraint.exprs: new_constraint = self.solve_constraint(cond, vector) if new_constraint is not True: domain = sp.Intersection(domain, new_constraint) return list(domain.boundary)
def manualSolveALessBLessC(A,B,C): """B is number, A and C are linear functions of X returns set of allowed X so A <= B <= C""" int1 = manualSolveSystem(A,B) int2 = manualSolveSystem(-C,-B) intersection = sympy.Intersection(int1, int2) if int1 == intersection: return (intersection, True) elif int2 == intersection: return (intersection, False) else: raise "This should never happen"
def solve_poly_equality_symbolically(expr, b): soln_lt = solve_poly_inequality_symbolically(expr, b, False) soln_gt = solve_poly_inequality_symbolically(-expr, -b, False) return sympy.Intersection(soln_lt, soln_gt)
def maximum_2(max_f, max_solution, max_combination, max_feasible_interval, max_interval, max3_f, max3_solution, max3_combination, max3_feasible_interval, max3_interval): # this function gets two arrays of maximum intervals and returns an overall maximum interval array # the concept is simillar to the function maximum_f() above. Only the starting point is the first # array, max_interval (instead the total feasible reagion of the constant ), # and the loop is over the second array (max3_interval) # this is used to combine intervals and maximums caculated by diffrent processors in case of parallel processing. # loop over all inetrvals in max3_interval for i_max3 in range(len(max3_interval)): # temporary storage for intervals and their values max2_f = [] max2_solution = [] max2_combination = [] max2_feasible_interval = [] max2_interval = [] # loop over all inetrvals in max_interval to be updated by max3_interval for i_max in range(len(max_interval)): # intersection of current maximum interval with each new maximum interval inter1 = sp.Intersection(max_interval[i_max], max3_interval[i_max3]) if inter1 == sp.EmptySet: # if there is no intersection keep current value max2_f.append(max_f[i_max]) max2_solution.append(max_solution[i_max]) max2_combination.append(max_combination[i_max]) max2_feasible_interval.append(max_feasible_interval[i_max]) max2_interval.append(max_interval[i_max]) else: # if there is intesection # check in which interval the new maximum is larger than the current one exp1 = sp.sympify(max3_f[i_max3] - max_f[i_max] > 0) exp1 = exp1.subs( {'s': 'd'} ) # becuase sympy is stupid and sometimes considers same 's' two variables. exp1 = exp1.subs({'d': 's'}) if exp1 == False: sol1_set = sp.EmptySet elif exp1 == True: sol1_set = sp.UniversalSet else: sol1 = solve(exp1) sol1_set = sol1.as_set() new_max_inter = sp.Intersection( inter1, sol1_set ) # intersection of interval that the new one is bigger and feasible if new_max_inter != sp.EmptySet: # if not empty make a new interval and keep the new maximum value as its maximum max2_f.append(max3_f[i_max3]) max2_solution.append(max3_solution[i_max3]) max2_combination.append(max3_combination[i_max3]) max2_feasible_interval.append( max3_feasible_interval[i_max3]) max2_interval.append(new_max_inter) max_comp_inter = sp.Complement( max_interval[i_max], new_max_inter) # complement of the updated interval if max_comp_inter != sp.EmptySet: # if complemet is not emty, ratain the previous maximum value for this complement interval max2_f.append(max_f[i_max]) max2_solution.append(max_solution[i_max]) max2_combination.append(max_combination[i_max]) max2_feasible_interval.append( max_feasible_interval[i_max]) max2_interval.append(max_comp_inter) else: # if there is no intersection between current interval and the interval that the new one is bigger ratin the current value max2_f.append(max_f[i_max]) max2_solution.append(max_solution[i_max]) max2_combination.append(max_combination[i_max]) max2_feasible_interval.append(max_feasible_interval[i_max]) max2_interval.append(max_interval[i_max]) # move from temporary storage to permanent max_f = max2_f.copy() max_solution = max2_solution.copy() max_combination = max2_combination.copy() max_feasible_interval = max2_feasible_interval.copy() max_interval = max2_interval.copy() return max_f, max_solution, max_combination, max_feasible_interval, max_interval
def maximum_f(feasible_f, feasible_solution, feasible_combination, feasible_interval, c2_exp, comm, p_n, p_i): # this function gets the array of optimum values and their feasible regions and comparing all of them finds # the maximum value for diffrent inetrvals of possible reagion of the constant. # the maximum value can be a number or a function of the constant. if c2_exp == []: # if there is no constants sol1_set = sp.Interval(0, 0) # set inetval else: # convert constarint on constants to set. This is the initial interval to be divided later for diffrent maximums sol1 = sp.solve(c2_exp) sol1_set = sol1.as_set() # here we define an array of intervals that have one interavl which is allowed region of the constant # We also set the optimum function value for this iterval to be negative infinity (-sp.oo) # later we update the arrays to have smaller inetrvals each with the optimum value for that interval # Outputs: # max_f: an array of maximum values for all the subintervals of possible interval of the constant # max_solution: to store the variable values for each interval # max_comb_id: keeping id for backward check # max_intersect_id: keeping id for backward check # max_opt_id: keeping id for backward check # max_feasible_id: keeping id for backward check # max_feasible_interval: list of intervals where the current maximum is feasible # (can be larger than interval below sincs below is both feasible and maximum) # max_interval: array of subintervals of the allowed region of the constant that has a distict maximum value save in max_f above. max_f = [-sp.oo] # set the maximum value of function to negative infinity max_solution = ["No answer" ] # to store the variable values for each maximum max_combination = ["No answer"] max_feasible_interval = ["No answer"] max_interval = [ sol1_set ] # set array of interval to have one member which is the allowed reagion of constant # t_p = t_print # # used to caculate total caculate time # start = time.time() # loop over all feasible solutions for i_f in range(len(feasible_f)): # max_2* arrays are used as temporary storages of maximum intervals and at the end of the loop are # copied to max* arrays max2_f = [] max2_sol = [] max2_combination = [] max2_feasible_interval = [] max2_interval = [] # loop over all previous intervals of maximum values saved in max* arrays for i_max in range(len(max_interval)): # intersection of current optimum interval with each previously calculated maximum interval inter1 = sp.Intersection(max_interval[i_max], feasible_interval[i_f]) if inter1 == sp.EmptySet: # if there is no intersection retain the current interval and associated maximum max2_f.append(max_f[i_max]) max2_sol.append(max_solution[i_max]) max2_combination.append(max_combination[i_max]) max2_feasible_interval.append(max_feasible_interval[i_max]) max2_interval.append(max_interval[i_max]) else: # if there is an intersection, find the interval that the new maximum is larger than the previous maximum exp1 = ( feasible_f[i_f] - max_f[i_max] ) > 0 # make an expersion to solve to see if current optimum is larger than previously found optimum for this interval exp1 = exp1.subs( {'s': 'd'} ) # becuase sympy is stupid and sometimes considers same 's' two variables. exp1 = exp1.subs({'d': 's'}) if exp1 == False: # new optimum is not larger anywhere sol1_set = sp.EmptySet elif exp1 == True: # new interval is always bigger sol1_set = sp.UniversalSet else: # if only larger on some interval, find the interval sol1 = solve(exp1) sol1_set = sol1.as_set() new_max_inter = sp.Intersection( inter1, sol1_set ) # define a new interval that is intersection of where the new optimum is larger and is feasible and whithin current maximum interval if new_max_inter != sp.EmptySet: # if this new interval is not empty append this interval and its f value to the list of intervals for maximum max2_f.append(feasible_f[i_f]) max2_sol.append(feasible_solution[i_f]) max2_combination.append(feasible_combination[i_f]) max2_feasible_interval.append(feasible_interval[i_f]) max2_interval.append(new_max_inter) max_comp_inter = sp.Complement( max_interval[i_max], new_max_inter ) # find the complement of the inetvarl above to retain the previous maxium value for the remaining interval if max_comp_inter != sp.EmptySet: # if remaining is not empty set add it to the array of maximums and retain the previous value for the maximum max2_f.append(max_f[i_max]) max2_sol.append(max_solution[i_max]) max2_combination.append(max_combination[i_max]) max2_feasible_interval.append( max_feasible_interval[i_max]) max2_interval.append(max_comp_inter) else: # if this new interval is empty retain the previous interval and its value as maximum max2_f.append(max_f[i_max]) max2_sol.append(max_solution[i_max]) max2_combination.append(max_combination[i_max]) max2_feasible_interval.append(max_feasible_interval[i_max]) max2_interval.append(max_interval[i_max]) # copy from temporary to permanent storage for the next iteration max_f = max2_f.copy() max_solution = max2_sol.copy() max_combination = max2_combination.copy() max_feasible_interval = max2_feasible_interval.copy() max_interval = max2_interval.copy() # print progress # t = time.time() - start # # # printing progress # if t > t_p : # perc = ((i_f+1)/(len(feasible_f)-1)*100) # if perc > 0: # t_left = t * (100 - perc) / perc # print("process",p_i, "maximum", int(perc), "% Time to finish:" , str(datetime.timedelta(seconds=int(t_left)) ) ) # t_p = t_p + t_print # # # caculate and print run time # end = time.time() # # print("process", p_i, " Maximum completed. Total time: ", str(datetime.timedelta(seconds=(end-start))) ) print("process", p_i, " Maximum completed.") # Outputs: # max_f: an array of maximum values for all the subintervals of possible interval of the constant # max_solution: to store the variable values for each interval # max_combination: keeping initial combination of constraints that lead to this. # max_feasible_interval: list of intervals where the current maximum is feasible # (can be larger than interval below sincs below is both feasible and maximum) # max_interval: array of subintervals of the allowed region of the constant that has a distict maximum value save in max_f above. return max_f, max_solution, max_combination, max_feasible_interval, max_interval
def ranging( DICp: Sequence[Sequence[Number]], c: Sequence[Number], dc: Sequence[Number], basic: Sequence[int], nonbasic: Sequence[int], ) -> None: DICp = np.array(DICp) c = np.array(c) dc = np.array(dc) basic = np.array(basic) nonbasic = np.array(nonbasic) zn = -DICp[0, 1:].reshape(-1, 1) basic = np.array(basic) - 1 nonbasic = np.array(nonbasic) - 1 dc_basic = dc[basic].reshape(-1, 1) dc_nonbasic = dc[nonbasic].reshape(-1, 1) BinvN = -DICp[1:, 1:] BinvNTcb = BinvN.T @ dc_basic dzn = BinvNTcb - dc_nonbasic print('Got dicitonary:') print_lp_dict(DICp, basic, nonbasic) print(f'\n-B{UTF["inv"]}N =') print(-BinvN) print() print(f'{UTF["Delta"]}c{UTF["T"]} = {dc.ravel()}') print(f'{UTF["Delta"]}c{UTF["_B"]}{UTF["T"]} = {dc_basic.ravel()}') print(f'{UTF["Delta"]}c{UTF["_N"]}{UTF["T"]} = {dc_nonbasic.ravel()}') print(f'\n(B{UTF["inv"]}N){UTF["T"]} =') print(BinvN.T) print() print( f'{UTF["Delta"]}z{UTF["_N"]}= ' f'(B{UTF["inv"]}N){UTF["T"]}{UTF["Delta"]}c{UTF["_B"]} - c{UTF["_N"]} =' ) print( f'{BinvNTcb.ravel()}{UTF["T"]} - {dc_nonbasic.ravel()}{UTF["T"]} = {dzn.ravel()}{UTF["T"]}' ) print( f'\nz*{UTF["_N"]} + t{UTF["Delta"]}z{UTF["_N"]} {UTF["geq"]} 0 {UTF["rarrow"]} ' f'{zn.ravel()}{UTF["T"]} + t{dzn.ravel()}{UTF["T"]} {UTF["geq"]} 0') print(UTF['rarrow']) for i, j in zip(zn.ravel(), dzn.ravel()): string = '' string += str(i) if j >= 0: string += ' +' elif j < 0: string += ' -' string += f' {abs(j)}t {UTF["geq"]} 0' print(string) t = sp.Symbol('t', real=True) polys = [(Poly(i + j * t), '>=') for i, j in zip(zn.ravel(), dzn.ravel()) if j != 0] result = sp.Intersection( *[s for p in polys for s in solve_poly_inequality(*p)]) # l for lower, u for upper l_bound, u_bound = result.left, result.right l_c = c + dc * l_bound u_c = c + dc * u_bound # Fix nans mask = l_c == sp.nan l_c[mask] = c[mask] mask = u_c == sp.nan u_c[mask] = c[mask] print() print(f'Respective to {UTF["Delta"]}c = {dc}') print(f'We see that we can vary c in:') print(l_c) print('to') print(u_c)