def inverterLoopTanh(numInverters, numSolutions="all", a=-5.0): epsilon = 1e-14 start = time.time() vs = [] for i in range(numInverters): vs.append(Variable("v" + str(i))) allConstraints = [] # Store rambus oscillator constraints for i in range(numInverters): allConstraints.append(vs[i] >= -1) allConstraints.append(vs[i] <= 1) inputInd = i outputInd = (i + 1) % numInverters allConstraints.append(tanh(a * vs[inputInd]) - vs[outputInd] == 0.0) allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] for i in range(numInverters): singleExcludingConstraints.append(vs[i] < solution[i][0]) singleExcludingConstraints.append(vs[i] > solution[i][1]) excludingConstraints.append(singleExcludingConstraints) # Add all the rambus oscillator constraints f_sat = logical_and(*allConstraints) # Add constraints so that old hyperrectangles are not considered if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((numInverters, 2)) for i in range(numInverters): hyper[i, :] = [ result[vs[i]].lb() - 2 * epsilon, result[vs[i]].ub() + 2 * epsilon ] #print ("hyper", hyper) allSolutions.append(hyper) print("num solutions found", len(allSolutions)) end = time.time() print("time taken", end - start) return allSolutions
def inverterScMosfet(inputVoltage, numSolutions="all"): epsilon = 1e-14 start = time.time() Vdd = 1.0 sn = 3 sp = 2 * sn outputVolt = Variable("outputVolt") iP = Variable("iP") iN = Variable("iN") allConstraints = [] allConstraints.append(outputVolt >= 0.0) allConstraints.append(outputVolt <= Vdd) allConstraints.append(-iP - iN == 0) allConstraints += mvs_id("n", 0.0, inputVoltage, outputVolt, iN, sn) allConstraints += mvs_id("p", Vdd, inputVoltage, outputVolt, iP, sp) allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] singleExcludingConstraints.append(outputVolt < solution[0][0]) singleExcludingConstraints.append(outputVolt > solution[0][1]) excludingConstraints.append(singleExcludingConstraints) #print ("allConstraints") #print (allConstraints) f_sat = logical_and(*allConstraints) if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((1, 2)) hyper[0, :] = [ result[outputVolt].lb() - 2 * epsilon, result[outputVolt].ub() + 2 * epsilon ] #print ("hyper", hyper) allSolutions.append(hyper) print("num solutions found", len(allSolutions)) end = time.time() print("time taken", end - start) return allSolutions
def exampleFun(numSolutions="all"): start = time.time() epsilon = 1e-14 lenV = 1 x = Variable('x') allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break allConstraints = [] allConstraints.append(2 * x * asin(cos(0.797) * sin(math.pi / x)) - 0.0331 * x >= 2 * math.pi - 2.097) allConstraints.append(x >= 3) allConstraints.append(x <= 64) excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] singleExcludingConstraints.append(x <= solution[0][0]) singleExcludingConstraints.append(x >= solution[0][1]) excludingConstraints.append(singleExcludingConstraints) #print ("allConstraints") #print (allConstraints) #print ("numConstraints", len(allConstraints)) f_sat = logical_and(*allConstraints) if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((1, 2)) hyper[0, :] = [ result[x].lb() - 2 * epsilon, result[x].ub() + 2 * epsilon ] print("hyper", hyper) allSolutions.append(hyper) print("num solutions found", len(allSolutions)) '''constraints = [] x = Variable('x') #constraints.append(x >= 0.0) #constraints.append(x <= 64.0) constraints.append(2*math.pi - 2*x*asin(cos(0.797)*sin(math.pi/x)) == 2.097 - 0.0331*x) f_sat = logical_and(*constraints) result = CheckSatisfiability(f_sat, epsilon) print (result)''' end = time.time() print("time taken", end - start)
def inverterTanh(inputVoltage, a=-5.0, numSolutions="all"): epsilon = 1e-14 start = time.time() outputVolt = Variable("outputVolt") allConstraints = [] allConstraints.append(outputVolt >= -1.0) allConstraints.append(outputVolt <= 1.0) allConstraints.append(tanh(a * inputVoltage) - outputVolt == 0) allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] singleExcludingConstraints.append(outputVolt < solution[0][0]) singleExcludingConstraints.append(outputVolt > solution[0][1]) excludingConstraints.append(singleExcludingConstraints) #print ("allConstraints") #print (allConstraints) f_sat = logical_and(*allConstraints) if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((1, 2)) hyper[0, :] = [ result[outputVolt].lb() - 2 * epsilon, result[outputVolt].ub() + 2 * epsilon ] #print ("hyper", hyper) allSolutions.append(hyper) print("num solutions found", len(allSolutions)) end = time.time() print("time taken", end - start) return allSolutions
def calculate_port_flow_rate(dg, port_name): """Calculate the flow rate into a port based on the cross sectional area of the channel it flows into, the pressure and the density eqn from https://en.wikipedia.org/wiki/Hagen-Poiseuille_equation flow_rate = area * sqrt(2*pressure/density) Unit for flow rate is m^3/s :param str port_name: Name of the port :returns: Flow rate determined from port pressure and area of connected channels """ areas = [] port_pressure = retrieve(dg, port_name, 'pressure') port_density = retrieve(dg, port_name, 'density') port_flow_rate = retrieve(dg, port_name, 'flow_rate') # Calculate cross sectional area of all channels flowing into this port for port_out in dg.succ[port_name]: areas.append( retrieve(dg, (port_name, port_out), 'height') * retrieve(dg, (port_name, port_out), 'width')) # Add together all these areas if multiple exist if len(areas) == 1: total_area = areas[0] else: areas = [a + b for a, b in zip(areas, areas[1:])] total_area = logical_and(*areas) return (port_flow_rate**2 == (total_area**2) * ((2 * port_pressure) / port_density))
def test_lorentz_cone(self): config = Config() config.use_local_optimization = True config.precision = 0.0001 result = Minimize( x2, logical_and(-5 <= x0, x0 <= 5, -5 <= x1, x1 <= 5, 0 <= x2, x2 <= 5, 1 >= (x0 - 1)**2 + (x1 - 1)**2, x2**2 >= x0**2 + x1**2), config) self.assertTrue(result) self.assertAlmostEqual(result[x2].mid(), 0.414212, places=3)
def test_minimize_via_forall(self): # To minimize f(X) s.t. φ(x), this test encodes # the problem into a first-order logic formula. # # ∃X. φ(X) ∧ [∀Y φ(Y) ⇒ (f(X) ≤ f(Y))] # # Here we use f(x) = sin(x)cos(x) # φ(X) = (0 ≤ x) ∧ (x ≤ π) def f(x): return sin(x) * cos(x) def phi(x): return logical_and(0 <= x, x <= math.pi) problem = logical_and( phi(x), forall([y], logical_and(logical_imply(phi(y), f(x) <= f(y))))) result = CheckSatisfiability(problem, 0.01) self.assertTrue(result) self.assertAlmostEqual(result[x].mid(), math.pi * 3 / 4, places=3)
def test_logical(self): f1 = (x == 0) f2 = (y == 0) self.assertEqual(str(logical_not(f1)), "!((x = 0))") self.assertEqual(str(logical_imply(f1, f2)), str(logical_or(logical_not(f1), f2))) self.assertEqual( str(logical_iff(f1, f2)), str(logical_and(logical_imply(f1, f2), logical_imply(f2, f1)))) # Test single-operand logical statements self.assertEqual(str(logical_and(x >= 1)), "(x >= 1)") self.assertEqual(str(logical_or(x >= 1)), "(x >= 1)") # Test binary operand logical statements self.assertEqual(str(logical_and(x >= 1, x <= 2)), "((x >= 1) and (x <= 2))") self.assertEqual(str(logical_or(x <= 1, x >= 2)), "((x >= 2) or (x <= 1))") # Test multiple operand logical statements self.assertEqual(str(logical_and(x >= 1, x <= 2, y == 2)), "((y = 2) and (x >= 1) and (x <= 2))") self.assertEqual(str(logical_or(x >= 1, x <= 2, y == 2)), "((y = 2) or (x >= 1) or (x <= 2))")
def test_02_Rosenbrock_Disk(self): (vars, domain) = make_domain([("x", -1.5, 1.5), ("y", -1.5, 1.5)]) [x, y] = vars def objective(x, y): return (1 - x)**2 + 100 * (y - x**2)**2 constraints = logical_and(domain, x**2 + y**2 < 2) sol = Minimize(objective(*vars), constraints, self.config) self.global_min = 0.0 self.assertIsNotNone(sol) self.found_min = compute_min(objective, sol, vars) self.assertAlmostEqual(self.found_min, self.global_min, delta=self.config.precision * 2)
def test_05_Simionescu(self): (vars, domain) = make_domain([("x", -1.25, 1.25), ("y", -1.25, 1.25)]) [x, y] = vars def objective(x, y): return 0.1 * x * y constraints = logical_and( domain, x**2 + y**2 <= (1 + 0.2 * cos(8 * atan(x / y)))**2) sol = Minimize(objective(*vars), constraints, self.config) self.global_min = -0.072625 self.assertIsNotNone(sol) self.found_min = compute_min(objective, sol, vars) self.assertAlmostEqual(self.found_min, self.global_min, delta=self.config.precision * 10)
def test_03_Mishra_Bird(self): (vars, domain) = make_domain([("x", -10, 0.0), ("y", -6.5, 0.0)]) [x, y] = vars def objective(x, y): return sin(y) * exp((1 - cos(x))**2) + cos(x) * exp( (1 - sin(y))**2) + (x - y)**2 constraints = logical_and(domain, (x + 5)**2 + (y + 5)**2 < 25) sol = Minimize(objective(*vars), constraints, self.config) self.global_min = -106.7645367 self.assertIsNotNone(sol) self.found_min = compute_min(objective, sol, vars) self.assertAlmostEqual(self.found_min, self.global_min, delta=self.config.precision * 2)
def test_04_Townsend(self): (vars, domain) = make_domain([("x", -2.25, 2.5), ("y", -2.5, 1.75)]) [x, y] = vars def objective(x, y): return -(cos((x - 0.1) * y))**2 - x * sin(3 * x + y) constraints = logical_and( domain, x**2 + y**2 < (2 * cos(atan2(x, y)) - 0.5 * cos(2 * atan2(x, y)) - 0.25 * cos(3 * atan2(x, y)) - 0.125 * cos(4 * atan2(x, y)))**2 + (2 * sin(atan2(x, y)))**2) sol = Minimize(objective(*vars), constraints, self.config) self.global_min = -2.0239884 self.assertIsNotNone(sol) self.found_min = compute_min(objective, sol, vars) self.assertAlmostEqual(self.found_min, self.global_min, delta=self.config.precision * 2)
def invoke_backend(self, _show): """Combine all of the SMT expressions into one expression to sent to dReal solver to determine solvability :param bool show: If true then the full SMT formula that was created is printed :returns: dReal model showing the values for each of the parameters """ formula = logical_and(*self.exprs) # Prints the generated formula in full, remove serialize for shortened if _show: # nx.draw(self.dg) # plt.show() print(formula) # Return None if not solvable, returns a dict-like structure giving the # range of values for each Variable model = CheckSatisfiability(formula, 10) if model: return model else: return "No solution found"
def translate_output(dg, name): """Create SMT expressions for bounding the parameters of an output port to be within the constraints defined by the user :param str name: Name of the port to be constrained :returns: None -- no issues with translating the port parameters to SMT """ exprs = [] if dg.size(name) <= 0: raise ValueError("Port %s must have 1 or more connections" % name) # Currently don't support this, and I don't think it would be the case # in real circuits, an output port is considered the end of a branch if len(list(dg.succ[name])) != 0: raise ValueError("Cannot have channels out of output port %s" % name) # Since input is just a specialized node, call translate node [exprs.append(val) for val in translate_node(dg, name)] # Calculate flow rate for this port based on pressure and channels out # if not specified by user if not algorithms.retrieve(dg, name, 'min_flow_rate'): # The flow rate at this node is the sum of the flow rates of the # the channel coming in (I think, should be verified) total_flow_in = [] for channel_in in dg.pred[name]: total_flow_in.append(dg.edges[(channel_in, name)]['flow_rate']) if len(total_flow_in) == 1: exprs.append( algorithms.retrieve(dg, name, 'flow_rate') == total_flow_in[0]) else: total_flow_in_formulas = [ a + b for a, b in zip(total_flow_in, total_flow_in[1:]) ] exprs.append( algorithms.retrieve(dg, name, 'flow_rate') == logical_and( *total_flow_in_formulas)) return exprs
def translate_ep_cross(dg, name, fluid_name='default'): """Create SMT expressions for an electrophoretic cross :param str name: the name of the junction node in the electrophoretic cross :returns: None -- no issues with translating channel parameters to SMT :raises: ValueError if the analyte_properties are not defined properly TypeError if the analyte_properties are not floats or ints """ # work in progress exprs = [] # Validate input if dg.size(name) != 4: raise ValueError("Electrophoretic Cross %s must have 4 connections" % name) # Electrophoretic Cross is a type of node, so call translate node [exprs.append(val) for val in translate_node(dg, name)] # Because it's done in translate_tjunc ep_cross_node_name = name # figure out which nodes are for sample injection and which are for separation channel # assume single input node, 3 output nodes, one junction node # assume separation and tail channels are specified by user phases = nx.get_edge_attributes(dg, 'phase') for edge, phase in phases.items(): # assuming only one separation channel, and only 1 tail channel if phase == 'separation': separation_channel_name = edge anode_node_name = edge[1] elif phase == 'tail': tail_channel_name = edge cathode_node_name = edge[ edge[0] == ep_cross_node_name] # returns whichever tuple element is NOT the ep_cross node # is there a better way to do this? node_kinds = nx.get_node_attributes(dg, 'kind') for node, kind in node_kinds.items(): if node not in separation_channel_name and node not in tail_channel_name: if kind == 'input': injection_channel_name = (node, ep_cross_node_name) injection_node_name = node # necessary? elif kind == 'output': waste_channel_name = (ep_cross_node_name, node) waste_node_name = node # necessary? # assert dimensions: # assert width and height of tail channel to be equal to separation channel exprs.append( algorithms.retrieve(dg, tail_channel_name, 'width') == algorithms.retrieve(dg, separation_channel_name, 'width')) exprs.append( algorithms.retrieve(dg, tail_channel_name, 'height') == algorithms.retrieve(dg, separation_channel_name, 'height')) # assert width and height of injection channel to be equal to waste channel exprs.append( algorithms.retrieve(dg, injection_channel_name, 'width') == algorithms.retrieve(dg, waste_channel_name, 'width')) exprs.append( algorithms.retrieve(dg, injection_channel_name, 'height') == algorithms.retrieve(dg, waste_channel_name, 'height')) # assert height of separation channel and injection channel are same exprs.append( algorithms.retrieve(dg, injection_channel_name, 'height') == algorithms.retrieve(dg, separation_channel_name, 'height')) # electric field E = Variable('E') exprs.append(E < 1000000) exprs.append(E > 0) exprs.append(E == algorithms.calculate_electric_field( dg, anode_node_name, cathode_node_name)) # only works if cathode is an input? only works for paths that are true in directed graph # assume that the analyte parameters were included in the injection port # need to validate that the data exists? D = algorithms.retrieve(dg, injection_node_name, 'analyte_diffusivities') C0 = algorithms.retrieve(dg, injection_node_name, 'analyte_initial_concentrations') q = algorithms.retrieve(dg, injection_node_name, 'analyte_charges') r = algorithms.retrieve(dg, injection_node_name, 'analyte_radii') analyte_properties = { 'analyte_diffusivities': D, 'analyte_initial_concentrations': C0, 'analyte_charges': q, 'analyte_radii': r } for property_name, values in analyte_properties.items(): # check if something is defined, otherwise should be set to false if not values: raise ValueError( 'No values defined for %s in electrophoretic cross node %s' % (property_name, ep_cross_node_name)) # make sure all the values are either ints or floats if not all(isinstance(x, (int, float)) for x in values): raise TypeError( "%s values in electrophoretic cross node '%s' must be numbers" % (property_name, ep_cross_node_name)) # n = number of analytes n = len(D) for property_name, values in analyte_properties.items(): # check that they all have the same number of values n_to_check = len(values) if not (n_to_check == n): raise ValueError( "Expecting %s values, and found %s for %s in node: '%s'" % (n, n_to_check, property_name, ep_cross_node_name)) delta = algorithms.retrieve(dg, separation_channel_name, 'min_sampling_rate') x_detector = algorithms.retrieve(dg, separation_channel_name, 'x_detector') # These are currently set as parameters to the node function # all are constants, numbers between 0 and 1 # brief descriptions: # lower c, more discernable concentration peaks # higher p, any given conc. peak must be higher (closer to max conc.) # qf is arbitrary, rule of thumb qf = 0.9 (called q in Stephen Chou's paper) c = algorithms.retrieve(dg, ep_cross_node_name, 'c') p = algorithms.retrieve(dg, ep_cross_node_name, 'p') qf = algorithms.retrieve(dg, ep_cross_node_name, 'qf') mu = [] v = [] t_peak = [] t_min = [] W = algorithms.retrieve(dg, injection_channel_name, 'width') # for each analyte for i in range(0, n): # calculate mobility mu.append(Variable('mu_' + str(i))) exprs.append(mu[i] < 10000000000) exprs.append(mu[i] > 0) exprs.append(mu[i] == algorithms.calculate_mobility( dg, separation_channel_name, q[i], r[i])) # calculate velocity v.append(Variable('v_' + str(i))) # exprs.append(v[i] < 1) exprs.append(v[i] > 0) exprs.append(v[i] == algorithms.calculate_charged_particle_velocity( dg, mu[i], E)) # calculate t_peak, initialize variables for t_min t_peak.append(Variable('t_peak_' + str(i))) t_min.append(Variable('t_min_' + str(i))) exprs.append(t_peak[i] < 1000000) exprs.append(t_peak[i] > 0) exprs.append(t_min[i] < 1000000) exprs.append(t_min[i] > 0) exprs.append(t_peak[i] == x_detector / v[i]) # detector position is somewhere along the separation channel # assume x_detector ranges from 0 to length of channel # to get absolute position of detector, add x_detector to ep_cross_node position exprs.append(x_detector <= algorithms.retrieve(dg, separation_channel_name, 'length')) # C_negligible is the minimum concentration level # i.e. smallest concentration peak should be > C_negligible C_negligible = Variable('C_negligible') C_floor = Variable('C_floor') sigma0 = Variable('sigma0') # TODO: This equation for sigma0 is for round, should add rectangular as well # definition of sigma0 for round channels (sigma0 ~ r_channel/2.355) exprs.append(sigma0 == W / (2 * 2.355)) exprs.append(C_floor == (min(C0) / (sigma0 + (2 * max(D) * x_detector / v[n - 1])**0.5))) exprs.append(C_negligible == p * C_floor) diff = [] for i in range(0, n - 1): # constrain that time difference between peaks is large enough to be detected exprs.append(t_peak[i] + delta < t_min[i]) exprs.append(t_peak[i] + delta < t_min[i + 1]) # constrain t_min to be where derivative of concentration is 0 # if two adjacent peaks are close enough in height, then instead of using # the differential eqn, can approximate Fi(tmin) = Fi+1(tmin) # where i is the current analyte, and i+1 is the next analyte # and F = C(x_detector), C is concentration # quantify closeness of heights of peaks using the variable diff diff.append(Variable('diff_' + str(i))) exprs.append(diff[i] == C0[i] / C0[i + 1] * (D[i + 1] * mu[i] / (D[i] * mu[i + 1]))**0.5) # if 0.1 < diff < 10, then use expression Fi(tmin) = Fi+1(tmin) # otherwise use expression dFi/dt (tmin) + dFi+1/dt (tmin) = 0 t_min_constraint_expression = if_then_else( logical_and(0.1 < diff[i], diff[i] < 10), algorithms.calculate_concentration(dg, C0[i], D[i], W, v[i], x_detector, t_min[i]) - algorithms.calculate_concentration(dg, C0[i + 1], D[i + 1], W, v[i + 1], x_detector, t_min[i]), (algorithms.calculate_concentration( dg, C0[i + 1], D[i + 1], W, v[i + 1], x_detector, t_min[i])).Differentiate(t_min[i]) + (algorithms.calculate_concentration( dg, C0[i + 1], D[i + 1], W, v[i + 1], x_detector, t_min[i])).Differentiate(t_min[i])) exprs.append(t_min_constraint_expression == 0) # an alternate way to define C_negligible is: # C_negligible < p * min(Fi(t_peaki)) # this requires computing the concentration again, which is inefficient # Wrote this expression just in case; this is the more exact expression # for C_negligible, in case the simpler one does not work for square # channels # I don't know how to use the min function in dreal, so I figured an # equivalent but less efficient way to do it is just to ensure it is # less than Fi(t_peaki), for every i # exprs.append(C_negligible < p * algorithms.calculate_concentration(dg, C0[i], D[i], W, v[i], x_detector, t_peak[i])) # F(tmin, i)/(F(tmax, i)) <= c # F(tmin, i)/F(tpeak, j) ~ ( Fi(tmin,i) + Fi+1(tmin, i) + (n-2)(1-q)/(n-3) ) / Fj(tpeak,j) exprs.append( (algorithms.calculate_concentration(dg, C0[i], D[i], W, v[i], x_detector, t_min[i]) + algorithms.calculate_concentration(dg, C0[i + 1], D[i + 1], W, v[ i + 1], x_detector, t_min[i]) + (n - 2) * (1 - qf) / (n - 3) * C_negligible) / (algorithms.calculate_concentration( dg, C0[i], D[i], W, v[i], x_detector, t_peak[i])) <= c) # F(tmin, i)/(F(tmax, i+1)) <= c exprs.append( (algorithms.calculate_concentration(dg, C0[i], D[i], W, v[i], x_detector, t_min[i]) + algorithms.calculate_concentration(dg, C0[i + 1], D[i + 1], W, v[ i + 1], x_detector, t_min[i]) + (n - 2) * (1 - qf) / (n - 3) * C_negligible) / (algorithms.calculate_concentration(dg, C0[i + 1], D[i + 1], W, v[ i + 1], x_detector, t_peak[i + 1])) <= c) # Call translate on output - waste node [ exprs.append(val) for val in translation_strats[algorithms.retrieve( dg, waste_node_name, 'kind')](dg, waste_node_name) ] # Call translate on output - anode [ exprs.append(val) for val in translation_strats[algorithms.retrieve( dg, anode_node_name, 'kind')](dg, anode_node_name) ] return exprs
def translate_node(dg, name): """Create SMT expressions for bounding the parameters of an node to be within the constraints defined by the user :param name: Name of the node to be constrained :returns: None -- no issues with translating the port parameters to SMT """ exprs = [] # Pressure at a node is the sum of the pressures flowing into it output_pressures = [] for node_name in dg.pred[name]: # This returns the nodes with channels that flowing into this node # pressure calculated based on P=QR # Could modify equation based on # https://www.dolomite-microfluidics.com/wp-content/uploads/ # Droplet_Junction_Chip_characterisation_-_application_note.pdf output_pressures.append( algorithms.channel_output_pressure(dg, (node_name, name))) if len(dg.pred[name]) == 1: exprs.append( algorithms.retrieve(dg, name, 'pressure') == output_pressures[0]) elif len(dg.pred[name]) > 1: output_pressure_formulas = [ a + b for a, b in zip(output_pressures, output_pressures[1:]) ] exprs.append( algorithms.retrieve(dg, name, 'pressure') == logical_and( *output_pressure_formulas)) if algorithms.retrieve(dg, name, 'min_x'): exprs.append( algorithms.retrieve(dg, name, 'x') == algorithms.retrieve( dg, name, 'min_x')) else: exprs.append(algorithms.retrieve(dg, name, 'x') >= 0) if algorithms.retrieve(dg, name, 'min_y'): exprs.append( algorithms.retrieve(dg, name, 'y') == algorithms.retrieve( dg, name, 'min_y')) else: exprs.append(algorithms.retrieve(dg, name, 'y') >= 0) # If parameters are provided by the user, then set the # their Variable equal to that value, otherwise make it greater than 0 if algorithms.retrieve(dg, name, 'min_pressure'): # If min_pressure has a value then a user defined value was provided # and this variable is set equal to this value, else simply set its # value to be >0, same for viscosity, pressure, flow_rate, X, Y and density exprs.append( algorithms.retrieve(dg, name, 'pressure') == algorithms.retrieve( dg, name, 'min_pressure')) else: exprs.append(algorithms.retrieve(dg, name, 'pressure') > 0.000001) # Force pressure to be greater than 1uPa exprs.append(algorithms.retrieve(dg, name, 'pressure') < 1000000) # Force pressure to be less than 1MPa if algorithms.retrieve(dg, name, 'min_flow_rate'): exprs.append( algorithms.retrieve(dg, name, 'flow_rate') == algorithms.retrieve( dg, name, 'min_flow_rate')) else: exprs.append( algorithms.retrieve(dg, name, 'flow_rate') > 0.000000000001) # Force flow rate to be greater than 1nL/s exprs.append(algorithms.retrieve(dg, name, 'flow_rate') < 0.001) # Force flow rate to be less than 1L/s if algorithms.retrieve(dg, name, 'min_viscosity'): exprs.append( algorithms.retrieve(dg, name, 'viscosity') == algorithms.retrieve( dg, name, 'min_viscosity')) else: exprs.append(algorithms.retrieve(dg, name, 'viscosity') > 0.0001) # Liquid helium is 0.000158 exprs.append(algorithms.retrieve(dg, name, 'viscosity') < 100) # Force viscosity to be less than 100Pa*s if algorithms.retrieve(dg, name, 'min_density'): exprs.append( algorithms.retrieve(dg, name, 'density') == algorithms.retrieve( dg, name, 'min_density')) else: exprs.append(algorithms.retrieve(dg, name, 'density') > 500) # No liquid should be below this density exprs.append(algorithms.retrieve(dg, name, 'density') < 2000) # Force density for be less than 2000kg/m^3 densities = [] for node_in in dg.pred[name]: densities.append(algorithms.retrieve(dg, node_in, 'density')) # If they are all equal, then set this node to be that density if there is a value # TODO: Create case for when different densities come in if densities and densities[1:] == densities[:-1]: exprs.append( algorithms.retrieve(dg, name, 'density') == algorithms.retrieve( dg, list(dg.pred[name].keys())[0], 'density')) # To recursively traverse, call on all successor channels for node_out in dg.succ[name]: [ exprs.append(val) for val in translation_strats[algorithms.retrieve( dg, (name, node_out), 'kind')](dg, (name, node_out)) ] return exprs
def test_minimize3(self): result = Minimize(x, logical_and(0 <= x, x <= 1, 0 <= p, p <= 1, p <= x), 0.00001) self.assertTrue(result) self.assertAlmostEqual(result[x].mid(), 0, places=2) self.assertAlmostEqual(result[p].mid(), 0, places=2)
def run_and(self, ident, val) -> None: a = val.exp_a['dreal_exp'] b = val.exp_b['dreal_exp'] ident['dreal_exp'] = dreal.logical_and(a, b)
def pFet(Vtp, Vdd, Kp, Sp, src, gate, drain, tI): constraints = [] if type(src) == Variable or type(gate) == Variable: constraints.append(logical_or(logical_and(src < drain, gate - drain >= Vtp, tI == 0.0), logical_and(src < drain, gate - drain <= Vtp, src - drain <= gate - drain - Vtp, tI == -0.5*Sp*Kp*(gate - drain - Vtp)*(gate - drain - Vtp)), logical_and(src < drain, gate - drain <= Vtp, src - drain >= gate - drain - Vtp, tI == -Sp*Kp*(gate - drain - Vtp - (src - drain)/2.0)*(src - drain)), logical_and(src >= drain, gate - src >= Vtp, tI == 0.0), logical_and(src >= drain, gate - src <= Vtp, drain - src <= gate - src - Vtp, tI == 0.5*Sp*Kp*(gate - src - Vtp)*(gate - src - Vtp)), logical_and(src >= drain, gate - src <= Vtp, drain - src >= gate - src - Vtp, tI == Sp*Kp*(gate - src - Vtp - (drain - src)/2.0)*(drain - src)))) else: if gate - src >= Vtp: constraints.append(logical_or(logical_and(src < drain, gate - drain >= Vtp, tI == 0.0), logical_and(src < drain, gate - drain <= Vtp, src - drain <= gate - drain - Vtp, tI == -0.5*Sp*Kp*(gate - drain - Vtp)*(gate - drain - Vtp)), logical_and(src < drain, gate - drain <= Vtp, src - drain >= gate - drain - Vtp, tI == -Sp*Kp*(gate - drain - Vtp - (src - drain)/2.0)*(src - drain)), logical_and(src >= drain, tI == 0.0))) else: constraints.append(logical_or(logical_and(src < drain, gate - drain >= Vtp, tI == 0.0), logical_and(src < drain, gate - drain <= Vtp, src - drain <= gate - drain - Vtp, tI == -0.5*Sp*Kp*(gate - drain - Vtp)*(gate - drain - Vtp)), logical_and(src < drain, gate - drain <= Vtp, src - drain >= gate - drain - Vtp, tI == -Sp*Kp*(gate - drain - Vtp - (src - drain)/2.0)*(src - drain)), logical_and(src >= drain, drain - src <= gate - src - Vtp, tI == 0.5*Sp*Kp*(gate - src - Vtp)*(gate - src - Vtp)), logical_and(src >= drain, drain - src >= gate - src - Vtp, tI == Sp*Kp*(gate - src - Vtp - (drain - src)/2.0)*(drain - src)))) return constraints
def nFet(Vtn, Vdd, Kn, Sn, src, gate, drain, tI): constraints = [] if type(src) == Variable or type(gate) == Variable: constraints.append(logical_or(logical_and(src > drain, gate - drain <= Vtn, tI == 0.0), logical_and(src > drain, gate - drain >= Vtn, src - drain >= gate - drain - Vtn, tI == -0.5*Sn*Kn*(gate - drain - Vtn)*(gate - drain - Vtn)), logical_and(src > drain, gate - drain >= Vtn, src - drain <= gate - drain - Vtn, tI == -Sn*Kn*(gate - drain - Vtn - (src - drain)/2.0)*(src - drain)), logical_and(src <= drain, gate - src <= Vtn, tI == 0.0), logical_and(src <= drain, gate - src >= Vtn, drain - src >= gate - src - Vtn, tI == 0.5*Sn*Kn*(gate - src - Vtn)*(gate - src - Vtn)), logical_and(src <= drain, gate - src >= Vtn, drain - src <= gate - src - Vtn, tI == Sn*Kn*(gate - src - Vtn - (drain - src)/2.0)*(drain - src)))) else: if gate - src <= Vtn: constraints.append(logical_or(logical_and(src > drain, gate - drain <= Vtn, tI == 0.0), logical_and(src > drain, gate - drain >= Vtn, src - drain >= gate - drain - Vtn, tI == -0.5*Sn*Kn*(gate - drain - Vtn)*(gate - drain - Vtn)), logical_and(src > drain, gate - drain >= Vtn, src - drain <= gate - drain - Vtn, tI == -Sn*Kn*(gate - drain - Vtn - (src - drain)/2.0)*(src - drain)), logical_and(src <= drain, tI == 0.0))) else: constraints.append(logical_or(logical_and(src > drain, gate - drain <= Vtn, tI == 0.0), logical_and(src > drain, gate - drain >= Vtn, src - drain >= gate - drain - Vtn, tI == -0.5*Sn*Kn*(gate - drain - Vtn)*(gate - drain - Vtn)), logical_and(src > drain, gate - drain >= Vtn, src - drain <= gate - drain - Vtn, tI == -Sn*Kn*(gate - drain - Vtn - (src - drain)/2.0)*(src - drain)), logical_and(src <= drain, drain - src >= gate - src - Vtn, tI == 0.5*Sn*Kn*(gate - src - Vtn)*(gate - src - Vtn)), logical_and(src <= drain, drain - src <= gate - src - Vtn, tI == Sn*Kn*(gate - src - Vtn - (drain - src)/2.0)*(drain - src)))) return constraints
from dreal.symbolic import Variable, logical_and, sin, cos from dreal.api import CheckSatisfiability, Minimize x = Variable("x") y = Variable("y") z = Variable("z") f_sat = logical_and(0 <= x, x <= 10, 0 <= y, y <= 10, 0 <= z, z <= 10, sin(x) + cos(y) == z) result = CheckSatisfiability(f_sat, 0.001) print(result)
def mvs_id(fetType, Vs, Vg, Vd, I, shape): params = model_params(fetType) version = params['version'] mType = params['mType'] W = params['W'] Lgdr = params['Lgdr'] dLg = params['dLg'] Cg = params['Cg'] etov = params['etov'] delta = params['delta'] n0 = params['n0'] Rs0 = params['Rs0'] Rd0 = params['Rd0'] Cif = params['Cif'] Cof = params['Cof'] vxo = params['vxo'] * 1e7 mu = params['mu'] beta = params['beta'] Tjun = params['Tjun'] phib = params['phib'] gamma = params['gamma'] Vt0 = params['Vt0'] alpha = params['alpha'] mc = params['mc'] CTM_select = params['CTM_select'] CC = params['CC'] nd = params['nd'] zeta = params['zeta'] # SMALL_VALUE SMALL_VALUE = 1e-10 # LARGE_VALUE LARGE_VALUE = 40 if mType == 1.0: Vb = 0.0 Vdsi = Variable("Vdsin") Vgsi = Variable("Vgsin") Vbsi = Variable("Vbsin") n = Variable("nn") nphit = Variable("nphitn") phibVbs = Variable("phibVbsn") Vtpcorr = Variable("Vtpcorrn") eVgpre = Variable("eVgpren") FFpre = Variable("FFpren") ab = Variable("abn") Vcorr = Variable("Vcorrn") Vgscorr = Variable("Vgscorrn") Vbscorr = Variable("Vbscorrn") phibVbscorr = Variable("phibVbscorrn") Vt0bs = Variable("Vt0bsn") phibVbsi = Variable("phibVbsin") Vt0bs0 = Variable("Vt0bs0n") Vtp = Variable("Vtpn") Vtp0 = Variable("Vtp0n") eVg = Variable("eVgn") FF = Variable("FFn") eVg0 = Variable("eVg0n") FF0 = Variable("FF0n") Qref = Variable("Qrefn") eta = Variable("etan") Qinv_corr = Variable("Qinv_corrn") Vdsat = Variable("Vdsatn") VdsiVdsat = Variable("VdsiVdsatn") powVal = Variable("powValn") Fsat = Variable("Fsatn") else: Vb = 1.8 Vdsi = Variable("Vdsip") Vgsi = Variable("Vgsip") Vbsi = Variable("Vbsip") n = Variable("np") nphit = Variable("nphitp") phibVbs = Variable("phibVbsp") Vtpcorr = Variable("Vtpcorrp") eVgpre = Variable("eVgprep") FFpre = Variable("FFprep") ab = Variable("abp") Vcorr = Variable("Vcorrp") Vgscorr = Variable("Vgscorrp") Vbscorr = Variable("Vbscorrp") phibVbscorr = Variable("phibVbscorrp") Vt0bs = Variable("Vt0bsp") phibVbsi = Variable("phibVbsip") Vt0bs0 = Variable("Vt0bs0p") Vtp = Variable("Vtpp") Vtp0 = Variable("Vtp0p") eVg = Variable("eVgp") FF = Variable("FFp") eVg0 = Variable("eVg0p") FF0 = Variable("FF0p") Qref = Variable("Qrefp") eta = Variable("etap") Qinv_corr = Variable("Qinv_corrp") Vdsat = Variable("Vdsatp") VdsiVdsat = Variable("VdsiVdsatp") powVal = Variable("powValp") Fsat = Variable("Fsatp") constraints = [] if mType == 1: constraints.append( logical_or(logical_and(Vs <= Vd, Vdsi == mType * (Vd - Vs)), logical_and(Vs > Vd, Vdsi == mType * (Vs - Vd)))) constraints.append( logical_or(logical_and(Vs <= Vd, Vgsi == mType * (Vg - Vs)), logical_and(Vs > Vd, Vgsi == mType * (Vg - Vd)))) constraints.append( logical_or(logical_and(Vs <= Vd, Vbsi == mType * (Vb - Vs)), logical_and(Vs > Vd, Vbsi == mType * (Vb - Vd)))) else: constraints.append( logical_or(logical_and(Vd <= Vs, Vdsi == mType * (Vd - Vs)), logical_and(Vd > Vs, Vdsi == mType * (Vs - Vd)))) constraints.append( logical_or(logical_and(Vd <= Vs, Vgsi == mType * (Vg - Vs)), logical_and(Vd > Vs, Vgsi == mType * (Vg - Vd)))) constraints.append( logical_or(logical_and(Vd <= Vs, Vbsi == mType * (Vb - Vs)), logical_and(Vd > Vs, Vbsi == mType * (Vb - Vd)))) Cofs = 0 * (0.345e-12 / etov) * dLg / 2.0 + Cof # s-terminal outer fringing cap [F/cm] Cofd = 0 * (0.345e-12 / etov) * dLg / 2.0 + Cof # d-terminal outer fringing cap [F/cm] Leff = Lgdr - dLg # Effective channel length [cm]. After subtracting overlap lengths on s and d side kB = 8.617e-5 # Boltzmann constant [eV/K] phit = kB * Tjun # Thermal voltage, kT/q [V] me = (9.1e-31) * mc # Carrier mass [Kg] constraints.append(n == n0 + nd * Vdsi) constraints.append(nphit == n * phit) aphit = alpha * phit constraints.append(phibVbs == dabs(phib - Vbsi)) constraints.append(Vtpcorr == Vt0 + gamma * (sqrt(phibVbs) - sqrt(phib)) - Vdsi * delta) constraints.append(eVgpre == exp((Vgsi - Vtpcorr) / (aphit * 1.5))) constraints.append(FFpre == 1.0 / (1.0 + eVgpre)) constraints.append(ab == 2 * (1 - 0.99 * FFpre) * phit) constraints.append(Vcorr == (1.0 + 2.0 * delta) * (ab / 2.0) * (exp(-Vdsi / ab))) constraints.append(Vgscorr == Vgsi + Vcorr) constraints.append(Vbscorr == Vbsi + Vcorr) constraints.append(phibVbscorr == dabs(phib - Vbscorr)) constraints.append(Vt0bs == Vt0 + gamma * (sqrt(phibVbscorr) - sqrt(phib))) constraints.append(phibVbsi == dabs(phib - Vbsi)) constraints.append(Vt0bs0 == Vt0 + gamma * (sqrt(phibVbsi) - sqrt(phib))) constraints.append(Vtp == Vt0bs - Vdsi * delta - 0.5 * aphit) constraints.append(Vtp0 == Vt0bs0 - Vdsi * delta - 0.5 * aphit) constraints.append(eVg == exp((Vgscorr - Vtp) / (aphit))) constraints.append(FF == 1.0 / (1.0 + eVg)) constraints.append(eVg0 == exp((Vgsi - Vtp0) / (aphit))) constraints.append(Qref == Cg * nphit) constraints.append(eta == (Vgscorr - (Vt0bs - Vdsi * delta - FF * aphit)) / (nphit)) constraints.append(Qinv_corr == Qref * log(1.0 + exp(eta))) vx0 = vxo Vdsats = vx0 * Leff / mu constraints.append(Vdsat == Vdsats * (1.0 - FF) + phit * FF) constraints.append(VdsiVdsat == Vdsi / Vdsat) constraints.append(powVal == pow(VdsiVdsat, beta)) constraints.append(Fsat == VdsiVdsat / (pow((1 + powVal), (1.0 / beta)))) if mType == 1: constraints.append( logical_or( logical_and(Vs <= Vd, I == Qinv_corr * vx0 * Fsat * W * mType * shape), logical_and( Vs > Vd, I == Qinv_corr * vx0 * Fsat * W * mType * -1.0 * shape))) else: constraints.append( logical_or( logical_and(Vd <= Vs, I == Qinv_corr * vx0 * Fsat * W * mType * shape), logical_and( Vd > Vs, I == Qinv_corr * vx0 * Fsat * W * mType * -1.0 * shape))) return constraints
def rambusOscillatorTanh(numStages, g_cc=0.5, numSolutions="all", a=-5.0): epsilon = 1e-14 start = time.time() g_fwd = 1.0 lenV = numStages * 2 vs = [] vfwds = [] vccs = [] for i in range(lenV): vs.append(Variable("v" + str(i))) vfwds.append(Variable("vfwd" + str(i))) vccs.append(Variable("vcc" + str(i))) allConstraints = [] # Store rambus oscillator constraints for i in range(lenV): allConstraints.append(vs[i] >= -1) allConstraints.append(vs[i] <= 1) fwdInd = (i - 1) % lenV ccInd = (i + lenV // 2) % lenV allConstraints.append(vfwds[i] == tanh(a * vs[fwdInd])) allConstraints.append(vccs[i] == tanh(a * vs[ccInd])) allConstraints.append(g_fwd * vfwds[i] + (-g_fwd - g_cc) * vs[i] + g_cc * vccs[i] == 0) allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] for i in range(lenV): singleExcludingConstraints.append(vs[i] < solution[i][0]) singleExcludingConstraints.append(vs[i] > solution[i][1]) excludingConstraints.append(singleExcludingConstraints) # Add all the rambus oscillator constraints f_sat = logical_and(*allConstraints) # Add constraints so that old hyperrectangles are not considered if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((lenV, 2)) for i in range(lenV): hyper[i, :] = [ result[vs[i]].lb() - 2 * epsilon, result[vs[i]].ub() + 2 * epsilon ] #print ("hyper", hyper) allSolutions.append(hyper) print("num solutions found", len(allSolutions)) end = time.time() print("time taken", end - start) return allSolutions
def phi(x): return logical_and(0 <= x, x <= math.pi)
# -*- coding: utf-8 -*- from dreal.symbolic import Variable, logical_and, sin, cos from dreal.symbolic import logical_imply, forall from dreal.api import CheckSatisfiability, Minimize from dreal.util import Box import math import unittest x = Variable("x") y = Variable("y") z = Variable("z") f_sat = logical_and(0 <= x, x <= 10, 0 <= y, y <= 10, 0 <= z, z <= 10, sin(x) + cos(y) == z) f_unsat = logical_and(3 <= x, x <= 4, 4 <= y, y <= 5, 5 <= z, z <= 6, sin(x) + cos(y) == z) objective = 2 * x * x + 6 * x + 5 constraint = logical_and(-10 <= x, x <= 10) class ApiTest(unittest.TestCase): def test_delta_sat(self): result = CheckSatisfiability(f_sat, 0.001) self.assertEqual(type(result), Box) b = Box([x, y, z]) result = CheckSatisfiability(f_sat, 0.001, b) self.assertEqual(result, True) self.assertTrue(b[x].diam() < 0.1)
def schmittTriggerScMosfet(inputVoltage, numSolutions="all"): epsilon = 1e-14 start = time.time() lenV = 3 Vdd = 1.0 sn = 3 sp = 2 * sn vs = [] tIs = [] nIs = [] for i in range(lenV): vs.append(Variable("v" + str(i))) nIs.append(Variable("nI" + str(i))) for i in range(lenV * 2): tIs.append(Variable("tI" + str(i))) allConstraints = [] for i in range(lenV): allConstraints.append(vs[i] >= 0.0) allConstraints.append(vs[i] <= Vdd) allConstraints += mvs_id('n', 0.0, inputVoltage, vs[1], tIs[0], sn) allConstraints += mvs_id('n', vs[1], inputVoltage, vs[0], tIs[1], sn) allConstraints += mvs_id('n', vs[1], vs[0], Vdd, tIs[2], sn) allConstraints += mvs_id('p', Vdd, inputVoltage, vs[2], tIs[3], sp) allConstraints += mvs_id('p', vs[2], inputVoltage, vs[0], tIs[4], sp) allConstraints += mvs_id('p', vs[2], vs[0], 0.0, tIs[5], sp) allConstraints.append(nIs[0] == -tIs[4] - tIs[1]) allConstraints.append(nIs[1] == -tIs[0] + tIs[1] + tIs[2]) allConstraints.append(nIs[2] == -tIs[3] + tIs[5] + tIs[4]) for i in range(lenV): allConstraints.append(nIs[i] == 0.0) allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] for i in range(lenV): singleExcludingConstraints.append(vs[i] < solution[i][0]) singleExcludingConstraints.append(vs[i] > solution[i][1]) excludingConstraints.append(singleExcludingConstraints) #print ("allConstraints") #print (allConstraints) f_sat = logical_and(*allConstraints) if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((lenV, 2)) for i in range(lenV): hyper[i, :] = [ result[vs[i]].lb() - 2 * epsilon, result[vs[i]].ub() + 2 * epsilon ] #print ("hyper", hyper) allSolutions.append(hyper) print("num solutions found", len(allSolutions)) end = time.time() print("time taken", end - start) return allSolutions
def rambusOscillatorLcMosfet(numStages, numSolutions = "all", g_cc = 0.5, Vtp = -0.4, Vtn = 0.4, Vdd = 1.8, Kn = 270*1e-6, Kp = -90*1e-6, Sn = 3.0): epsilon = 1e-14 start = time.time() #print ("Vtp", Vtp, "Vtn", Vtn, "Vdd", Vdd, "Kn", Kn, "Kp", Kp, "Sn", Sn) g_fwd = 1.0 lenV = numStages*2 Sp = 2*Sn vs = [] ifwdNs = [] ifwdPs = [] iccNs = [] iccPs = [] for i in range(lenV): vs.append(Variable("v" + str(i))) ifwdNs.append(Variable("ifwdN" + str(i))) ifwdPs.append(Variable("ifwdP" + str(i))) iccNs.append(Variable("iccN" + str(i))) iccPs.append(Variable("iccP" + str(i))) allConstraints = [] for i in range(lenV): allConstraints.append(vs[i] >= 0.0) allConstraints.append(vs[i] <= Vdd) allConstraints.append(g_fwd*(-ifwdNs[i]-ifwdPs[i]) + g_cc*(-iccNs[i]-iccPs[i]) == 0) fwdInd = (i-1)%lenV ccInd = (i+lenV//2)%lenV fwdConstraints = nFet(Vtn, Vdd, Kn, Sn, 0.0, vs[fwdInd], vs[i], ifwdNs[i]) fwdConstraints += pFet(Vtp, Vdd, Kp, Sp, Vdd, vs[fwdInd], vs[i], ifwdPs[i]) ccConstraints = nFet(Vtn, Vdd, Kn, Sn, 0.0, vs[ccInd], vs[i], iccNs[i]) ccConstraints += pFet(Vtp, Vdd, Kp, Sp, Vdd, vs[ccInd], vs[i], iccPs[i]) allConstraints += fwdConstraints + ccConstraints allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] for i in range(lenV): singleExcludingConstraints.append(vs[i] < solution[i][0]) singleExcludingConstraints.append(vs[i] > solution[i][1]) excludingConstraints.append(singleExcludingConstraints) #print ("allConstraints") #print (allConstraints) f_sat = logical_and(*allConstraints) if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((lenV,2)) for i in range(lenV): hyper[i,:] = [result[vs[i]].lb() - 1000*epsilon, result[vs[i]].ub() + 1000*epsilon] #print ("hyper", hyper) allSolutions.append(hyper) print ("num solutions found", len(allSolutions)) end = time.time() print ("time taken", end - start) return allSolutions
def inverterLoopLcMosfet(numInverters, numSolutions = "all", Vtp = -0.4, Vtn = 0.4, Vdd = 1.8, Kn = 270*1e-6, Kp = -90*1e-6, Sn = 3.0): epsilon = 1e-14 start = time.time() #print ("Vtp", Vtp, "Vtn", Vtn, "Vdd", Vdd, "Kn", Kn, "Kp", Kp, "Sn", Sn) Sp = 2*Sn vs = [] iNs = [] iPs = [] for i in range(numInverters): vs.append(Variable("v" + str(i))) iNs.append(Variable("iN" + str(i))) iPs.append(Variable("iP" + str(i))) allConstraints = [] for i in range(numInverters): allConstraints.append(vs[i] >= 0.0) allConstraints.append(vs[i] <= Vdd) allConstraints.append(-iNs[i]-iPs[i] == 0) inputInd = i outputInd = (i+1)%numInverters allConstraints += nFet(Vtn, Vdd, Kn, Sn, 0.0, vs[inputInd], vs[outputInd], iNs[i]) allConstraints += pFet(Vtp, Vdd, Kp, Sp, Vdd, vs[inputInd], vs[outputInd], iPs[i]) allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] for i in range(numInverters): singleExcludingConstraints.append(vs[i] < solution[i][0]) singleExcludingConstraints.append(vs[i] > solution[i][1]) excludingConstraints.append(singleExcludingConstraints) #print ("allConstraints") #print (allConstraints) f_sat = logical_and(*allConstraints) if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((numInverters,2)) for i in range(numInverters): hyper[i,:] = [result[vs[i]].lb() - 1000*epsilon, result[vs[i]].ub() + 1000*epsilon] #print ("hyper", hyper) allSolutions.append(hyper) print ("num solutions found", len(allSolutions)) end = time.time() print ("time taken", end - start) return allSolutions
def schmittTriggerLcMosfet(inputVoltage, Vtp = -0.4, Vtn = 0.4, Vdd = 1.8, Kn = 270*1e-6, Kp = -90*1e-6, Sn = 3.0, numSolutions = "all"): epsilon = 1e-14 start = time.time() #print ("Vtp", Vtp, "Vtn", Vtn, "Vdd", Vdd, "Kn", Kn, "Kp", Kp, "Sn", Sn) Sp = Sn *2.0 lenV = 3 vs = [] tIs = [] nIs = [] for i in range(lenV): vs.append(Variable("v" + str(i))) nIs.append(Variable("nI" + str(i))) for i in range(lenV*2): tIs.append(Variable("tI" + str(i))) allConstraints = [] for i in range(lenV): allConstraints.append(vs[i] >= 0.0) allConstraints.append(vs[i] <= 1.8) allConstraints += nFetLeak(Vtn, Vdd, Kn, Sn, 0.0, inputVoltage, vs[1], tIs[0]) allConstraints += nFetLeak(Vtn, Vdd, Kn, Sn, vs[1], inputVoltage, vs[0], tIs[1]) allConstraints += nFetLeak(Vtn, Vdd, Kn, Sn, vs[1], vs[0], Vdd, tIs[2]) allConstraints += pFetLeak(Vtp, Vdd, Kp, Sp, Vdd, inputVoltage, vs[2], tIs[3]) allConstraints += pFetLeak(Vtp, Vdd, Kp, Sp, vs[2], inputVoltage, vs[0], tIs[4]) allConstraints += pFetLeak(Vtp, Vdd, Kp, Sp, vs[2], vs[0], 0.0, tIs[5]) allConstraints.append(nIs[0] == -tIs[4] - tIs[1]) allConstraints.append(nIs[1] == -tIs[0] + tIs[1] + tIs[2]) allConstraints.append(nIs[2] == -tIs[3] + tIs[5] + tIs[4]) for i in range(lenV): allConstraints.append(nIs[i] == 0.0) allSolutions = [] while True: if numSolutions != "all" and len(allSolutions) == numSolutions: break # Store constraints pruning search space so that # old hyperrectangles are not considered excludingConstraints = [] for solution in allSolutions: singleExcludingConstraints = [] for i in range(lenV): singleExcludingConstraints.append(vs[i] < solution[i][0]) singleExcludingConstraints.append(vs[i] > solution[i][1]) excludingConstraints.append(singleExcludingConstraints) #print ("allConstraints") #print (allConstraints) #print ("numConstraints", len(allConstraints)) f_sat = logical_and(*allConstraints) if len(excludingConstraints) > 0: for constraints in excludingConstraints: f_sat = logical_and(f_sat, logical_or(*constraints)) #print ("f_sat") #print (f_sat) result = CheckSatisfiability(f_sat, epsilon) #print (result) if result is None: break hyper = np.zeros((lenV,2)) for i in range(lenV): hyper[i,:] = [result[vs[i]].lb() - 1000*epsilon, result[vs[i]].ub() + 1000*epsilon] #print ("hyper", hyper) allSolutions.append(hyper) print ("num solutions found", len(allSolutions)) end = time.time() print ("time taken", end - start) return allSolutions
def reducer(vars_bounds, item): (var, bound) = make_bound(*item) vars = vars_bounds[0] bounds = vars_bounds[1] return (vars + [var], logical_and(bounds, bound))