<commit_before>#ifndef HALIDE_FUNC_H
#define HALIDE_FUNC_H

/** \file
 *
 * Defines Func - the front-end handle on a halide function, and related classes.
 */

#include "IR.h"
#include "Var.h"
#include "Function.h"
#include "Param.h"
#include "OutputImageParam.h"
#include "Argument.h"
#include "RDom.h"
#include "JITModule.h"
#include "Image.h"
#include "Target.h"
#include "Tuple.h"
#include "Module.h"
#include "Pipeline.h"

#include <map>

namespace Halide {

/** A class that can represent Vars or RVars. Used for reorder calls
 * which can accept a mix of either. */
struct VarOrRVar {
    VarOrRVar(const std::string &n, bool r) : var(n), rvar(n), is_rvar(r) {}
    VarOrRVar(const Var &v) : var(v), is_rvar(false) {}
    VarOrRVar(const RVar &r) : rvar(r), is_rvar(true) {}
    VarOrRVar(const RDom &r) : rvar(RVar(r)), is_rvar(true) {}

    const std::string &name() const {
        if (is_rvar) return rvar.name();
        else return var.name();
    }

    Var var;
    RVar rvar;
    bool is_rvar;
};

namespace Internal {
struct Split;
struct StorageDim;
}

/** A single definition of a Func. May be a pure or update definition. */
class Stage {
    Internal::Definition definition;
    std::string stage_name;
    std::vector<Var> dim_vars; // Pure Vars of the Function (from the init definition)
    std::vector<Internal::StorageDim> storage_dims;

    void set_dim_type(VarOrRVar var, Internal::ForType t);
    void set_dim_device_api(VarOrRVar var, DeviceAPI device_api);
    void split(const std::string &old, const std::string &outer, const std::string &inner,
               Expr factor, bool exact, TailStrategy tail);
    void remove(const std::string &var);
    Stage &purify(VarOrRVar old_name, VarOrRVar new_name);

public:
    Stage(Internal::Definition d, const std::string &n, const std::vector<Var> &args,
          const std::vector<Internal::StorageDim> &sdims)
            : definition(d), stage_name(n), dim_vars(args), storage_dims(sdims) {
        internal_assert(definition.args().size() == dim_vars.size());
        definition.schedule().touched() = true;
    }

    Stage(Internal::Definition d, const std::string &n, const std::vector<std::string> &args,
          const std::vector<Internal::StorageDim> &sdims)
            : definition(d), stage_name(n), storage_dims(sdims) {
        definition.schedule().touched() = true;

        std::vector<Var> dim_vars(args.size());
        for (size_t i = 0; i < args.size(); i++) {
            dim_vars[i] = Var(args[i]);
        }
        internal_assert(definition.args().size() == dim_vars.size());
    }

    /** Return the current Schedule associated with this Stage.  For
     * introspection only: to modify Schedule, use the Func
     * interface. */
    const Internal::Schedule &get_schedule() const { return definition.schedule(); }

    /** Return a string describing the current var list taking into
     * account all the splits, reorders, and tiles. */
    EXPORT std::string dump_argument_list() const;

    /** Return the name of this stage, e.g. "f.update(2)" */
    EXPORT const std::string &name() const;

    /** Calling rfactor() on an associative update definition a Func will split
     * the update into an intermediate which computes the partial results and
     * replace the current update definition with a new definition which merges
     * the partial results. If called on a init/pure definition, this will
     * throw an error. rfactor() will automatically infer the associative reduction
     * operator and identity of the operator. If it can't prove the operation
     * is associative or if it cannot find an identity for that operator, this
     * will throw an error.
     *
     * rfactor() takes as input 'preserved', which is a list of <RVar, Var> pairs.
     * The rvars not listed in 'preserved' are removed from the original Func and
     * are lifted to the intermediate Func. The remaining rvars (the ones in
     * 'preserved') are made pure in the intermediate Func. The intermediate Func's
     * update definition inherits all scheduling directives (e.g. split,fuse, etc.)
     * applied to the original Func's update definition. The loop order of the
     * intermediate Func's update definition is the same as the original, albeit
     * the lifted RVars are replaced by the new pure Vars. The loop order of the
     * intermediate Func's init definition from innermost to outermost is the args'
     * order of the original Func's init definition followed by the new pure Vars.
     *
     * The intermediate Func also inherits storage order from the original Func
     * with the new pure Vars added to the outermost.
     *
     * For example, f.update(0).rfactor({{r.y, u}}) would rewrite a pipeline like this:
     \code
     f(x, y) = 0;
     f(x, y) += g(r.x, r.y);
     \endcode
     * into a pipeline like this:
     \code
     f_intm(x, y, u) = 0;
     f_intm(x, y, u) += g(r.x, u);

     f(x, y) = 0;
     f(x, y) = f_intm(x, y, r.y);
     \endcode
     *
     * This has a variety of uses. You can use it to split computation of an associative reduction:
     \code
     f(x, y) = 10;
     RDom r(0, 96);
     f(x, y) = max(f(x, y), g(x, y, r.x));
     f.update(0).split(r.x, rxo, rxi, 8).reorder(y, x).parallel(x);<commit_msg>Fix documentation typo.<commit_after>#ifndef HALIDE_FUNC_H
#define HALIDE_FUNC_H

/** \file
 *
 * Defines Func - the front-end handle on a halide function, and related classes.
 */

#include "IR.h"
#include "Var.h"
#include "Function.h"
#include "Param.h"
#include "OutputImageParam.h"
#include "Argument.h"
#include "RDom.h"
#include "JITModule.h"
#include "Image.h"
#include "Target.h"
#include "Tuple.h"
#include "Module.h"
#include "Pipeline.h"

#include <map>

namespace Halide {

/** A class that can represent Vars or RVars. Used for reorder calls
 * which can accept a mix of either. */
struct VarOrRVar {
    VarOrRVar(const std::string &n, bool r) : var(n), rvar(n), is_rvar(r) {}
    VarOrRVar(const Var &v) : var(v), is_rvar(false) {}
    VarOrRVar(const RVar &r) : rvar(r), is_rvar(true) {}
    VarOrRVar(const RDom &r) : rvar(RVar(r)), is_rvar(true) {}

    const std::string &name() const {
        if (is_rvar) return rvar.name();
        else return var.name();
    }

    Var var;
    RVar rvar;
    bool is_rvar;
};

namespace Internal {
struct Split;
struct StorageDim;
}

/** A single definition of a Func. May be a pure or update definition. */
class Stage {
    Internal::Definition definition;
    std::string stage_name;
    std::vector<Var> dim_vars; // Pure Vars of the Function (from the init definition)
    std::vector<Internal::StorageDim> storage_dims;

    void set_dim_type(VarOrRVar var, Internal::ForType t);
    void set_dim_device_api(VarOrRVar var, DeviceAPI device_api);
    void split(const std::string &old, const std::string &outer, const std::string &inner,
               Expr factor, bool exact, TailStrategy tail);
    void remove(const std::string &var);
    Stage &purify(VarOrRVar old_name, VarOrRVar new_name);

public:
    Stage(Internal::Definition d, const std::string &n, const std::vector<Var> &args,
          const std::vector<Internal::StorageDim> &sdims)
            : definition(d), stage_name(n), dim_vars(args), storage_dims(sdims) {
        internal_assert(definition.args().size() == dim_vars.size());
        definition.schedule().touched() = true;
    }

    Stage(Internal::Definition d, const std::string &n, const std::vector<std::string> &args,
          const std::vector<Internal::StorageDim> &sdims)
            : definition(d), stage_name(n), storage_dims(sdims) {
        definition.schedule().touched() = true;

        std::vector<Var> dim_vars(args.size());
        for (size_t i = 0; i < args.size(); i++) {
            dim_vars[i] = Var(args[i]);
        }
        internal_assert(definition.args().size() == dim_vars.size());
    }

    /** Return the current Schedule associated with this Stage.  For
     * introspection only: to modify Schedule, use the Func
     * interface. */
    const Internal::Schedule &get_schedule() const { return definition.schedule(); }

    /** Return a string describing the current var list taking into
     * account all the splits, reorders, and tiles. */
    EXPORT std::string dump_argument_list() const;

    /** Return the name of this stage, e.g. "f.update(2)" */
    EXPORT const std::string &name() const;

    /** Calling rfactor() on an associative update definition a Func will split
     * the update into an intermediate which computes the partial results and
     * replace the current update definition with a new definition which merges
     * the partial results. If called on a init/pure definition, this will
     * throw an error. rfactor() will automatically infer the associative reduction
     * operator and identity of the operator. If it can't prove the operation
     * is associative or if it cannot find an identity for that operator, this
     * will throw an error.
     *
     * rfactor() takes as input 'preserved', which is a list of <RVar, Var> pairs.
     * The rvars not listed in 'preserved' are removed from the original Func and
     * are lifted to the intermediate Func. The remaining rvars (the ones in
     * 'preserved') are made pure in the intermediate Func. The intermediate Func's
     * update definition inherits all scheduling directives (e.g. split,fuse, etc.)
     * applied to the original Func's update definition. The loop order of the
     * intermediate Func's update definition is the same as the original, albeit
     * the lifted RVars are replaced by the new pure Vars. The loop order of the
     * intermediate Func's init definition from innermost to outermost is the args'
     * order of the original Func's init definition followed by the new pure Vars.
     *
     * The intermediate Func also inherits storage order from the original Func
     * with the new pure Vars added to the outermost.
     *
     * For example, f.update(0).rfactor({{r.y, u}}) would rewrite a pipeline like this:
     \code
     f(x, y) = 0;
     f(x, y) += g(r.x, r.y);
     \endcode
     * into a pipeline like this:
     \code
     f_intm(x, y, u) = 0;
     f_intm(x, y, u) += g(r.x, u);

     f(x, y) = 0;
     f(x, y) += f_intm(x, y, r.y);
     \endcode
     *
     * This has a variety of uses. You can use it to split computation of an associative reduction:
     \code
     f(x, y) = 10;
     RDom r(0, 96);
     f(x, y) = max(f(x, y), g(x, y, r.x));
     f.update(0).split(r.x, rxo, rxi, 8).reorder(y, x).parallel(x);
{'fraction_non_alphanumeric': 0.11736867013724563, 'fraction_numerical': 0.0024609559867486987, 'mean_word_length': 3.1533018867924527, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1713572', 'n_tokens_mistral': 3352, 'n_tokens_neox': 3281, 'n_words': 1183}