What I am doing wrong in the following code:
import dis
def count_operations(f):
operations = 0
for op in dis.get_instructions(f):
if op.opname in ('ADD', 'SUB', 'MULT', 'DIV', 'MOD'):
operations = 1
return operations
def solve_system(A, b):
x = np.linalg.solve(A, b)
return x
A = np.array([[2, 3],
[3, 4]])
b = np.array([8, 11])
operations = count_operations(solve_system)
print(f'Number of operations: {operations}')
I wrote two functions, one for counting operations and one for solving a system.
CodePudding user response:
Numpy does a lot of the heavy lifting with (compiled) library routines written in C or Fortran. You won't see those in dis
output:
In [1]: import numpy as np
In [2]: import dis
In [3]: def solve_system(A, b):
...: x = np.linalg.solve(A, b)
...: return x
...:
In [4]: dis.dis(solve_system)
2 0 LOAD_GLOBAL 0 (np)
2 LOAD_ATTR 1 (linalg)
4 LOAD_METHOD 2 (solve)
6 LOAD_FAST 0 (A)
8 LOAD_FAST 1 (b)
10 CALL_METHOD 2
12 STORE_FAST 2 (x)
3 14 LOAD_FAST 2 (x)
16 RETURN_VALUE
In [5]: dis.dis(np.linalg.solve)
179 0 LOAD_DEREF 0 (dispatcher)
2 LOAD_FAST 0 (args)
4 BUILD_MAP 0
6 LOAD_FAST 1 (kwargs)
8 DICT_MERGE 1
10 CALL_FUNCTION_EX 1
12 STORE_FAST 2 (relevant_args)
180 14 LOAD_GLOBAL 0 (implement_array_function)
181 16 LOAD_DEREF 1 (implementation)
18 LOAD_DEREF 2 (public_api)
20 LOAD_FAST 2 (relevant_args)
22 LOAD_FAST 0 (args)
24 LOAD_FAST 1 (kwargs)
180 26 CALL_FUNCTION 5
28 RETURN_VALUE
From the numpy.linalg.solve
documentation:
The solutions are computed using LAPACK routine
_gesv
.
Those routines (sgesv
and dgesv
for single and double precision) are written in Fortran.
See e.g. the documentation for dgesv.
CodePudding user response:
This is actually an interesting question. So you are making a wrapper function to show the amount of operations that are in a given tuple.
On inspection, the if
statement is failing and you can verify this by including an else
.
So i do this modification to verify:
import dis
import numpy as np
def count_operations(f):
operations = 0
not_operations = 0 # <---added this
for op in dis.get_instructions(f):
if op.opname in ('ADD', 'SUB', 'MULT', 'DIV', 'MOD'):
operations = 1
else:
not_operations = 1
return operations, not_operations
def solve_system(A, b):
x = np.linalg.solve(A, b)
return x
A = np.array([[2, 3],
[3, 4]])
b = np.array([8, 11])
operations = count_operations(solve_system)
print(f'Number of operations: {operations}')
The above code now returns a operations
as a tuple (of ops and not ops).
When i run the modified code i get this:
Number of operations: (0, 9)
You can also add a print statement to expose what you get in each loop. An example of the first operation in the list is this:
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='np', argrepr='np', offset=0, starts_line=18, is_jump_target=False)
Which is <class 'dis.Instruction'>
So you could expose that...
Finally, i can show that the code does infact work, but adding LOAD_FAST
into the tuple which then returns (3,6)
as it occurs 3 times...