Repository: HigherOrderCO/Bend
File: src/hvmc_net/pre_reduce.rs (Rust)

Code before:
// Reduce the compiled networks, solving any annihilations and commutations.
// This is a useful optimization on its own, but also required by an hvm-core optimization.

use crate::term::DefNames;
use hvmc::{
  ast::{book_from_runtime, name_to_val, net_from_runtime, net_to_runtime, runtime_net_to_runtime_def},
  run::{Heap, OP2, REF},
};
use std::collections::BTreeMap;

const MAX_ITERS: usize = 100_000;

/// Reduces the definitions in the book individually, except for main.
/// If cross_refs, will deref and try to find the smallest net.
/// Otherwise, just apply node~node interactions.
pub fn pre_reduce_book(book: &mut BTreeMap<String, hvmc::ast::Net>, cross_refs: bool) -> Result<(), String> {
  let mut rt_book = hvmc::ast::book_to_runtime(book);
  for (nam, net) in book.iter() {
    // Skip unnecessary work
    if net.rdex.is_empty() || nam == DefNames::ENTRY_POINT {
      continue;
    }
    let heap = Heap::init(1 << 18);
    let mut rt = hvmc::run::Net::new(&heap);
    let fid = name_to_val(nam);
    rt.boot(fid);
    rt.expand(&rt_book);

    let iters = if cross_refs {
      let mut iters = 0;
      // TODO: If I just call `rt.normal` some terms expand infinitely, so I put this workaround.
      // But I don't think this is the right way (even if it works).
      loop {
        iters += rt.reduce(&rt_book, MAX_ITERS);
        if rt.heap.get_root().is_ref() {
          rt.expand(&rt_book);
        } else {
          break;
        }
      }
      iters
    } else {
      reduce_without_deref(&mut rt, MAX_ITERS)
    };
    if iters > MAX_ITERS {

Review comment (suggestion):
Main still needs to be reduced to only have `REF` and `NUM` active pairs to run hvmc in compile mode.

We need to figure out a flag/options scheme to choose appropriately when to do no pre-reduction of main or minimal pre-reduction of main, but we definitely can't always skip it.

Code after:
// Reduce the compiled networks, solving any annihilations and commutations.
// This is a useful optimization on its own, but also required by an hvm-core optimization.

use crate::term::DefNames;
use hvmc::{
  ast::{book_from_runtime, name_to_val, net_from_runtime, net_to_runtime, runtime_net_to_runtime_def},
  run::{Heap, OP2, REF},
};
use std::collections::BTreeMap;

const MAX_ITERS: usize = 100_000;

/// Reduces the definitions in the book individually, except for main.
/// If cross_refs, will deref and try to find the smallest net.
/// Otherwise, just apply node~node interactions.
pub fn pre_reduce_book(book: &mut BTreeMap<String, hvmc::ast::Net>, cross_refs: bool) -> Result<(), String> {
  let mut rt_book = hvmc::ast::book_to_runtime(book);
  for (nam, net) in book.iter() {
    // Skip unnecessary work
    if net.rdex.is_empty() {
      continue;
    }
    let heap = Heap::init(1 << 18);
    let mut rt = hvmc::run::Net::new(&heap);
    let fid = name_to_val(nam);
    rt.boot(fid);
    rt.expand(&rt_book);

    let fully_reduce = cross_refs && nam != DefNames::ENTRY_POINT;
    let iters = if fully_reduce {
      let mut iters = 0;
      // TODO: If I just call `rt.normal` some terms expand infinitely, so I put this workaround.
      // But I don't think this is the right way (even if it works).
      loop {
        iters += rt.reduce(&rt_book, MAX_ITERS);
        if rt.heap.get_root().is_ref() {
          rt.expand(&rt_book);
        } else {
          break;
        }
      }
      iters
    } else {
      reduce_without_deref(&mut rt, MAX_ITERS)
    };