Skip to content

include/tenzr/frontend/node.h

Namespaces

Name
tenzr

Classes

Name
class tenzr::Node
class tenzr::VariableNode
class tenzr::AddNode
Elementwise addition of two operands.
class tenzr::MulNode
Elementwise multiplication of two operands.
class tenzr::SubNode
Elementwise subtraction of two operands.
class tenzr::DivNode
Elementwise division of two operands.
class tenzr::MatmulNode
Matrix multiplication of two operands.
class tenzr::ConvolutionNode
class tenzr::ReshapeNode
View of an operand reshaped to a new shape.
class tenzr::TransposeNode
View of an operand with its dimensions reordered by a permutation.
class tenzr::SliceNode
View of an operand restricted by per-axis slice bounds.
class tenzr::PadNode
Pad an operand with a fill value at the edges and between elements.
class tenzr::GatherNode
Gather slices of an operand at the given indices.
class tenzr::ScatterNode
class tenzr::DynamicSliceNode
class tenzr::DynamicUpdateSliceNode
class tenzr::ArgSortNode
class tenzr::ConcatenateNode
Join multiple operands along an axis.
class tenzr::ReluNode
Elementwise rectified linear unit.
class tenzr::SigmoidNode
Elementwise logistic sigmoid.
class tenzr::CustomOpNode
Node backed by a custom operator registered in the OpRegistry.
class tenzr::ConvertNode
Convert an operand to another element type.
class tenzr::ReduceNode
class tenzr::ReduceWindowNode

Source code

// Copyright 2026 The Tenzr Project Authors
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef TENZR_FRONTEND_NODE_H_
#define TENZR_FRONTEND_NODE_H_

#include <atomic>
#include <memory>
#include <string>
#include <vector>

#include "tenzr/frontend/dtype.h"
#include "tenzr/frontend/layout.h"
#include "tenzr/frontend/memory_pool.h"
#include "tenzr/frontend/shape.h"
#include "tenzr/frontend/sharding.h"
#include "tenzr/runtime/device_buffer.h"

namespace tenzr {

  struct OpDef;

  enum class NodeKind {
    kVariable,
    kAdd,
    kMul,
    kSub,
    kDiv,
    kMatmul,
    kConvolution,
    kReshape,
    kTranspose,
    kSlice,
    kRelu,
    kSigmoid,
    kCustomOp,
    kConvert,
    kReduce,
    kReduceWindow,
    kPad,
    kGather,
    kScatter,
    kDynamicSlice,
    kDynamicUpdateSlice,
    kArgSort,
    kConcatenate
  };

  class Node : public std::enable_shared_from_this<Node> {
   public:
    Node(NodeKind kind, Shape shape, DType dtype, ShardingSpec sharding = ShardingSpec::Replicated());
    virtual ~Node() = default;

    NodeKind Kind() const { return kind_; }

    const Shape& shape() const { return shape_; }

    DType Dtype() const { return dtype_; }

    const ShardingSpec& Sharding() const { return sharding_; }

    void SetSharding(ShardingSpec spec) { sharding_ = std::move(spec); }

    const StridedLayout& Layout() const { return layout_; }

    void SetLayout(StridedLayout layout) { layout_ = std::move(layout); }

    const std::vector<std::shared_ptr<Node>>& Inputs() const { return inputs_; }

    uint64_t Id() const { return id_; }

    virtual std::string OpName() const = 0;

   protected:
    NodeKind kind_;
    Shape shape_;
    DType dtype_;
    ShardingSpec sharding_;
    StridedLayout layout_;
    std::vector<std::shared_ptr<Node>> inputs_;
    uint64_t id_;

    static uint64_t NextId();
  };

  class VariableNode : public Node {
   public:
    VariableNode(Shape shape, DType dtype, std::string name = "", ShardingSpec sharding = ShardingSpec::Replicated());

    std::string OpName() const override { return "Variable"; }

    const std::string& VariableName() const { return name_; }

    void SetData(std::shared_ptr<PinnedBuffer> data);

    const std::shared_ptr<PinnedBuffer>& Data() const;

    bool HasData() const;

    void SetDeviceData(std::shared_ptr<DeviceBuffer> device_data);

    const std::shared_ptr<DeviceBuffer>& DeviceData() const;

    bool HasDeviceData() const;

    void SyncHost();

    void SyncDevice();

   private:
    std::string name_;
    mutable std::shared_ptr<PinnedBuffer> data_;
    std::shared_ptr<DeviceBuffer> device_data_;
  };

  class AddNode : public Node {
   public:
    AddNode(std::shared_ptr<Node> lhs, std::shared_ptr<Node> rhs);

    std::string OpName() const override { return "Add"; }

    const std::shared_ptr<Node>& Lhs() const { return inputs_[0]; }
    const std::shared_ptr<Node>& Rhs() const { return inputs_[1]; }
  };

  class MulNode : public Node {
   public:
    MulNode(std::shared_ptr<Node> lhs, std::shared_ptr<Node> rhs);

    std::string OpName() const override { return "Mul"; }

    const std::shared_ptr<Node>& Lhs() const { return inputs_[0]; }
    const std::shared_ptr<Node>& Rhs() const { return inputs_[1]; }
  };

  class SubNode : public Node {
   public:
    SubNode(std::shared_ptr<Node> lhs, std::shared_ptr<Node> rhs);

    std::string OpName() const override { return "Sub"; }

    const std::shared_ptr<Node>& Lhs() const { return inputs_[0]; }
    const std::shared_ptr<Node>& Rhs() const { return inputs_[1]; }
  };

  class DivNode : public Node {
   public:
    DivNode(std::shared_ptr<Node> lhs, std::shared_ptr<Node> rhs);

    std::string OpName() const override { return "Div"; }

    const std::shared_ptr<Node>& Lhs() const { return inputs_[0]; }
    const std::shared_ptr<Node>& Rhs() const { return inputs_[1]; }
  };

  class MatmulNode : public Node {
   public:
    MatmulNode(std::shared_ptr<Node> lhs, std::shared_ptr<Node> rhs);

    std::string OpName() const override { return "Matmul"; }

    const std::shared_ptr<Node>& Lhs() const { return inputs_[0]; }
    const std::shared_ptr<Node>& Rhs() const { return inputs_[1]; }
  };

  class ConvolutionNode : public Node {
   public:
    ConvolutionNode(std::shared_ptr<Node> input, std::shared_ptr<Node> kernel, std::vector<int64_t> window_strides, std::vector<int64_t> lhs_dilation,
                    std::vector<int64_t> rhs_dilation, std::vector<int64_t> padding_low, std::vector<int64_t> padding_high);

    std::string OpName() const override { return "Convolution"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }

    const std::shared_ptr<Node>& Kernel() const { return inputs_[1]; }

    const std::vector<int64_t>& WindowStrides() const { return window_strides_; }

    const std::vector<int64_t>& LhsDilation() const { return lhs_dilation_; }

    const std::vector<int64_t>& RhsDilation() const { return rhs_dilation_; }

    const std::vector<int64_t>& PaddingLow() const { return padding_low_; }

    const std::vector<int64_t>& PaddingHigh() const { return padding_high_; }

   private:
    std::vector<int64_t> window_strides_;
    std::vector<int64_t> lhs_dilation_;
    std::vector<int64_t> rhs_dilation_;
    std::vector<int64_t> padding_low_;
    std::vector<int64_t> padding_high_;
  };

  class ReshapeNode : public Node {
   public:
    ReshapeNode(std::shared_ptr<Node> input, Shape new_shape);

    std::string OpName() const override { return "Reshape"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }
  };

  class TransposeNode : public Node {
   public:
    TransposeNode(std::shared_ptr<Node> input, std::vector<int64_t> permutation);

    std::string OpName() const override { return "Transpose"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }

    const std::vector<int64_t>& Permutation() const { return permutation_; }

   private:
    std::vector<int64_t> permutation_;
  };

  class SliceNode : public Node {
   public:
    SliceNode(std::shared_ptr<Node> input, std::vector<Slice> slices);

    std::string OpName() const override { return "Slice"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }

    const std::vector<Slice>& Slices() const { return slices_; }

   private:
    std::vector<Slice> slices_;
  };

  class PadNode : public Node {
   public:
    PadNode(std::shared_ptr<Node> operand, std::shared_ptr<Node> padding_value, std::vector<int64_t> edge_padding_low, std::vector<int64_t> edge_padding_high,
            std::vector<int64_t> interior_padding);

    std::string OpName() const override { return "Pad"; }

    const std::shared_ptr<Node>& Operand() const { return inputs_[0]; }

    const std::shared_ptr<Node>& PaddingValue() const { return inputs_[1]; }

    const std::vector<int64_t>& EdgePaddingLow() const { return low_; }

    const std::vector<int64_t>& EdgePaddingHigh() const { return high_; }

    const std::vector<int64_t>& InteriorPadding() const { return interior_; }

   private:
    std::vector<int64_t> low_;
    std::vector<int64_t> high_;
    std::vector<int64_t> interior_;
  };

  class GatherNode : public Node {
   public:
    GatherNode(std::shared_ptr<Node> operand, std::shared_ptr<Node> indices);

    std::string OpName() const override { return "Gather"; }

    const std::shared_ptr<Node>& Operand() const { return inputs_[0]; }
    const std::shared_ptr<Node>& Indices() const { return inputs_[1]; }
  };

  class ScatterNode : public Node {
   public:
    ScatterNode(std::shared_ptr<Node> operand, std::shared_ptr<Node> indices, std::shared_ptr<Node> updates, std::string update_op = "add");

    std::string OpName() const override { return update_op_ == "add" ? "ScatterAdd" : "Scatter"; }

    const std::string& UpdateOp() const { return update_op_; }

    const std::shared_ptr<Node>& Operand() const { return inputs_[0]; }

    const std::shared_ptr<Node>& Indices() const { return inputs_[1]; }

    const std::shared_ptr<Node>& Updates() const { return inputs_[2]; }

   private:
    std::string update_op_;
  };

  class DynamicSliceNode : public Node {
   public:
    DynamicSliceNode(std::shared_ptr<Node> operand, std::vector<std::shared_ptr<Node>> start_indices, std::vector<int64_t> slice_sizes);

    std::string OpName() const override { return "DynamicSlice"; }

    const std::shared_ptr<Node>& Operand() const { return inputs_[0]; }

    const std::vector<int64_t>& SliceSizes() const { return slice_sizes_; }

   private:
    std::vector<int64_t> slice_sizes_;
  };

  class DynamicUpdateSliceNode : public Node {
   public:
    DynamicUpdateSliceNode(std::shared_ptr<Node> operand, std::shared_ptr<Node> update, std::vector<std::shared_ptr<Node>> start_indices);

    std::string OpName() const override { return "DynamicUpdateSlice"; }

    const std::shared_ptr<Node>& Operand() const { return inputs_[0]; }
    const std::shared_ptr<Node>& Update() const { return inputs_[1]; }
  };

  class ArgSortNode : public Node {
   public:
    ArgSortNode(std::shared_ptr<Node> values, std::shared_ptr<Node> indices, bool descending = false, int64_t axis = 0, bool return_values = false);

    std::string OpName() const override { return return_values_ ? "SortValues" : "ArgSort"; }

    const std::shared_ptr<Node>& Values() const { return inputs_[0]; }

    const std::shared_ptr<Node>& Indices() const { return inputs_[1]; }

    bool Descending() const { return descending_; }

    int64_t Axis() const { return axis_; }

    bool ReturnValues() const { return return_values_; }

   private:
    bool descending_{false};
    int64_t axis_{0};
    bool return_values_{false};
  };

  class ConcatenateNode : public Node {
   public:
    ConcatenateNode(std::vector<std::shared_ptr<Node>> inputs, int64_t axis);

    std::string OpName() const override { return "Concat"; }

    int64_t Axis() const { return axis_; }

   private:
    int64_t axis_{0};
  };

  class ReluNode : public Node {
   public:
    explicit ReluNode(std::shared_ptr<Node> input);
    std::string OpName() const override { return "Relu"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }
  };

  class SigmoidNode : public Node {
   public:
    explicit SigmoidNode(std::shared_ptr<Node> input);

    std::string OpName() const override { return "Sigmoid"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }
  };

  class CustomOpNode : public Node {
   public:
    CustomOpNode(std::string op_name, std::vector<std::shared_ptr<Node>> inputs, const OpDef* Definition = nullptr);

    std::string OpName() const override { return op_name_str_; }

    const OpDef* Definition() const { return op_def_; }

   private:
    std::string op_name_str_;
    const OpDef* op_def_{nullptr};
  };

  class ConvertNode : public Node {
   public:
    ConvertNode(std::shared_ptr<Node> input, DType target_dtype);

    std::string OpName() const override { return "Convert"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }
  };

  enum class ReduceOp { kSum, kProd, kMax, kMin };

  class ReduceNode : public Node {
   public:
    ReduceNode(std::shared_ptr<Node> input, ReduceOp Reduction, std::vector<int64_t> dimensions, bool keepdims);

    std::string OpName() const override;

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }

    ReduceOp Reduction() const { return reduce_op_; }

    const std::vector<int64_t>& Dimensions() const { return dimensions_; }

    const std::vector<int64_t>& CanonicalDimensions() const { return canonical_dimensions_; }

    bool Keepdims() const { return keepdims_; }

    const Shape& NonKeepdimsShape() const { return non_keepdims_shape_; }

    Shape ExpandedShape() const;

   private:
    ReduceOp reduce_op_;
    std::vector<int64_t> dimensions_;
    std::vector<int64_t> canonical_dimensions_;
    bool keepdims_;
    Shape non_keepdims_shape_;
  };

  class ReduceWindowNode : public Node {
   public:
    ReduceWindowNode(std::shared_ptr<Node> input, std::shared_ptr<Node> init_value, std::vector<int64_t> window_dimensions, std::vector<int64_t> window_strides,
                     std::vector<int64_t> padding_low, std::vector<int64_t> padding_high, std::vector<int64_t> window_dilations, std::string Reduction);

    std::string OpName() const override { return "ReduceWindow"; }

    const std::shared_ptr<Node>& Input() const { return inputs_[0]; }

    const std::shared_ptr<Node>& InitValue() const { return inputs_[1]; }

    const std::vector<int64_t>& WindowDimensions() const { return window_dimensions_; }

    const std::vector<int64_t>& WindowStrides() const { return window_strides_; }

    const std::vector<int64_t>& PaddingLow() const { return padding_low_; }

    const std::vector<int64_t>& PaddingHigh() const { return padding_high_; }

    const std::vector<int64_t>& WindowDilations() const { return window_dilations_; }

    const std::string& Reduction() const { return reduce_op_; }

   private:
    std::vector<int64_t> window_dimensions_;
    std::vector<int64_t> window_strides_;
    std::vector<int64_t> padding_low_;
    std::vector<int64_t> padding_high_;
    std::vector<int64_t> window_dilations_;
    std::string reduce_op_;
  };

}  // namespace tenzr

#endif  // TENZR_FRONTEND_NODE_H_