Code#

Our convention is to follow PEP8 unless there is a good reason to do otherwise.

One good reason is to get closer to mathematical notation in a given lecture.

Hence it’s fine to use capitals for matrices, etc.

Operators are typically surrounded by spaces, as in a * b and a + b, but we write a**b for \(a^b\).

Variable Naming Conventions#

Unicode Variable Names#

Prefer Unicode symbols for Greek letters commonly used in economics:

  • Use α instead of alpha

  • Use β instead of beta

  • Use γ instead of gamma

  • Use δ instead of delta

  • Use ε instead of epsilon

  • Use σ instead of sigma

  • Use θ instead of theta

  • Use ρ instead of rho

This makes the code more readable and closer to mathematical notation used in economic literature.

Example:

# ✅ Preferred: Unicode variables
def utility_function(c, α=0.5, β=0.95):
    """CRRA utility function with discount factor."""
    return (c**(1-α) - 1) / (1-α) * β

# ❌ Avoid: Spelled-out Greek letters  
def utility_function(c, alpha=0.5, beta=0.95):
    """CRRA utility function with discount factor."""
    return (c**(1-alpha) - 1) / (1-alpha) * beta

Guiding principle

QuantEcon lecture’s should run in a base installation of Anaconda python.

Any packages (that are not included in anaconda) need to be installed at the top of the lecture.

An example:

In addition to what’s in Anaconda, this lecture will need the following libraries:

In the example above we install the quantecon and yfinance packages.

We use tags: [hide-output] as the output is not central to the lecture.

There are a couple of exceptions to this guideline.

  • when the software involves specific configuration for the hardware (i.e. gpu computing), or

  • if additional software needs to be installed on your system via apt or some other binary source.

JAX#

When using jax you should not install jax at the top of your lecture.

This may install jax[cpu] which will run but is not the optimal configuration for executing the lecture.

The following admonition can be used.

```{admonition} GPU
:class: warning

This lecture is accelerated via [hardware](status:machine-details) that has access to a GPU and JAX for GPU programming.

Free GPUs are available on Google Colab. To use this option, please click on the play icon top right, select Colab, and set the runtime environment to include a GPU.

Alternatively, if you have your own GPU, you can follow the [instructions](https://github.com/google/jax) for installing JAX with GPU support. If you would like to install JAX running on the `cpu` only you can use `pip install jax[cpu]`
```

which will render as

GPU

This lecture is accelerated via hardware that has access to a GPU and JAX for GPU programming.

Free GPUs are available on Google Colab. To use this option, please click on the play icon top right, select Colab, and set the runtime environment to include a GPU.

Alternatively, if you have your own GPU, you can follow the instructions for installing JAX with GPU support. If you would like to install jax running on the cpu only you can use pip install jax[cpu]

The jax[gpu] package needs to be properly installed via Docker or GitHub Actions.

Please consult with Matt McKay should you need to update these settings.

Binary packages with Python frontends#

The graphviz package is a python interface to a local installation of graphviz and is useful for rendering DOT source code.

If you need to use graphviz you should:

  1. Install pip install graphviz at the top of your lecture

  2. Check if graphviz is getting installed in .github/workflows/ci.yml for preview builds

  3. Add the below note admonition to your lecture.

graphviz

If you are running this lecture locally it requires graphviz to be installed on your computer. Installation instructions for graphviz can be found here

which will render as

graphviz

If you are running this lecture locally it requires graphviz to be installed on your computer. Installation instructions for graphviz can be found here

Performance Timing Patterns#

Timer Context Manager#

Use the modern qe.Timer() context manager instead of manual timing patterns.

The QuantEcon library provides a Timer context manager that replaces older timing approaches like tic/tac/toc functions with cleaner, more reliable syntax.

❌ Avoid: Manual timing patterns

import time

# Old pattern - verbose and error-prone
start_time = time.time()
result = expensive_computation()
end_time = time.time()
print(f"Elapsed time: {(end_time - start_time) * 1000:.6f} ms")

✅ Preferred: Timer context manager

import quantecon as qe

# Modern pattern - clean and reliable
with qe.Timer():
    result = expensive_computation()
# Output: 0.05 seconds elapsed

Timer Features and Usage Patterns#

The Timer context manager supports various usage patterns:

Basic Timing#

import quantecon as qe

with qe.Timer():
    result = expensive_computation()
# Output: 0.05 seconds elapsed

Custom Messages and Units#

# Custom message with milliseconds
with qe.Timer("Computing eigenvalues", unit="milliseconds"):
    eigenvals = compute_eigenvalues(matrix)
# Output: Computing eigenvalues: 50.25 ms elapsed

# Microseconds for very fast operations
with qe.Timer("Quick calculation", unit="microseconds"):
    result = simple_operation()
# Output: Quick calculation: 125.4 μs elapsed

Silent Mode for Method Comparison#

# Store timing without printing for performance comparisons
timer = qe.Timer(silent=True)
with timer:
    result = expensive_computation()
elapsed_time = timer.elapsed  # Access stored time

# Compare multiple methods
methods = [method_a, method_b, method_c]
timers = []

for method in methods:
    timer = qe.Timer(f"{method.__name__}", silent=True)
    with timer:
        method(data)
    timers.append((method.__name__, timer.elapsed))

# Find fastest method
fastest = min(timers, key=lambda x: x[1])
print(f"Fastest method: {fastest[0]} ({fastest[1]:.6f}s)")

Precision Control#

# Control decimal places in output
with qe.Timer("High precision timing", precision=8):
    result = computation()
# Output: High precision timing: 0.12345678 seconds elapsed

Exception Safety#

The Timer context manager works correctly even when exceptions occur:

timer = qe.Timer("Error-prone operation", silent=True)
try:
    with timer:
        risky_computation()
except Exception as e:
    print(f"Operation failed after {timer.elapsed:.4f} seconds")
    raise

Migration from Legacy Patterns#

Replace tic/tac/toc patterns:

# Old approach
from quantecon.util.timing import tic, tac, toc

tic()
result = computation()
toc()

# New approach
with qe.Timer():
    result = computation()

Note

The tic/tac/toc functions remain available for backward compatibility, but new code should use the Timer context manager for better readability and reliability.