CS 1 (Fall 2025) Project 05: Chemical Reaction Balancer

This project covers using custom types and linear algebra operations in Python.

Goals and Outcomes

In this project, you will create a chemical reaction balancer.

Setup

Go to project registration to register for the project. Make sure to sign up for cs1-25fa projects on the left! Once you do, restart vscode and a folder with the starter code should automatically show up in your file browser.

Project Grading

As per the syllabus, to pass the class, you must earn at least a 50% on each project.

Note that you can earn extra credit on this project by completing more than the required number of stars, as outlined in Step 3: Run score.py.

The Idea

We’ve seen in previous projects that CS can be useful in many other fields, including subjects in the rest of core!

You might have seen in Ch1a that balancing chemical equations can often be quite tedious. However, we can automate this process using linear algebra (specifically, gaussian elimination methods) to find coefficients of chemical compounds, and can also extend this to find limiting reagents and yields for various chemical equations.

It’s okay if you don’t know what all these words mean! We have provided guidance for each of the functions, and you are always encouraged to go to OH for any questions (short or long!).

What’s New?

To simplify the transition between chemistry and linear algebra, we have created some new useful chemistry and math types that will be used throughout the chemistry components of the project. In the relevant type descriptions section you will see the relevant chemistry and math types required, and some documentation to help understand them better. Additionally, in the drop-down definitions of each function, you will see the relevant chemistry and math types required. To see how they are implemented, take a look at the file chem_types.py in the support folder.

Just to be clear, while the tool you’re writing can be incredibly helpful in classes like Ch1a and Ma1b, we expect you to follow the Honor Code and use your best judgment if using it in any of these classes!

How This Project Works

This project will be structured differently from the previous ones. Think of this as a “choose your own adventure” project, where you can choose which subset of functions you want to write that are outlined below. Each function is assigned a certain number of “stars” corresponding to their difficulty and ultimately their point value.

Even if you don’t plan to implement all of the functions, we still recommend you read through all of them before starting - some definitions may make a lot more sense after reading others!

Your Development Cycle for This Project

Step 1: Choose a function to implement.

Look at the list of function choices and choose one to attempt to implement next.

Step 2: Uncomment that function in config.py.

Each time you write a function, you must uncomment the name of function in the file config.py. Keep all function names that you have not written as commented out!

Debugging tip: Isolate the the function you are working on by commenting out everything else in config.py. Please come to OH if you need more help!

The tests will automatically ONLY use your versions of the functions you have uncommented. It will use our reference solution for any commented/unimplemented functions. This also means that the functions you write can (and often will!) use a helper function that you have not written, and the tests will still work because they will pull those helper functions from our reference solution. This is why all your tests should always pass if the code you wrote is correct!

Step 3: Run score.py.

Before implementing a function. Run score.py by using the play button in the top right to see what your score would be with that function implemented correctly. Note that score.py does not check correctness; it only indicates your final score assuming you have passed all the tests (NOT just the ones for your implemented functions). We expect you to play around with choices until you reach your desired score. Since functions are worth different numbers of points, you should decide what to implement based on what you’re interested in. Additionally, there are “bonus” stars (i.e., points) for every category you’ve implemented at least one function in AND every category you’ve implemented every function in!

Step 4: Write the code!!!

You got this!

Step 5: See your code in action!

Once you finish writing all your code, you should open the file website.py file located in the project05-[username] folder. Run this file by using the play button in the top right corner, and there will be a link in the terminal (starting with “127”) you can click on to open a website. That website will be a chemical equation balancer whose backend comes from your implementation!

The Functions

There are no DUES for this project!

Relevant Type Description Appendix

The above functions use several types you haven’t encountered before. We’re listing them all here for quick reference.

Chemistry Type Definitions:

Gram

Represents the amount of a substance (element or compound) in grams as a float.

Mol

Represents the amount of a substance (element or compound) in mols as a float.

MolarMass

Represents the amount of a substance (element or compound) in g/mol as a float.

Element

A string that must be a valid element from the periodic table.

PeriodicTableEntry

A dictionary that defines the structure of each entry in the periodic table. The dictionary includes the following key-value pairs:

PERIODIC_TABLE

This dictionary represents the periodic table, with Elements as keys and PeriodicTableEntrys as values.

CompoundDict

A dictionary that represents a chemical compound by mapping Elements to ints, where the values represent the number of atoms of an element in the compound.
    Example: \(\text{CO}_2\) would be represented by {'C': 1, 'O': 2}.

CompoundString

A string representation of a compound in chemical notation. To convert from a CompoundString to a CompoundDict, use the parse_compound function from support.parser.
    Example: \(\text{Fe}_2\text{O}_3\) would be represented by the CompoundString FeO'.

Side

A list of CompoundDicts, representing one side of a chemical equation (e.g., reactants on the left side, or products on the right side).
    Example: The left Side of the reaction \(2\text{CO} + \text{O}_2 \rightarrow 2\text{CO}_2\) would be [{'C': 1, 'O': 1}, {'O': 2}] and the right Side would be [{'C': 1, 'O': 2}].

SideList

A list of CompoundStrings for one side of an equation.

UnparsedEquation

A tuple containing the SideLists for the reactants and products of the equation.
    Example: For the reaction \(2\text{CO} + \text{O}_2 \rightarrow 2\text{CO}_2\), the UnparsedEquation would be (['CO', 'O₂'], ['CO₂']).

Solution

A dictionary with CompoundStrings as keys and int values. This type represents a solution to a chemical equation, where each compound is mapped to its coefficient in the balanced equation.
    Example: For the reaction \(2\text{CO} + \text{O}_2 \rightarrow 2\text{CO}_2\), the Solution would be {'CO': 2, 'O₂': 1, 'CO₂': 2}.

Math Type Definitions:

Fraction

A representation of fractions in python. Use frac = Fraction(p, q) to create a fraction called frac defined by \(\displaystyle \frac{p}{q}\). You can also use frac = Fraction(p) to create a fraction called frac defined by \(p\).

MutableRationalVector

A representation of a vector of rational numbers (i.e., Fractions) in python. You can use a MutableRationalVector in the following ways:

MutableRationalMatrix2D

A list of MutableRationalVectors that represents a 2D matrix. You can use a MutableRationalMatrix2D in the following ways: