Early exposure of economics students to symbolic computation in Python

Andrew Adrian Pua

2024-11-07

… is a mixed bag.

Follow along

Or visit https://bit.ly/pes-py.

Context

  1. DLSU 1st year economics majors
  2. Last 3-unit maths course before entering the majors – focus is on optimization
  3. A 1-unit lab course runs along concurrently
  4. These two courses are taught by separate instructors who did not coordinate at all.
  5. This time, I taught both and students were informed in advance of the appropriate sections to enroll.

Setup

  1. No Python background required (yours truly never used Python until I taught the lab)
  2. No nasty installation of Python and other libraries required
  3. Use freely available computing interface: SymPy Live Shell, then Google Colab (latter one “freely”)
  4. Go directly to doing actual work, worry about weird stuff later
  5. Plotting limited, had to use Desmos for expediency

My intended goals

  1. Every student should be able to open their textbook (or references) and then work on examples and answer the exercises using SymPy.
  2. Even better if they could write a full solution with text, explanations, and mathematical reasoning.
  3. Best case: All of the above, giving value to setting up a computational representation of a problem rather than “dump everything into computer and cross your fingers”

Constraints

  1. Meet only one hour once a week
  2. Meet only 12 times, but 3 of those times are exams
  3. Introduce every basic thing early vs introduce things just-in-time
  4. Work individually vs work with groups
  5. Topics in “maths” course should be in sync vs relegate some “symbolically overwhelming” topics to lab

Constraints

  1. Meet only one hour once a week
  2. Meet only 12 times, but 3 of those times are exams
  3. Introduce every basic thing early vs introduce things just-in-time
  4. Work individually vs work with groups
  5. Topics in “maths” course should be in sync vs relegate some “symbolically overwhelming” topics to lab: A mix happened.

Example: Finding extrema andd doing some comparative statics

From Essential Mathematics for Economic Analysis:

Thinking in terms of SymPy when developing a solution

  1. obtain the stationary points of \(f\).

    • Declare variables.
    • Define a function.
    • Know how to calculate derivatives.
    • Know how to solve a system of equations.

Thinking in terms of SymPy when developing a solution

  1. determine whether each stationary point is a local maximum, local minimum, saddle point, or “cannot tell”.

    • Enter an expression.
    • Make substitutions.
    • Check whether conditions are satisfied.

Thinking in terms of SymPy when developing a solution

  1. produce an expression of the maximized value of \(f\).

    • Make substitutions.
  2. produce an expression of how the maximized value of \(f\) going to be affected by changes in \(a\).

    • Make substitutions.
    • Know how to calculate derivatives.
    • Do this mechanically or use Envelope Theorem.

Code

  1. Setup the function to be optimized.
from sympy import *
f, x, y, a, D = symbols('f x y a D', real = True)
f = (x**2-a*x*y)*exp(y)
  1. Find stationary points.
eq1 = Derivative(f, x).doit() 
eq2 = Derivative(f, y).doit()
soln = solve([eq1, eq2], [x, y], dict = True)
soln
[{x: 0, y: 0}, {x: -a, y: -2}]

Code, continued

  1. Determine if you have a local max, local min, or saddle point.
D = Derivative(f, x, x).doit()*Derivative(f, y, y).doit()-(Derivative(f, x, y).doit())**2
soln[0]
{x: 0, y: 0}
soln[1]
{x: -a, y: -2}
D.subs(soln[0]), D.subs(soln[1])
(-a**2, a**2*exp(-4))

Code, continued

  1. Effect of changing \(a\) on \(f\)
f.subs(soln[1])

\(\displaystyle - \frac{a^{2}}{e^{2}}\)

Derivative(f.subs(soln[1]), a).doit()

\(\displaystyle - \frac{2 a}{e^{2}}\)

Derivative(f, a).doit().subs(soln[1])

\(\displaystyle - \frac{2 a}{e^{2}}\)

“Weird” stuff

  1. You have seen a preview of some “weird” stuff.

    • Indices start at 0.
    • The displayed output may have some variations depending on how you want to present and use them in subsequent calculations.
soln = solve([eq1, eq2], [x, y])
type(soln[0])
tuple
soln = solve([eq1, eq2], [x, y], dict = True)
type(soln[0])
dict

Weird stuff, continued

  1. There is a distinction between the numeric and the symbolic.
x = 2
type(x)
int
from sympy import *
x = symbols('x')
type(x)
sympy.core.symbol.Symbol

Example: Nastier comparative statics

From Essential Mathematics for Economic Analysis:

Thinking in terms of SymPy when developing a solution

  1. Declare variables, define functions, take derivatives, make substitutions, solve systems of equations

    • Same set of skills!
    • But we work with functions which are not specified
  2. Key step is to distinguish regular inputs \(K\), \(L\) against optimal inputs \(K^*\), \(L^*\)

Code

  1. Setup profit function.
from sympy import *
p, w, r = symbols('p w r', real = True, positive = True)
K, L = symbols('K L', real = True, positive = True)
pi = symbols('pi', real = True)
Q = Function('F')(K, L)
pi = p*Q-w*L-r*K
  1. Distinguish regular inputs \(K\), \(L\) against optimal inputs \(K^*\), \(L^*\).
Kstar = Function('K')(w,r,p)
Lstar = Function('L')(w,r,p)

Code, continued

  1. Solve systems of equations (quite a mess, not very clean looking output)
x, y = symbols('x y', real = True)
eq1 = Derivative(Derivative(pi, K).doit().subs({K:Kstar, L:Lstar}), w).doit().subs({Derivative(K, w).subs({K:Kstar, L:Lstar}):x, Derivative(L, w).subs({K:Kstar, L:Lstar}):y})
eq2 = Derivative(Derivative(pi, L).doit().subs({K:Kstar, L:Lstar}), w).doit().subs({Derivative(K, w).subs({K:Kstar, L:Lstar}):x, Derivative(L, w).subs({K:Kstar, L:Lstar}):y})
solve([eq1, eq2], [x, y], dict = True)
[{x: -Derivative(F(K(w, r, p), L(w, r, p)), K(w, r, p), L(w, r, p))/(p*Derivative(F(K(w, r, p), L(w, r, p)), (K(w, r, p), 2))*Derivative(F(K(w, r, p), L(w, r, p)), (L(w, r, p), 2)) - p*Derivative(F(K(w, r, p), L(w, r, p)), K(w, r, p), L(w, r, p))**2),
  y: Derivative(F(K(w, r, p), L(w, r, p)), (K(w, r, p), 2))/(p*Derivative(F(K(w, r, p), L(w, r, p)), (K(w, r, p), 2))*Derivative(F(K(w, r, p), L(w, r, p)), (L(w, r, p), 2)) - p*Derivative(F(K(w, r, p), L(w, r, p)), K(w, r, p), L(w, r, p))**2)}]

Code, continued

  1. Make things look nicer by churning out LaTeX code:
expr = solve([eq1, eq2], [x, y], dict = True)
from IPython.display import display, Math
display(Math('%s' %latex(expr)))

\(\displaystyle \left[ \left\{ x : - \frac{\frac{\partial^{2}}{\partial L{\left(w,r,p \right)}\partial K{\left(w,r,p \right)}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)}}{p \frac{\partial^{2}}{\partial K{\left(w,r,p \right)}^{2}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)} \frac{\partial^{2}}{\partial L{\left(w,r,p \right)}^{2}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)} - p \left(\frac{\partial^{2}}{\partial L{\left(w,r,p \right)}\partial K{\left(w,r,p \right)}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)}\right)^{2}}, \ y : \frac{\frac{\partial^{2}}{\partial K{\left(w,r,p \right)}^{2}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)}}{p \frac{\partial^{2}}{\partial K{\left(w,r,p \right)}^{2}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)} \frac{\partial^{2}}{\partial L{\left(w,r,p \right)}^{2}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)} - p \left(\frac{\partial^{2}}{\partial L{\left(w,r,p \right)}\partial K{\left(w,r,p \right)}} F{\left(K{\left(w,r,p \right)},L{\left(w,r,p \right)} \right)}\right)^{2}}\right\}\right]\)

Advantages

  1. Chance to see theory in a different form
  2. Teach programming (in a narrow sense) indirectly
  3. Be comfortable with the “command line”
  4. Create dynamic documents and weave Python calculations into documents – Learn LaTeX, HTML, Markdown indirectly
  5. Taking notes in line with the current generation
  6. “Dumping everything on a computer” mentality can somehow be corrected.

Disadvantages

  1. AI is literally built in to Google Colab
  2. Can be frustrating to move around the lab troubleshooting every little thing
  3. 1 hour goes by so fast
  4. Unclear whether skills get transferred to major courses
  5. Not very natural to learn syntax and write code: Why? It requires thinking and a suspension of disbelief.
  6. Plotting can be unwieldy! Desmos might be better for something quicker.

Student evaluation

Based on 3 evaluations during the first 4 to 5 meetings:

  1. Roughly 50%-60% were distracted by other open tabs.
  2. Roughly 80%-90% of students can see tangible evidence that the lectures are connected to the lab.
  3. Roughly 60% of students forgotten commands from past labs.
  4. Not everyone can finish all exercises

Exam styles

  1. Write code by hand for first half and then answer the same exercise with a computer
  2. A report with a full solution and explanation could be required.
  3. Students have a hard time writing self-contained code on paper which will run without error.
  4. Some students failed the course.

Should you do it? Yes, if you …

  1. Want to pick up something new under pressure (dignity as an instructor at stake!)
  2. Want to write a paper, create new materials, and present at PES (or maybe some other conferences!)
  3. Want to really understand how the courses at your institution mesh together
  4. Reduce the tedious calculations and make room for other material

Should you do it? No, if you …

  1. Do not have enough patience: troubleshooting can be taxing
  2. Have grander plans than what could be achievable given the constraints
  3. Feel that it is highly unlikely that students will use these skills in their major or even in the “real world”

Final advertisements

Slides Lecture/lab course webpage My webpage Even earlier exposure

Questions, proposals, collaboration?

Email me at andrew.pua@dlsu.edu.ph or approach me, I’ll give you my card.