In addition to theory π this course has a strong βοΈ practical component, with hands-on exercises and a semester-long project. To follow the course effectively you need an environment in which you can run code, version code, and β this is the new part β collaborate with an AI assistant on code without losing control of what it does.
This class sets up all three, plus the workflow you will use to submit every homework: a pull request in your own course repository.
PrerequisitesΒΆ
A reasonably modern computer: desktop or laptop, Windows or macOS or Linux
Administrative access to it (you can install programs)
A terminal you are willing to type into β PowerShell or Windows Terminal on Windows, Terminal or iTerm on macOS, anything on Linux
PythonΒΆ
The course primarily uses numpy, scipy, matplotlib and sympy, and Jupyter to run the
notebooks. Nothing fancy is required; no deep learning frameworks, no heavy toolboxes.
The current default: uvΒΆ
uv is a Python package and project manager that has become the default way to set up scientific Python. It installs Python itself, so you do not need a separate Python install, and it resolves and installs the whole stack in seconds rather than minutes.
# install uv (macOS/Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh
# on Windows, in PowerShell:
# powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
# then, inside the course repository
uv venv # create .venv with a suitable Python
uv pip install -r requirements.txt
uv run jupyter lab # run without activating anythingFor your own project, prefer a pyproject.toml and let uv maintain a lock file:
uv init # writes pyproject.toml
uv add numpy scipy matplotlib sympy jupyter
uv sync # reproduces the environment exactly from uv.lockuv.lock records the exact version of every package, transitively. Commit it. It is
the difference between βworks on my machineβ and a replication package someone can
actually run.
The alternative: condaΒΆ
If you already work in conda, or you need compiled libraries that conda packages better, use Miniforge, which is the conda-forge installer:
conda env create -f environment.yml
conda activate eco629pixi is a newer conda-compatible manager with uv-style lock files, worth knowing about if you end up in a conda-heavy group.
Versions matter more than you thinkΒΆ
Python 3.13 and 3.14 introduced free-threaded builds β an interpreter without the global interpreter lock. It is officially supported as of 3.14, and it changes how you would parallelize a solver.
NumPy 2.x is the default and removed a number of long-deprecated aliases. Code written before 2024 may fail on the removal, not on anything conceptual.
SciPy keeps moving optimizers around; pin it in your project.
It is a good practice to record the versions you use in README. When your work cannot be reproduced two years from now, this is almost always why, and it is a problem.
Your solver converges on your laptop but does not on a classmateβs, same code, same data, same seed. Even worse if it is you and the data editorβs team at the journal! What are the plausible causes?
Where you write codeΒΆ
A good editor is invaluable for editing source files β and it is now also the place where AI assistance lives, which makes the choice less cosmetic than it was.
VS Code β the default recommendation. Free, cross-platform, first-class Python and Jupyter support, Git built in, and GitHub Copilot integrates directly. If you have no strong preference, install this.
Cursor and Windsurf β forks of VS Code built around AI editing. Same keybindings and extensions, deeper assistant integration, subscription-based.
Positron β Positβs data-science IDE, VS Code-based, with a data explorer and a session-oriented layout familiar from RStudio.
Zed β fast native editor with built-in AI, if VS Code feels heavy.
PyCharm β a full IDE; excellent debugger and refactoring, free for students.
JupyterLab / Notebook 7 β where you will actually run the course notebooks.
Git and GitHubΒΆ
Git is the version control system; GitHub hosts repositories and is where course materials and all homework are distributed and collected.
Git β the command line tool
Git GUI clients β a graphical client makes branches, staging and history far easier to see than the command line does:
GitHub Desktop β simplest, free, macOS and Windows
Fork β fast and well designed, with an excellent diff and merge-conflict view; macOS and Windows, paid with an unlimited evaluation period
Sourcetree β free, macOS and Windows
the Git panel built into VS Code, if you would rather not install anything
GitHub CLI (
gh) β creates pull requests, checks out someone elseβs PR, views CI logs, all from the terminal. Install it; it removes most of the browser round-trips from the submission workflow.
Account setup, onceΒΆ
Register on GitHub. Be mindful about the personal data you use when registering.
Enable two-factor authentication β required for accounts that contribute code. A passkey or an authenticator app is fine; SMS is the weakest option.
Add an SSH key (or use
gh auth login, which sets one up for you). Password authentication for Git operations has not worked since 2021; if a tutorial tells you to type your GitHub password into a terminal, it predates the current world.Apply for the Student Developer Pack β it includes GitHub Pro, Copilot Pro, extra Codespaces hours and a long list of other services, free while you are a student.
Send me your GitHub username. I will create a private repository for you and invite you to it, together with the repository the tasks are posted in β see Homework submission workflow below. Accept both invitations; nothing works until you do.
Commands worth knowingΒΆ
git pull upstream main # collect newly posted tasks
git switch -c alpha # create and move to a branch (modern `checkout -b`)
git status # what is changed, staged, untracked
git add -p # stage selected hunks β read your own diff
git commit -m "alpha: bisection solver"
git push -u origin alpha
gh pr create # open the pull request without leaving the terminalIf you are on WindowsΒΆ
Everything in this course runs on Windows β Python, Git, Jupyter, the assistants. What differs is the shell you type commands into, and a couple of defaults that produce baffling diffs if left alone.
Use Git BashΒΆ
Git for Windows installs Git Bash alongside Git. Use it for everything in these notes, ideally inside Windows Terminal. Every command block in this book then runs exactly as written.
The alternative shells will bite you in small ways:
Windows PowerShell 5.1 β still the default
powershell.exeon Windows 10 β has no&&, sogit add . && git commit -m "..."simply fails. PowerShell 7 (pwsh) added it.Line continuation in PowerShell is a backtick, not a backslash, so any command broken across lines has to be rewritten.
Command Prompt has neither the Unix utilities nor the quoting rules the examples assume.
None of this is fatal, and if you already live in PowerShell you will be fine β but Git Bash is the path of least translation.
Install the GitHub CLIΒΆ
gh is a separate install; it does not come with Git for Windows. Pick one:
winget install --id GitHub.cli # preinstalled on Windows 11 and recent Windows 10
scoop install gh
choco install ghRestart the terminal afterwards so PATH picks it up, then run gh auth login.
gh auth login is also the easiest way through the part of setup that Windows makes
fussiest. Choose SSH as the protocol and it generates a key, loads it into the agent,
and uploads the public key to GitHub for you. Choose HTTPS and gh auth setup-git
registers gh as Gitβs credential helper, so there is no key to manage at all.
Either way you can skip the manual ssh-keygen, enable-the-service, paste-into-
settings sequence.
Line endingsΒΆ
Git for Windows sets core.autocrlf=true, which converts line endings on checkout
and commit. Left to itself in a mixed-OS class this produces diffs where every line
of a file you never touched is marked as changed.
The course repositories carry a .gitattributes that stores every text file with
LF regardless of who commits it, which settles the question. Leave both that file
and your core.autocrlf alone. If you do end up with a whole-file diff, fix it once
with
git add --renormalize .Where to put the repositoryΒΆ
Not inside OneDrive, Dropbox or any synced folder. Sync clients lock files while Git is writing them, and a
.gitdirectory synced across machines corrupts in ways that are tedious to recover from. Use a plain local path such asC:\Users\you\code\.Windows still enforces a 260-character path limit in places. One-time cure:
git config --global core.longpaths trueWSL, if you want itΒΆ
The Windows Subsystem for Linux gives you a real Linux, and everything in this book
then works the Linux way. It is a perfectly good choice, and it is not required.
Two rules if you go there: install the tools again inside WSL β a Windows gh or
uv is invisible from the Linux side β and keep the repository on the Linux
filesystem, since a repository under /mnt/c is slow enough to notice.
Notebooks, and their limitsΒΆ
Editing course notebooks and writing project modules are different activities. Use the notebook for exploration and the editor for anything you will reuse.
Jupyter notebooks are an excellent way to present and discuss code β this entire course is taught with them β and a good instrument for developing ideas. They are saved as JSON with text, LaTeX math, code and code output interleaved.
Their limitations have not changed, and they matter for your project:
Not a good place to store developed code. Put solvers, simulators and estimators in
.pymodules and import them into the notebook.Not good for version control. Execution counts, metadata and cell outputs are all tracked as changes; merging two edited notebooks can break the JSON outright.
Hidden state. Cells run out of order produce results that no fresh run reproduces. Before you submit anything: Restart kernel and run all.
However, the tooling around these problems is now good enough that there is no excuse for fighting them:
jupytext pairs every notebook with a plain
.pyor.mdfile. You commit the text file, diffs are readable, merges work. The percent format (# %%cell markers) is understood by VS Code, PyCharm and Spyder, which run those.pyfiles as notebooks directly.nbstripout and nbdime strip outputs before commit and diff notebooks cell by cell. Install nbstripout as a pre-commit hook and forget about it.
marimo is a reactive Python notebook stored as an ordinary
.pyfile: no hidden state, since changing a cell re-runs everything downstream, and it is git-friendly by construction. A serious option for your project.MyST Markdown notebooks are how these lecture notes are written β Markdown with executable code blocks, built by Jupyter Book 2. Look at the source of any chapter of this book to see the format.
AI coding assistantsΒΆ
This course is AI-friendly: see the AI policy on the front page. The policy is short β you are responsible for everything you submit, and you must understand every line β and it is examined orally. You also must disclose the use of AI assistants beyond text editing: see the disclosure policy below.
Three kinds of toolΒΆ
| Kind | Examples | Good for |
|---|---|---|
| Chat | Claude, ChatGPT, Gemini | deriving, explaining, checking algebra, talking through a modelling choice |
| In-editor | GitHub Copilot, Cursor, Windsurf, Colabβs assistant | completion, small refactors, docstrings, tests, βexplain this cellβ |
| Agentic CLI | Claude Code, Codex CLI, Gemini CLI | multi-file work: writing a solver module, running it, reading the traceback, fixing it, repeating |
The third category is what changed most recently, and it is the one worth your time this semester. An agentic tool runs in your repository, reads and writes files, and executes commands β so it can close the loop between writing code and finding out that the code is wrong, which is exactly the loop a structural project consists of.
Copilot has a free tier, and Copilot Pro is included in the Student Developer Pack. Colab includes assistance at no cost. Anthropic and OpenAI both offer inexpensive entry plans that include their CLIs. You do not need to pay for all of these; pick one from the second or third row and learn it properly.
Configure the context, not just the promptΒΆ
Every one of these tools reads a plain-text instructions file from the repository
root β CLAUDE.md, AGENTS.md, or the editorβs equivalent β and treats it as
standing instructions. This is where you write down what the assistant cannot infer:
# Project: Rust bus engine replacement, ECO 629
- Python, numpy/scipy only. No deep learning frameworks.
- Value functions are indexed by [state]; replacement-specific value is the first element of the vector; keep that order everywhere.
- Always check Bellman convergence with a monotonicity test before trusting output.
- Never edit files under data/raw/.
- Leave all git operations to me.Five lines like these are worth more than any amount of prompt phrasing. Commit the file: it documents the projectβs conventions for humans too.
Where AI helpsΒΆ
Scaffolding β grids, interpolation helpers, plotting, argument parsing, tests. Tedious, well-specified, easy to check.
Translation β a lot of code is historically written in MATLAB and Fortran. Porting it to Python or Julia is a task assistants do well, and you should verify numerically against the original output.
Debugging β pasting a traceback plus the relevant function is the single highest-value use.
Reading β βwhat does equation (12) in this paper assume about the error termβ against a PDF you have open.
Derivations β with
sympyin the loop so the algebra is checked, not asserted.
Where it will quietly hurt youΒΆ
Numerical code fails silently. A wrong Jacobian, a mis-signed log-likelihood, a transition matrix whose rows do not sum to one β all of these produce output, plots, and estimates. Nothing raises an exception. Assistants are fluent at producing plausible numerical code, which means the burden of verification is entirely yours.
DisclosureΒΆ
This is not an obstacle to clear β it is normal professional practice, and increasingly journal policy. A complete disclosure is short:
Claude Code wrote the EGM interpolation helper and the plotting code; I verified the helper against the analytic solution for the cake-eating case. ChatGPT was used to check the algebra of the Euler equation derivation in Section 2.
Disclosure changes nothing about responsibility. The work is yours, the errors are yours, and the oral exam is about your understanding of every line you submit β see the AI policy. Disclosure exists so that we can talk about how you worked, which is a subject of this course in its own right.
An assistant hands you a working NFXP estimator in five minutes. What do you have, and what do you not have? What would you need to do before you would defend it at the board?
Reproducibility, from day oneΒΆ
Your project is a small replication package. Structural estimates that nobody can reproduce β including you, in six months β are not results.
Pin the environment: commit
uv.lockorenvironment.yml, and note the Python version.Seed everything: create one
np.random.default_rng(seed)and pass it down. Never call the legacy globalnp.random.*functions in project code.Separate stages: a script that solves, a script that simulates, a script that estimates, each writing its output to disk. Estimation runs are long; you do not want to redo the solve because a plot was ugly.
Log the runs: parameters in, starting values, convergence flag, wall time, final objective. A CSV of runs beats scrollback.
Write the README as you go: how to install, what to run, in what order, and roughly how long each step takes.
The AEA Data Editorβs replication policy is the standard your future submissions will be held to, and it is a good template now.
Cloud fallbackΒΆ
Google Colab β free tier, no setup, built-in AI assistance, easy to share. Sessions are time-limited and the filesystem is ephemeral; mount Drive or push to GitHub before you close the tab.
GitHub Codespaces β a full VS Code in the browser running on a container defined by a
.devcontainer/file in the repository. Monthly free allowance, larger with the Student Developer Pack. The closest cloud equivalent of a local install, and the environment is defined in code.Binder β builds a temporary environment from any public repository. Capacity-limited; good for demos, not for work.
Stony Brookβs SeaWulf cluster β if your project needs to run many estimations, or a bootstrap, or a Monte Carlo, this is what it is for. Talk to me early if you want to go this route.
Homework submission workflowΒΆ
You do not fork anything, and you never push to the course repository. Two repositories are involved:
| Repository | What it is | Your access |
|---|---|---|
fediskhakov/sb-dse-class | the task repository β I push each assignment here | read |
fediskhakov/sb-dse-<your-username> | your repository for the whole semester | write |
Your repository is created as a clone of the task repository, so it shares its history: pulling from the task repository brings each new assignment straight into your working copy, all semester, without any copying by hand.
Once, at the start of the semesterΒΆ
Send me your GitHub username
Accept the two invitations GitHub emails you β one to your own repository, one to the task repository
Clone your repository and add the task repository as a second remote:
git clone git@github.com:fediskhakov/sb-dse-<your-username>.git
cd sb-dse-<your-username>
git remote add upstream git@github.com:fediskhakov/sb-dse-class.git
uv tool install nbstripout && nbstripout --install # conda: conda install -c conda-forge nbstripoutorigin is now your repository, upstream is the task repository. Confirm with
git remote -v.
For each assignmentΒΆ
git pull upstream main # collect newly posted tasks
cp -r tasks/<assignment_name> solutions/<assignment_name> # copy
git switch -c <assignment_name> # one branch per assignment
# ... solve inside solutions/<assignment_name>/ ...
git add . && git commit -m "<short message describing the work you are submitting>"
git push -u origin <assignment_name>. # submit
gh pr create --reviewer fediskhakov # add me as a reviewerWhile you workΒΆ
The line git add . && git commit -m "..." above compresses a whole assignment into
one commit. Do not actually work that way. Commit every time something starts
working β a function that returns the right value, a plot that comes out, a bug you
have just fixed:
git status # what have I changed?
git diff # what exactly did I change?
git add <path/filename> # stage one file...
git add -p # ...or stage selected hunks, reading as you go
git commit -m "<descriptive commit message>"
git push # after the first push -u, plain git push is enoughTen small commits over three evenings, then the pull request:
A commit is a save point. When an experiment goes wrong,
git restore .puts you back at the last one β cheaper and safer than undoing edits by hand.Pushing is your backup. A laptop that dies the night before the deadline costs you nothing if the branch is already on GitHub.
The history shows how you worked. Useful to you at the board, when you have to explain why the estimator changed shape halfway through; useful to me, because a pull request that arrives as one commit of 400 lines cannot be reviewed.
Small commits get better comments. Twelve commits with meaningful messages attract useful review; one commit called βalphaβ attracts none.
Write messages that say what changed and why β βfix bugβ is worth nothing three weeks later, βclip the value function at the borrowing constraintβ is worth a lot.
Three commands that recover from the usual mistakes:
git commit --amend # fix the message or add a file to the last commit,
# but only if you have not pushed it yet
git restore <file> # discard uncommitted changes to one file
git stash # park changes to try something else; git stash pop brings them backSubmittingΒΆ
The pull request is the submission, and its creation time is the timestamp of
record. It stays open until we have discussed the assignment in class; then it is
merged into your main, so your main ends the semester as a record of your
accepted work.
Homework is discussed at the start of the class that follows it, with one student presenting the solution at the board. The presenter rotates, so plan on presenting several times over the semester β including code that does not work yet, which is usually the more instructive case.