This module provides a default set of reward functions.
import numpy as np
from chemistrylab import material
from chemistrylab.vessel import Vessel
from typing import NamedTuple, Tuple, Callable, Optional, List
def get_dissolved_amounts(vessel: Vessel, desired_material: str):
- The amount material that could be produced if you removed the solvent. This is the minimum of (quantity/stoich_coeff) for each dissolved component
- The amount of mols of solutes to subtract from the total material amount
material_amounts = 
dis_mats = material.REGISTRY[desired_material]().dissolve()
# Dissolved version is already the target material
if len(dis_mats) < 2: return 0,0
for mat in dis_mats:
#Can't make any with what's dissolved
if not mat._name in vessel.solute_dict: return 0,0
# Determine how much of the target the solute would make
amount = vessel.material_dict[mat._name].mol / dis_mats[mat]
if amount< min_amount:
RewardGenerator class generates rewards for a given set of vessels and desired materials.
use_purity (bool): True if reward is based on purity, False if reward is based on the amount of desired material.
exclude_solvents (bool): True if solvents should be excluded from the total amount of materials for purity calculations.
include_dissolved (bool): True if reward should include dissolved material components in the vessels as the desired material.
exclude_mat (str, optional): A string representing a material which gives a negative reward.
This class returns callable objects, which serve as reward functions
def __init__(self, use_purity, exclude_solvents, include_dissolved, exclude_mat=None):
def __call__(self,vessels: Tuple[Vessel], desired_material: str, exclude_material: Optional[str] = None):
Assign a reward to a set of vessels based off of what is desired/undesired
vessels (Tuple[Vessel]): A list of Vessel objects.
desired_material (str): A string representing the desired material for which the reward should be calculated.
exclude_material (Optional[str]): Currently unused
float: A floating point number representing the calculated reward.
for v in vessels:
mat_dict = v.material_dict
# Get the amount of target material that could be extracted from dissolved components
dissolved, exclude= get_dissolved_amounts(v,desired_material)
# Grab the amount of target material
amount=dissolved+(mat_dict[desired_material].mol if desired_material in mat_dict else 0)
if self.exclude_mat is not None and (self.exclude_mat != desired_material):
amount -= (mat_dict[self.exclude_mat].mol if self.exclude_mat in mat_dict else 0)
#Purity requires you to multiply by (desired_amount)/(total_amount)
#Total amount is either calculated using all materials, or just the non-solvents
all_mats = sum(mat.mol for key,mat in mat_dict.items() if not mat.is_solvent())
all_mats = sum(mat.mol for key,mat in mat_dict.items())
all_mats -= exclude
reward += amount**2/all_mats