A collection of major projects from over the years.
Triton is a GPU programming language that hides memory coalescing, shared-memory allocation, and intra-block scheduling behind a tile-level abstraction. We wanted to know what that abstraction costs, so our four-person team (for Penn's CIS 6010) implemented 2D convolution five ways — a coalesced global-memory CUDA kernel, two shared-memory tiling strategies, cuDNN, and Triton — and benchmarked all five across 32 input sizes from 128×128 to 4096×4096, timing the kernels alone on a laptop RTX 4060 so the implementations were directly comparable.
At 4096×4096 our best hand-written CUDA kernel ran in 20.5 ms and the Triton kernel ran in 13 ms — 1.6× faster, and within 1.5× of cuDNN. Reading the generated PTX explained why: Triton vectorized into 8-wide predicated loads across 128-thread cooperative blocks, saturating eight cache lines per request, while our CUDA lowered to scalar, branch-heavy loops handling one element per thread.
The most useful result was a negative one. The tiling strategy sized to the input tile ran 55% slower than the plain (coalesced) global-memory kernel: idle halo threads and larger thread blocks cost more in occupancy than the shared-memory reuse gave back.
ICPU-v0 (Ian CPU) is a five-stage pipelined processor implementing the RISC-V RV32I integer base and the RV32M multiply/divide extension, written in about 1,800 lines of SystemVerilog and implemented on an FPGA, built solo for Penn's CIS 4710. It carries a full bypass network (MX, WX, and WD), interlocks for load-use and divide-use hazards, branch flushing, and a pipelined signed divider, and it drives both instruction and data memory over an AXI4-Lite interface.
It runs the Dhrystone benchmark in 255,086 cycles at 1.32 cycles per instruction, matching the reference trace cycle for cycle across the RV32IM test suite. The main cause of stall cycles in this iteration were taken-branch flushes at 22.9% of all cycles, against 1.2% for load-use interlocks and 0.2% for divides. The original design closes timing at roughly 20 MHz on a Zedboard.
Based off my benchmark findings, I built a branch predictor to improve the design beyond the scope of the class. A build-time parameter selects the original predict-not-taken policy, a direct-mapped branch target buffer that predicts taken on a hit, or the same buffer with 2-bit saturating (bimodal) counters. With 64 entries and bimodal counters, Dhrystone drops from 1.32 to 1.13 cycles per instruction (255,086 to 217,840 cycles, 14.6% fewer) at a 24.1% misprediction rate, and branch flushes fall from 22.9% to 9.7% of cycles. Sweeping the buffer from 16 to 64 to 256 entries gives 1.20, 1.13, and 1.07 cycles per instruction. Every configuration passes the full RISC-V ISA test suite, directed tests for aliased entries and self-modifying code, and Dhrystone, all in cycle-accurate Verilator and cocotb simulation.
PennCloud is a fully distributed webmail and cloud storage system
built by a four-person team. At its core is a fault-tolerant
key-value store modeled on Google's BigTable, which I helped
design and paired on with the rest of the team. On top of it I
built the HTTP server — request routing, cookies, and
chunked transfer encoding — a multithreaded design where
pthread worker threads each own a connection queue and new
connections go to the least-loaded worker, plus a heartbeat thread
for health checks — and the load balancer that distributes
requests round-robin across frontend replicas, with heartbeat
health checks and an admin command interface for adding and
removing servers. Under wrk it sustained 10,000+
requests/s with p99 latency under 10 ms on a saturated
low-end laptop CPU. The report below covers the full feature set
and the design tradeoffs behind it.
IMG2GPS predicts where a photograph was taken from the image alone. We collected over 500 GPS-tagged photographs from the blocks around the Penn engineering quad and trained a pipeline of convolutional neural networks on them: a first model sorts an image into a coarse region, then an ensemble of region-specific models narrows down the location within it. The project report has the architecture and accuracy results.
A tiny C command-line tool that sends a question to an AI model
over any OpenAI-compatible
/chat/completions endpoint (LiteLLM, Ollama, vLLM,
OpenAI) and prints the answer as plain text. The tool ships with
read, write, and execute tools for basic file manipulation and
shell commands. Additionally, MCP servers can be connected. All
tool use is opt-in, so it's safe by default.
The stripped binary is 39 KB and starts in
5–10 ms. It ships with unit tests and a mock-server
integration suite, both passing clean under AddressSanitizer/UBSan
and Valgrind —
make debug runs the full suite under sanitizers as a
standing target — and prebuilt Debian/Ubuntu packages via
GitHub Releases. It's open source under the MIT license.
PennOS is a working Unix-like operating system with a kernel-level
API, a file system, and a user-space terminal, built from scratch
by a four-person team for Penn's CIS 5480. The team built the
scheduler, threads, processes, and signals. I designed and wrote
its FAT-based file system (the FAT and block layer, directories,
and mkfs/mount), co-wrote the file descriptor layer
(open, read, write,
close, and lseek over a custom file
descriptor table) and the standalone PennFAT shell, and wrote
job-control code for foregrounding and backgrounding processes. In
file-system benchmarks it sustained 113,000 writes/s and 200,000
reads/s with no corruption. The documents below cover the feature
set and the generated Doxygen reference.
MiniMinecraft is a scaled-down Minecraft clone in C++ and OpenGL, built by a 3-person team for Penn's CIS 4600, that won the semester Hall of Fame award. I built the game engine and player physics: grid-marching collision along each axis, and ray-marched block placing and breaking. I also worked across the multithreaded terrain pipeline, where worker threads generate terrain alongside rendering. I built chunk saving and loading into the worker threads (only modified chunks are written to disk), moved tree growth onto them, reworked them so the main thread knows when terrain is ready, and added a Qt main menu to start a world from a seed or load a save. On the rendering side, I split each chunk into opaque and transparent passes, added UV and animation data for animated water and lava, and drew the hotbar and crosshair in their own pass. The video walks through the full feature set.
A Stirling engine that converts heat applied at the rounded chamber on the back into rotation, by cyclically heating and cooling the air inside it. Magnets around the perimeter of the flywheel pass through a stator and coils, generating alternating current: three phases of 0.2 V peak-to-peak at 40 Hz, which rectify to 1.5 V DC. I designed and machined the entire engine and generator myself. It is still a work in progress — raising the power output is the next step.
Four single-precision matrix-multiply kernels written and tuned against cuBLAS: a naive version, a coalesced global-memory version, a 32×32 shared-memory tiled version, and a register-blocked variant where each thread accumulates a 2×2 block of the output in registers before writing it back. Every kernel is validated element-wise against cuBLAS, and the tile and blocking factors were chosen by sweeping them against Nsight Compute occupancy and memory-throughput counters.
A combined dataset joining the World Ocean Database and the Ocean Biodiversity Information System, built so researchers can study how climate change affects marine biodiversity.
IDK is a semi-autonomous robot built by a 3-person team for Penn's MEAM 5100 (Design of Mechatronic Systems) class-wide robot battle game. It runs on an ESP32-S2 with 2 encoder DC motors on an L298N driver, 3 VL53L0X time-of-flight sensors, and a servo-driven attack arm, for $113.85 in parts. I designed the electrical schematic in KiCad, then restructured the final firmware and wrote most of it (about 1,200 lines of Arduino C++, building on teammates' motor-control and wall-following prototypes): PI motor control from encoder counts, an 8-state drive state machine, time-of-flight sensing, the servo arm, and a WiFi web interface for driving it from a keyboard. All 3 sensors share one I2C bus; sequencing their XSHUT pins gives each its own address. It scored 55 of the 50 points required at the demo, reached the opposing nexus autonomously in the final competition, and finished in the second-place alliance.
MicroMaya is a small mesh editor supporting basic editing operations and OBJ file viewing.
PennSAT is a SAT solver built on the DPLL algorithm. The graph above shows its runtime on random 3-CNF formulas with 75 variables and 324 clauses.
SV to Net is a logic-synthesis compiler that turns combinational SystemVerilog into minimized, formally verified gate-level netlists, and uses SAT-based exact synthesis to prove that small circuits are optimal. A hand-written lexer and recursive-descent parser feed an elaborator that applies SystemVerilog's width rules and bit-blasts every operator into an XOR-AND graph. From there it searches for the cheapest circuit in CMOS transistors, combining Quine-McCluskey and Espresso minimization with exact synthesis on Google's OR-Tools CP-SAT solver, and checks every result for equivalence before writing it out as Verilog, BLIF, or Graphviz.
It found a 32-transistor full adder built only from NAND, NOR, and NOT gates, and proved nothing cheaper exists (the textbook circuit costs 36). A redesigned solver encoding cut the time to prove that from about 98 s to under 7 s. On a random 4-input, 4-output, 100-gate module where my first prototype timed out, it cuts the cost by 68% and proves the result optimal in under 20 s. Not every design shrinks: for adders, comparators, and parity trees, the logic as written was already the best circuit it found. It began as a final project in December 2025, and I rewrote it from a 600-line prototype into a typed, packaged tool with 725 tests, including property-based tests and differential testing against the Verilator simulator.
A 6-person Penn senior-design project that evaluates LLMs on newly released competition math problems (published after model training cutoffs), with standardized prompting and structured multi-metric scoring — embedding similarity, Lean 4 proof compilation, concept coverage, and exact-match checks. I architected the AWS system design, worked on keeping the system performant, and paired on implementation, including the problem crawler and the model evaluator.
The site you are reading now: a static site for my projects and artwork. It lives in an S3 bucket on AWS, updated automatically by a GitHub Actions workflow on every push, served over HTTPS through Route 53 and distributed by the CloudFront CDN.