tl-lang 0.4.8

A differentiable programming language with tensor support for machine learning

    // Helper to infer free indices from implicit tensor equation (RHS)
    // Returns sorted list of unique variable names used as indices but not bound in scope
    fn infer_free_indices(&self, expr: &Expr) -> Vec<String> {
        let mut indices = std::collections::HashSet::new();
        self.collect_indices(expr, &mut indices);

        // Filter out variables that are defined in current scope (e.g. loops)
        // If a variable is NOT in scope, it is a free index (implicit dimension)
        let mut free_indices: Vec<String> = indices
            .into_iter()
            .filter(|idx| {
                // If variable exists in scope, it's a bound value/loop var, NOT a free dimension
                !self.variable_exists(idx)
            })
            .collect();
        
        free_indices.sort();
        free_indices
    }

    fn collect_indices(&self, expr: &Expr, indices: &mut std::collections::HashSet<String>) {
        match expr {
            Expr::IndexAccess(_, idxs) => {
                for idx in idxs {
                    if let Expr::Variable(name) = idx {
                        indices.insert(name.clone());
                    }
                    // Recursive check? Indices usually simple vars.
                }
            }
            Expr::BinOp(lhs, _, rhs) => {
                self.collect_indices(lhs, indices);
                self.collect_indices(rhs, indices);
            }
            Expr::UnOp(_, val) => {
                self.collect_indices(val, indices);
            }
            Expr::FnCall(_, args) | Expr::MethodCall(_, _, args) | Expr::StaticMethodCall(_, _, args)  => {
                 for arg in args {
                    self.collect_indices(arg, indices);
                 }
            }
            Expr::TensorLiteral(elems) => {
                for elem in elems {
                    self.collect_indices(elem, indices);
                }
            }
            Expr::IfExpr(cond, _, _) => {
                 self.collect_indices(cond, indices);
            }
            _ => {}
        }
    }
    
    fn variable_exists(&self, name: &str) -> bool {
         for scope in self.variables.iter().rev() {
            if scope.contains_key(name) {
                return true;
            }
         }
         false
    }