Translating normal code to 3AC - Three address code - python

I am trying to make an algorithm that will transcribe certain input, such as:
(a * b) / (c * d)
and will print out input like this in 3AC:
t1: a * b
t2: c * d
t3= t1/t2
Has anyone any suggestions?

Algorithm for transcribing such equations is pretty straightforward.
Obviously first task would be to convert given equation to reverse polish notation. From here you already have perfectly defined order of execution.
You now have to prepare stack for operands. At this point you just do it like normal RPN, except instead of performing operation and putting result back on operands stack, you have to print new TAC instruction with new number, and put that symbol back on stack instead of result.
In your example RPN will be : a b * c d * /
So a and b go on the stack. When we encounter * we pop 2 items from stack, print t1 := a * b and put t1 on stack. Now we traverse RPN more and put c and d on stack. Now we come to encounter another *, so again lets pop 2 items from stack, print them with new TAC symbol t2 := c * d and put our new symbol t2 back on stack.
lastly we encounter / so again we pop 2 items from stack, create new symbol and print it :) t3 := t1 / t2.
This is much simpler than standard RPN calculator.

One way you could do this is to first turn this into an AST
then traverse the AST by recursive function to make your code.
for your example your code will be turned into something like this
("/", ("*", "a", "b"), ("*", "c", "d")
traverse with said function and turn it into this
t0 = a * b
t1 = c * d
t2 = t0 / t1

Related

How do you write Ranged Inequality Constraint in Pyomo

I'm new to Pyomo and I need help writing this equation in Pyomo.
I'm trying to write a (ranged inequality) constraint equation in Pyomo.
Here is the equation:
So far I wrote these 2 versions:
Version 1: Not sure if this correct
model.amount_of_energy_con = pe.ConstraintList()
for t in model.time:
lhs = 0
rhs = sum(model.c_ratings[s] * model.boat_capacity * model.charging[b, t, s] * model.boats_availability[b][t] for b in model.boats for s in model.chargers)
body = sum(model.charge_energy[b, t, s] for b in model.boats for s in model.chargers)
model.amount_of_energy_con.add(lhs <= body)
model.amount_of_energy_con.add(body <= rhs)
Version 2: I think this is not correct
model.amount_of_energy_con = pe.ConstraintList()
for t in model.time:
lhs = 0
rhs = sum(model.c_ratings[s] * model.boat_capacity * model.charging[b, t, s] * model.boats_availability[b][t] for b in model.boats for s in model.chargers)
body = sum(model.charge_energy[b, t, s] for b in model.boats for s in model.chargers)
#model.amount_of_energy_con.add(expr=pe.inequality(lhs, body, rhs))
model.amount_of_energy_con.add(lhs, body, rhs)
Note:
All the subscripts in the equation are elements of 3 different sets. s Elements of Set S (model.chargers), b Elements of Set B (model.boats), t Elements of Set T (model.time).
C-rate, Availability, Battery capacity are given parameters while E and Charging are Variables in Pyomo.
Please, let me know what you think and how to write it in Pyomo. Generally if there is something you think I'm doing wrong, please me know and also if you need my full code, data and further explanation let me know as well.
Thank you so much for your help
This solution works for me:
model.amount_of_energy_con = pe.ConstraintList()
for t in model.time:
for b in model.boats:
for s in model.chargers:
lhs = model.charge_energy[b, t, s]
rhs = model.c_rating[s] * model.boat_battery_capacity * boats_availability[b, t] * model.charging[b, t, s]
model.amount_of_energy_con.add(expr= (lhs <= rhs))
The problem with those previous versions I posted above in the question are:
The sum() function/ method will do sum of the variables and parameters which is not what I want because the equation doesn't have summation. The 2 versions above will work if we are trying to do summation of the variables on the right and left hand side separately.
The 0 in the range inequalities/ left hand side was covered using the "within parameter" when writing the charge_energy variable as follows model.charge_energy = pe.Var(model.boats, model.time, model.chargers, within=pe.NonNegativeReals).
Thank you.

how can write this formula in python?

how can i write a function that takes 2 integer parameters, a and b.
Inside the function I need calculate the value of x using the formula below (where the term 2a indicates that 2 is multiplied by a).
I'm quite lost with doing this can someone please give me a hint on how to start this code in python?
You can use the below method to achieve your goal.
# remember to import math
x = lambda a, b: (math.sqrt(b**2 - 1) + b)/(2 * a)
Now you can use this function:
x(5, 10) # gives 1.99498743710662 (roughly)
Here is how:
def x(a, b):
return (b+(b**2-1)**0.5)/(2*a)
In python, we use ** for power symbols.

Sympy: There remains some terms which shuold be obviously vanished

I want to calculate derivative of a function using following code.
import sympy
pi = sympy.symbols("pi")
class H(sympy.Function):
nargs = 1
def fdiff(self, argindex=1):
x = self.args[0]
return - sympy.functions.exp(-sympy.Pow(x, 2) / 2) / sympy.sqrt(2 * pi)
def G(a):
return (
(a + 1) * H(1 / sympy.sqrt(a))
- sympy.sqrt(a / (2 * pi)) * sympy.functions.exp(-1 / (2 * a))
)
x = sympy.symbols("x")
sympy.simplify(sympy.diff(G(x), x))
It is expected to be G'(x) = H(1 / sqrt(x)), but I got
Out[1]: H(1/sqrt(x)) - sqrt(2)*sqrt(x/pi)*exp(-1/(2*x))/(4*x) - sqrt(2)*sqrt(x/pi)*exp(-1/(2*x))/(4*x**2) + sqrt(2)*exp(-1/(2*x))/(4*sqrt(pi)*sqrt(x)) + sqrt(2)*exp(-1/(2*x))/(4*sqrt(pi)*x**(3/2))
The remaining terms should obviously be 0 when seen by human eye.
Then I tried to change two pis in the definition of H and G to sympy.pi, which returns H(1 / sqrt(x)) as I expected.
Why my first code returns some extra terms?
SymPy has built in rules which allow certain transformations to happen (automatically, sometimes) or to be prohibited (by default). When you defined pi as a Symbol, you created a generic symbol with the only assumption being that it is commutative. But the number pi is that and it is positive. That assumption allows something like sqrt(x/y) to automatically rewrite as sqrt(y)*sqrt(x)/y if y is positive:
>>> sqrt(x/y)
sqrt(x/y)
>>> sqrt(x/3)
sqrt(3)*sqrt(x)/3
If you take your last expression and substitution a positive value for the symbol pi you will get that rewrite and then the cancelling terms will cancel.
>>> print(sympy.simplify(sympy.diff(G(x), x))).subs(pi, 3)
H(1/sqrt(x))
As Johan points out, it is better in this case to just use SymPy's S.Pi:
>>> S.Pi.n(3)
3.14

How do I implement summation and array iteration correctly based on Pseudo code. PYTHON Relaxation Method

I am trying to implement relaxation iterative solver for a project. The function we create should intake two inputs: Matrix A, and Vector B, and should return iterative vectors X that Approximate solution Ax = b.
Pseudo Code from the book is here:
enter image description here
I am new to Python so I am struggling quite a bit with implementing this method. Here is my code:
def SOR_1(A,b):
k=1
n = len(A)
xo = np.zeros_like(b)
x = np.zeros_like(b)
omega = 1.25
while (k <= N):
for i in range(n-1):
x[i] = (1.0-omega)*xo[i] + (1.0/A[i][i])[omega(-np.sum(A[i][j]*x[j]))
-np.sum(A[i][j]*xo[j] + b[i])]
if ( np.linalg.norm(x - xo) < 1e-9):
print (x)
k = k + 1.0
for i in range(n-1):
xo[i] = x[i]
return x
My question is how do I implement the for loop and generating the arrays correctly based off of the Pseudo Code.
Welcome to Python!
Variables in Python are case sensitive so n is defined but N is not defined. If they are supposed to be different variables, I don't see what your value is for N.
You are off to a good start but the following line is still psuedocode for the most part:
x[i] = (1.0-omega)*xo[i] + (1.0/A[i][i])[omega(-np.sum(A[i][j]*x[j]))
-np.sum(A[i][j]*xo[j] + b[i])]
In the textbook's pseudocode square brackets are being used as a grouping symbol but in Python, they are reserved for creating and accessing lists (which is what python calls arrays). Also, there is no implicit multiplication in Python so you have to write things like (1 + 2)*(3*(4+5)) rather than (1 + 2)[3(4+5)]
The other major issue is that you don't define j. You probably need a for loop that would either look like:
for j in range(1, i):
or if you want to do it inline
sum(A[i][j]*x[j] for j in range(1, i))
Note that range has two arguments, where to start and what value to stop before so range(1, i) is equivalent to the summation from 1 to i - 1
I think you are struggling with that line because there's far too much going on in that line. See if you can figure out parts of it using separate variables or offload some of the work to separate functions.
something like: x[i] =a + b * c * d() - e() but give a,b c, d and e meaningful names. You'd then have to correctly set each variable and define each function but at least you are trying to solve separate problems rather than one huge complex one.
Also, make sure you have your tabs correct. k = k + 1.0 should not be inside that for loop, just inside the while loop.
Coding is an iterative process. First get the while loop working. Don't try to do anything in it (except print out the variable so you can see that it is working). Next get the for loop working inside the while loop (again, just printing the variables). Next get (1.0-omega)*xo[i] working. Along the way, you'll discover and solve issues such as (1.0-omega)*xo[i] will evaluate to 0 because xo is a NumPy list initiated with all zeros.
You'd start with something like:
k = 1
N = 3
n = 3
xo = [1, 2, 3]
while (k <= N):
for i in range(n):
print(k, i)
omega = 1.25
print((1.0-omega)*xo[i])
k += 1
And slowly work more and more of the relaxation solver in until you have everything working.

How to perform arithmetic on the same line as a augmented assignment in Python 3.x.x?

In one of my programs,
I had the following line:
a = (a * b) + a
Where a = 30, b = .05
This outputted 31.5 as the result
This worked properly, but PyCharm told me I could turn it into an augmented assignment.
I know that a * = b is the same as a = a * b
So I rewrote the line as follows:
a *= b + a
However upon compiling it outputted the result of 901.5 which is obviously not the correct answer! Putting parenthesis anywhere does not change the result and I would like to do this in the same line as the augmented assignment instead of two separate lines, so in reality I have two questions:
Is it possible to get the augmented assignment to perform the same way as my initial equation on the same line?
If not, why can't we perform arithmetic on augmented assignments?
You can use
a += a * b
which will do a * b and then + a, same result as:
a * b + a

Categories