pub(crate) fn precompile_airs_with_memory_events_per_row(
    ) -> impl Iterator<Item = (RiscvAirId, usize)> {
        let mut airs: HashSet<_> = Self::get_airs_and_costs().0.into_iter().collect();

        // Remove the core airs.
        for core_air in Self::get_all_core_airs() {
            airs.remove(&core_air);
        }

        // Remove the memory init/finalize airs.
        for memory_air in Self::memory_init_final_airs() {
            airs.remove(&memory_air);
        }

        // Remove the syscall, program, and byte lookup airs.
        airs.remove(&Self::SyscallPrecompile(SyscallChip::precompile()));
        airs.remove(&Self::Program(ProgramChip::default()));
        airs.remove(&Self::ByteLookup(ByteChip::default()));

        airs.into_iter().map(|air| {
            let chip = Chip::new(air);
            let local_mem_events_per_row: usize = chip
                .sends()
                .iter()
                .chain(chip.receives())
                .filter(|interaction| {
                    interaction.kind == InteractionKind::Memory &&
                        interaction.scope == InteractionScope::Local
                })
                .count();

            (chip.into_inner().id(), local_mem_events_per_row)
        })
    }
Returns the upper bound of the number of memory events per row of each precompile. Used in
shape-fitting.
crates/core/machine/src/riscv/mod.rs