1#ifndef TMVA_SOFIE_SOFIE_COMMON
2#define TMVA_SOFIE_SOFIE_COMMON
29 UNDEFINED = 0,
FLOAT = 1,
UINT8 = 2,
INT8 = 3,
UINT16 = 4,
INT16 = 5,
INT32 = 6,
INT64 = 7,
STRING = 8,
BOOL = 9,
99 return !(*
this == rhs);
129 static bool IsDim() {
return true; }
133 static bool IsDim() {
return false; }
141 static const std::string
Name() {
return "float"; }
145 static const std::string
Name() {
return "double"; }
149 static const std::string
Name() {
return "int64_t"; }
153 static const std::string
Name() {
return "int32_t"; }
157 static const std::string
Name() {
return "uint32_t"; }
161 static const std::string
Name() {
return "uint64_t"; }
165 static const std::string
Name() {
return "bool"; }
169 static const std::string
Name() {
return "int8_t"; }
173 static const std::string
Name() {
return "uint8_t"; }
182 throw std::invalid_argument(
"New size exceeds available tensor size.");
217 std::stringstream ret;
218 ret << std::to_string(
value);
224 std::stringstream ret;
226 if (std::isinf(
value))
227 ret << (
value > 0 ?
"std::numeric_limits<float>::infinity()" :
228 "-std::numeric_limits<float>::infinity()");
229 else if (std::isnan(
value))
230 ret <<
"std::numeric_limits<float>::quiet_NaN()";
232 ret << std::setprecision(std::numeric_limits<float>::max_digits10);
240 std::stringstream ret;
242 if (std::isinf(
value))
243 ret << (
value > 0 ?
"std::numeric_limits<double>::infinity()" :
244 "-std::numeric_limits<double>::infinity()");
245 else if (std::isnan(
value))
246 ret <<
"std::numeric_limits<double>::quiet_NaN()";
248 ret << std::setprecision(std::numeric_limits<double>::max_digits10);
256 std::stringstream ret;
257 if (
value == INT64_MIN)
260 ret << std::to_string(
value);
268 std::stringstream ret;
270 for (
size_t i = 0; i < std::min(
n,maxprint); i++) {
272 if (i <
n-1) ret <<
", ";
273 if (i <
n-1 && i == maxprint-1) ret <<
"..... ";
309 template <
class T =
void>
312 return static_cast<T
const *
>(
fData.get());
320 for (std::size_t item :
fShape) {
321 fSize *=
static_cast<int>(item);
383std::string
Clean_name(std::string input_tensor_name);
386bool AreSameShape(
const std::vector<size_t>&,
const std::vector<size_t>&);
387bool AreSameShape(
const std::vector<size_t>&,
const std::vector<Dim>&);
388bool AreSameShape(
const std::vector<Dim>&,
const std::vector<Dim>&);
405 size_t size = targetShape.size();
406 if (targetShape[1] != channel) {
407 std::stringstream ss;
408 ss <<
"TMVA::SOFIE - Error broadcasting Conv Bias of shape {";
409 ss << std::to_string(channel);
413 std::runtime_error(ss.str());
417 T* newData =
new T[targetLength];
419 if (targetLength == channel) {
420 std::copy(
data,
data + channel, newData);
426 for (
size_t i = 2; i <
size; i++)
427 cStride *= targetShape[i];
430 for (
size_t i = 0; i < channel; i++) {
431 std::fill(newData + i * cStride, newData + (i + 1) * cStride,
data[i]);
434 size_t batch = targetShape[0];
435 size_t bStride = channel * cStride;
436 for (
size_t i = 1; i < batch; i++) {
437 std::copy(newData, newData + bStride, newData + i * bStride);
445template<
typename T,
class ConstContT = std::span<const T>>
446void BroadcastTensor(ConstContT
data,
const std::vector<size_t>& shape,
const std::vector<size_t>& targetShape, T *broadcastedData) {
448 size_t size = shape.size();
450 size_t curLength =
data.size();
452 if (
size > 1 && shape.front() == targetShape.front() && shape.back() == 1) {
453 size_t bsize = targetShape.back();
455 for (
int k =
int(
size)-2; k >=0; k--) {
456 if (shape[k] != 1)
break;
457 bsize *= targetShape[k];
459 for (
size_t i = 0; i < curLength; i++) {
460 std::fill(broadcastedData + i*bsize, broadcastedData + (i+1)*bsize ,
data[i]);
465 std::copy(
data.begin(),
data.end(), broadcastedData);
471 for (
size_t idx = 0; idx <
size; idx++) {
472 size_t dim = shape[idx];
473 size_t targetDim = targetShape[idx];
474 if (dim == 1 && targetDim > 1) {
476 size_t newLength = curLength * targetDim;
478 size_t arrayLength = curLength / arrayNum;
480 if (arrayLength > 1) {
482 for (
size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
483 for (
size_t targetIdx = 0; targetIdx < targetDim; targetIdx++) {
484 size_t offset = arrayIdx * arrayLength * targetDim + targetIdx * arrayLength;
485 std::copy(broadcastedData + arrayIdx * arrayLength,
486 broadcastedData + (arrayIdx + 1) * arrayLength,
487 newData.begin() +
offset);
492 for (
size_t arrayIdx = 0; arrayIdx < arrayNum; arrayIdx++) {
493 std::fill(newData.begin() + arrayIdx * targetDim,
494 newData.begin() + (arrayIdx + 1) * targetDim, broadcastedData[arrayIdx]);
498 curLength = newLength;
500 std::copy(newData.begin(), newData.begin() + newLength, broadcastedData);
503 arrayNum *= targetDim;
511 T* broadcastedData =
new T[targetLength];
514 return broadcastedData;
521 if (shape.size() < targetShape.size()) {
522 size_t targetSize = targetShape.size();
523 std::vector<size_t> newShape(targetSize, 1);
524 size_t offset = targetSize - shape.size();
525 std::copy(shape.begin(), shape.end(), newShape.begin() +
offset);
535 std::span<T> inData(
const_cast<T*
>(
data), curLength);
537 if (shape.size() < targetShape.size()) {
538 size_t targetSize = targetShape.size();
539 std::vector<size_t> newShape(targetSize, 1);
540 size_t offset = targetSize - shape.size();
541 std::copy(shape.begin(), shape.end(), newShape.begin() +
offset);
554 return static_cast<unsigned>(
a) <
static_cast<unsigned>(
b);
578void Im2col(
const T *data_im,
const int channels,
const int height,
const int width,
const int kernel_h,
579 const int kernel_w,
const int pad_h,
const int pad_w,
const int stride_h,
const int stride_w,
580 const int dilation_h,
const int dilation_w, T *data_col)
582 const int output_h = (
height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
583 const int output_w = (
width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
585 for (
int channel = channels; channel--; data_im += channel_size) {
586 for (
int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
587 for (
int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
588 int input_row = -pad_h + kernel_row * dilation_h;
589 for (
int output_rows = output_h; output_rows; output_rows--) {
591 for (
int output_cols = output_w; output_cols; output_cols--) {
595 int input_col = -pad_w + kernel_col * dilation_w;
596 for (
int output_col = output_w; output_col; output_col--) {
598 *(data_col++) = data_im[input_row *
width + input_col];
602 input_col += stride_w;
605 input_row += stride_h;
615 const int depth,
const int height,
const int width,
616 const int kernel_d,
const int kernel_h,
const int kernel_w,
617 const int pad_d,
const int pad_h,
const int pad_w,
618 const int stride_d,
const int stride_h,
const int stride_w,
619 const int dilation_d,
const int dilation_h,
const int dilation_w, T *data_col)
621 const int output_h = (
height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
622 const int output_w = (
width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
623 const int output_d = (depth + 2 * pad_d - (dilation_d * (kernel_d - 1) + 1)) / stride_d + 1;
626 for (
int channel = channels; channel--; data_im += channel_size) {
627 for (
int kernel_depth = 0; kernel_depth < kernel_d; kernel_depth++) {
628 for (
int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
629 for (
int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
630 int input_dep = -pad_d + kernel_depth * dilation_d;
631 for (
int output_dep = output_d; output_dep; output_dep--) {
633 for (
int output_rows = output_h; output_rows; output_rows--) {
634 for (
int output_cols = output_w; output_cols; output_cols--) {
639 int input_row = -pad_h + kernel_row * dilation_h;
640 for (
int output_rows = output_h; output_rows; output_rows--) {
642 for (
int output_cols = output_w; output_cols; output_cols--) {
646 int input_col = -pad_w + kernel_col * dilation_w;
647 for (
int output_col = output_w; output_col; output_col--) {
649 *(data_col++) = data_im[input_dep *
width *
height + input_row *
width + input_col];
653 input_col += stride_w;
656 input_row += stride_h;
659 input_dep += stride_d;
667template <
typename Dtype>
668void col2im(
const Dtype* data_col,
const int channels,
669 const int height,
const int width,
const int kernel_h,
const int kernel_w,
670 const int pad_h,
const int pad_w,
671 const int stride_h,
const int stride_w,
672 const int dilation_h,
const int dilation_w,
675 std::fill(data_im, data_im +
height *
width * channels, 0.);
679 const int output_h = (
height + 2 * pad_h -
680 (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
681 const int output_w = (
width + 2 * pad_w -
682 (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
684 for (
int channel = channels; channel--; data_im += channel_size) {
685 for (
int kernel_row = 0; kernel_row < kernel_h; kernel_row++) {
686 for (
int kernel_col = 0; kernel_col < kernel_w; kernel_col++) {
687 int input_row = -pad_h + kernel_row * dilation_h;
688 for (
int output_rows = output_h; output_rows; output_rows--) {
690 data_col += output_w;
692 int input_col = -pad_w + kernel_col * dilation_w;
693 for (
int output_col = output_w; output_col; output_col--) {
700 data_im[input_row *
width + input_col] += *data_col;
703 input_col += stride_w;
706 input_row += stride_h;
717extern "C" void sgemm_(
const char * transa,
const char * transb,
const int *
m,
const int *
n,
const int * k,
718 const float * alpha,
const float * A,
const int * lda,
const float * B,
const int * ldb,
719 const float * beta,
float * C,
const int * ldc);
741 throw std::runtime_error(
"TMVA RTensor Concatenate - tensors have different memory layout");
742 auto & shape1 =
t1.GetShape();
744 if (
t1.GetSize()/shape1[axis] != t2.
GetSize()/shape2[axis]) {
745 std::cout <<
"axis " << axis <<
" sizes " <<
t1.GetSize() <<
" " << t2.
GetSize() <<
" ";
748 throw std::runtime_error(
"TMVA RTensor Concatenate - tensors have incompatible shapes");
750 std::vector<size_t> outShape = shape1;
751 outShape[axis] = shape1[axis] + shape2[axis];
753 if (
t1.GetMemoryLayout() == TMVA::Experimental::MemoryLayout::ColumnMajor) {
754 throw std::runtime_error(
"TMVA RTensor Concatenate is not yet supported for column major tensors");
757 auto & stride1 =
t1.GetStrides();
761 size_t s1 = (axis > 0) ? stride1[axis-1] :
t1.GetSize();
762 size_t s2 = (axis > 0) ? stride2[axis-1] : t2.
GetSize();
763 size_t sout = (axis > 0) ? outStride[axis-1] : tout.
GetSize();
764 size_t nb =
t1.GetSize()/
s1;
765 for (
size_t i = 0; i < nb; i++) {
766 std::copy(
t1.GetData() + i*
s1,
t1.GetData() + (i+1)*
s1, tout.
GetData() + i * sout );
797inline void Gemm_Call(
float *output,
bool transa,
bool transb,
int m,
int n,
int k,
float alpha,
const float *A,
798 const float *B,
float beta,
const float *C)
802 const int *lda = transa ? &k : &
m;
803 const int *ldb = transb ? &
n : &k;
806 std::copy(C, C +
m *
n, output);
808 TMVA::Experimental::SOFIE::BLAS::sgemm_(transa ? &ct : &cn, transb ? &ct : &cn, &
m, &
n, &k, &alpha, A, lda, B, ldb,
825 for (
int i = 0; i <
size; i++) {
826 output[i] = (
input[i] > 0.0f) ?
input[i] : 0.0f;
831 if (s ==
"inf")
return std::numeric_limits<float>::infinity();
832 if (s ==
"-inf")
return -std::numeric_limits<float>::infinity();
833 if (s ==
"nan")
return std::numeric_limits<float>::quiet_NaN();
843 if (
name != expectedName) {
844 std::string err_msg =
845 "TMVA-SOFIE failed to read the correct tensor name; expected name is " + expectedName +
" , read " +
name;
846 throw std::runtime_error(err_msg);
848 if (
length != expectedLength) {
849 std::string err_msg =
"TMVA-SOFIE failed to read the correct tensor size; expected size is " +
850 std::to_string(expectedLength) +
" , read " + std::to_string(
length);
851 throw std::runtime_error(err_msg);
854 for (
size_t i = 0; i <
length; ++i) {
859 throw std::runtime_error(
"TMVA-SOFIE failed to read the values for tensor " + expectedName);
864void EmitNestedLoops(std::stringstream &out,
size_t loopRank,
const std::vector<Dim> shape);
906 for (std::size_t i = 0; i <
size; ++i) {
true
Register systematic variations for multiple existing columns using auto-generated tags.
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
RTensor is a container with contiguous memory and shape information.
RTensor< Value_t, Container_t > Copy(MemoryLayout layout=MemoryLayout::RowMajor) const
Copy RTensor to new object.
RTensor is a container with contiguous memory and shape information.
MemoryLayout GetMemoryLayout() const
const Shape_t & GetStrides() const
std::size_t GetSize() const
const Shape_t & GetShape() const
bool IsWeightTensor() const
std::shared_ptr< void > const & sharedptr() const
std::shared_ptr< void > fData
! Transient shared data
InitializedTensor()=default
ETensorType fType
Encodes the type of the data.
std::vector< std::size_t > const & shape() const
char * fPersistentData
[fSize] Persistent version of the data
std::vector< std::size_t > fShape
The shape of the data in terms of elements in each dimension.
bool fIsNotWritable
Flag to indicate that tensor values do not need to be written as weight or generated code.
bool IsConstantTensor() const
void CastSharedToPersistent()
bool fConstant
Flag specifying if tensor is a Constant one (coming from a Constant operator)
ETensorType const & type() const
bool IsNotWritable() const
void CastPersistentToShared()
InitializedTensor(ETensorType type, std::span< std::size_t > shape, std::shared_ptr< void > data, bool typeConstant=false)
int fSize
The size of the persistent data in bytes (not number of elements!)
void sgemm_(const char *transa, const char *transb, const int *m, const int *n, const int *k, const float *alpha, const float *A, const int *lda, const float *B, const int *ldb, const float *beta, float *C, const int *ldc)
bool AreSameShape(const std::vector< size_t > &, const std::vector< size_t > &)
void Im2col_3d(const T *data_im, const int channels, const int depth, const int height, const int width, const int kernel_d, const int kernel_h, const int kernel_w, const int pad_d, const int pad_h, const int pad_w, const int stride_d, const int stride_h, const int stride_w, const int dilation_d, const int dilation_h, const int dilation_w, T *data_col)
3d implementation
T * BroadcastConvBias(const T *data, const size_t channel, const std::vector< size_t > &targetShape)
std::vector< size_t > UnidirectionalBroadcastShape(std::vector< size_t > &, std::vector< size_t > &)
void col2im(const Dtype *data_col, const int channels, const int height, const int width, const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w, const int dilation_h, const int dilation_w, Dtype *data_im)
void BroadcastTensor(ConstContT data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape, T *broadcastedData)
std::string Clean_name(std::string input_tensor_name)
bool is_a_ge_zero_and_a_lt_b(int a, int b)
function to check if a >> 0 and a < MAX using a single comparison / use trick casting to unsigned val...
std::vector< size_t > MultidirectionalBroadcastShape(std::vector< std::vector< size_t > >)
T * UnidirectionalBroadcast(const T *data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape)
void Im2col(const T *data_im, const int channels, const int height, const int width, const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, const int stride_h, const int stride_w, const int dilation_h, const int dilation_w, T *data_col)
im2col : efficient function to re-arrange input data of convolution to a matrix that can be used by B...
T * CreateBroadcastTensor(const T *data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape, size_t targetLength)
std::vector< size_t > ComputeStrideFromShape(const std::vector< size_t > &shape)
compute stride of a tensor given its shape (assume layout is row-major)
MemoryResult OrganizeMemory(const std::vector< TensorLifeInfo > &tensorsInfo)
Greedy best-fit planner with coalescing free list.
constexpr TensorDims makeDims(Arr const &arr)
std::string ConvertDimShapeToString(const std::vector< Dim > &shape)
std::size_t ConvertShapeToLength(const std::vector< size_t > &shape)
std::string ConvertValToString< double >(double value)
void ReadTensorFromStream(std::istream &is, T &target, std::string const &expectedName, std::size_t expectedLength)
std::string ConvertValuesToString(size_t n, const T *data, size_t maxprint=-1)
std::vector< Dim > ConvertShapeToDim(const std::vector< size_t > &shape)
Convert shape from integer format to dynamic one (based on Dim)
constexpr size_t GetTypeSize(ETensorType type)
ETensorType GetTemplatedType(T)
void Gemm_Call(float *output, bool transa, bool transb, int m, int n, int k, float alpha, const float *A, const float *B, float beta, const float *C)
std::string ConvertValToString< float >(float value)
void Fill(float *output, float value, int size)
std::vector< size_t > ConvertShapeToInt(const std::vector< Dim > &shape)
Convert shape based on Dim to integer format.
std::string ConvertTypeToString(ETensorType type)
void Relu(float *output, float const *input, int size)
ETensorType ConvertStringToType(std::string type)
TMVA::Experimental::RTensor< T > Concatenate(TMVA::Experimental::RTensor< T > &t1, TMVA::Experimental::RTensor< T > &t2, int axis=0)
float ParseFloatToken(const std::string &s)
std::ostream & operator<<(std::ostream &os, const Dim &d)
std::string ConvertDimShapeToLength(const std::vector< Dim > &shape)
void EmitNestedLoops(std::stringstream &out, size_t loopRank, const std::vector< Dim > shape)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
void CloseNestedLoops(std::stringstream &out, size_t loopRank)
std::string ConvertValToString(T value)
std::string ConvertValToString< int64_t >(int64_t value)
bool IsInteger(const std::string &s)
GNN_Data Copy(const GNN_Data &data)
create variable transformations
bool operator!=(const Dim &rhs) const
bool operator==(const Dim &rhs) const
Dim(const std::string &p, size_t d=0)
std::ostream & operator<<(std::ostream &os) const
std::string GetVal() const
RTensor< float > global_data
RTensor< float > edge_data
RTensor< int > edge_index
RTensor< float > node_data
std::map< size_t, TensorMemoryInfo > total_stack
std::map< size_t, size_t > available_stack
std::vector< size_t > offsets
constexpr SingleDim(std::size_t v)
constexpr SingleDim(const char *v)
constexpr std::size_t total_size() const
std::vector< size_t > shape
void merge(const TensorMemoryInfo &other)
std::string_view tensor_name
TensorMemoryInfo split(const std::string_view new_name, size_t new_size)
static const std::string Name()
static const std::string Name()
static const std::string Name()
static const std::string Name()
static const std::string Name()
static const std::string Name()
static const std::string Name()
static const std::string Name()
static const std::string Name()