Ada中的异构元组

时间:2018-07-18 20:33:20

标签: ada

在ada中是否可以在没有新的运算符和访问类型的情况下在堆栈上创建异构元组?我需要根据编译时的已知数量制作N个2-d数组。更准确地说,一定数量的张量取决于神经网络中的层数。我是这样的:

   subtype Layer_Value_Type is Float range 0.0 .. 1.0;

   package My_Activate is new Activate (Value_Type => Layer_Value_Type);
   package My_Logsig is new My_Activate.Logsig;

   package My_Layer is new Layer (Value_T => Layer_Value_Type);
   package My_Net is new Net (Value_Type    => My_Layer.Value_Type,
                              Layer_Package => My_Layer);
   use My_Layer;

   Layer1 : My_Layer.Layer (5, null);
   Layer2 : My_Layer.Layer (10, My_Logsig.Func'Access);
   Layer3 : My_Layer.Layer (3, My_Logsig.Func'Access);
   Layers_Array : My_Net.Layers_Array := (Layer1, Layer2, Layer3);

   Net : My_Net.Net (Layers_Array'Length);

begin
   declare
   begin
      Net.Make (Layers_Array);
      Net.FeedForward(Input => (0.3, 0.4, 0.5, 0.6, 0.7));
   end;
generic
   type Value_T is digits <>;
package Layer with SPARK_Mode is
   subtype Value_Type is Value_T;
   type Activate_Type is access function (Item : in Float) return Value_Type;
   type Layer (Num : Natural := 0; F : Activate_Type := null) is private;
   procedure Make (This : out Layer; Num : in Natural; F : in Activate_Type := null);

private
   type Layer (Num : Natural := 0; F : Activate_Type := null) is
      record
         Length      : Natural := Num;
         Func        : Activate_Type := F;
         FuncDeriv   : Activate_Type;
      end record;
end Layer;
generic
   type Value_Type is digits <>;
   with package Layer_Package is new Layer(Value_T => Value_Type);
package Net is
   type Layers_Array is array (Positive range <>) of Layer_Package.Layer;
   type Net (Layers_Num : Positive) is tagged limited private;

   subtype Input_Array is Ada.Numerics.Real_Arrays.Real_Vector;

   procedure Make (This :in out Net; Layers : in Layers_Array); 

   function Is_Input_Valid (This : in out Net; Vector : in Input_Array) return Boolean;

   procedure FeedForward (This : in out Net; Input : in Input_Array)
     with Pre => This.Is_Input_Valid (Vector => Input);

private
   --types declaration of values
   subtype Value_Arr is Ada.Numerics.Real_Arrays.Real_Vector;
   type Values_Arr_Ref is access all Value_Arr;

   --types declaration of biases
   subtype Bias_Arr is Value_Arr;
   type Bias_Arr_Ref is access all Bias_Arr;

   --types declaration of waights
   subtype Layer_Waights is Ada.Numerics.Real_Arrays.Real_Matrix;
   type Layer_Waights_Ref is access all Layer_Waights;

   --types declaration of tensors
   type Values_Tensor is array (Positive range <>) of Values_Arr_Ref;
   type Waights_Tensor is array (Positive range <>) of Layer_Waights_Ref;

   --types declaration of activate function array
   type Activate_Arr is array (Positive range <>) of Layer_Package.Activate_Type;

   type Net (Layers_Num : Positive) is tagged limited 
      record
         Values    : Values_Tensor (1 .. Layers_Num);
         Waights   : Waights_Tensor (2 .. Layers_Num);
         Activates : Activate_Arr (2 .. Layers_Num);
      end record;
end Net;
   procedure Make (This : in out Net; Layers : in Layers_Array) is
      type Waight_Tensor_Arr is array (Positive range <>, Positive range <>) of Value_Type;

      --task for random number generator
      task type  Tensor_Randomizer is
         entry Init (Item : in out  Layer_Waights);
      end Tensor_Randomizer;

      task body Tensor_Randomizer is
         My_Generator : Ada.Numerics.Float_Random.Generator;

         function Get return Value_Type with
           Post => (Get'Result >= Value_Type'First + 0.2) and
           (Get'Result <= Value_Type'Last - 0.2)
         is
            use Ada.Numerics.Float_Random;
            Ratio_For_Large : constant := 0.7;
            type Sign_Type is new Boolean with Default_Value => False;
            type Constraint_Type is new Boolean with Default_Value => False;
         begin
            return Result : Value_Type do
               declare
                  Tmp                 : Value_Type := 0.0;
                  Is_Negative         : Sign_Type;
                  Large               : constant := 0.8;
                  Small               : constant := 0.2;
                  Is_Over_Constraints : Constraint_Type;
               begin
                  Tmp := Value_Type (Random (Gen => My_Generator));
                  Is_Negative := (if Tmp >= 0.0 then False else True);
                  Is_Over_Constraints := (if abs (Tmp) >= Large or abs (Tmp) <= Small then
                                             True else False);

                  case Is_Over_Constraints is
                  when False =>
                     Result := Tmp;
                  when True =>
                     Result := (case Is_Negative is
                                   when False => (if abs (Tmp) >= Large then
                                                     Tmp * Ratio_For_Large else 0.5 - Tmp),
                                   when True  => 0.0 - (abs (Tmp) * (if abs (Tmp) >= Large then
                                     Ratio_For_Large else -0.5 + Tmp)));
                  end case;
               end;
            end return;
         end Get;
      begin
         Ada.Numerics.Float_Random.Reset (Gen => My_Generator);
         accept Init (Item : in out Layer_Waights) do
            begin
               Item := (others => (others => Float(Get)));
            end;
         end Init;
      end Tensor_Randomizer;

      type Task_Array_Base_Type is array (This.Waights'Range) of Tensor_Randomizer;
      subtype Task_Array_Type is Task_Array_Base_Type with
        Dynamic_Predicate => Task_Array_Type'Length <= 8;
      Task_Array : Task_Array_Type;

      --this procedure initializing values tensor to  value
      procedure Init_Values_Tensor with
        Post => (for all I of This.Values (1).all => I = 0.0)
      is
         Idx : Positive := This.Values'First;
      begin
      for I of Layers loop
         declare
               Local_Values_Arr : aliased Value_Arr (1 .. I.Num) := (others => 0.0);
         begin
               This.Values (Idx) := new Value_Arr (1 .. I.Num);
               This.Values (Idx).all := Local_Values_Arr;
               Idx := Idx + 1;
         end;
      end loop;
      end Init_Values_Tensor;

      --this procedure initializing waights tensor to random value
      procedure Init_Waight_Tensor is
         Idx : Positive := This.Values'First;
      begin
         for I in This.Waights'Range loop
            This.Waights(I) := new Layer_Waights (1 .. Layers (Idx + 1).Num, 1 .. Layers (Idx).Num);
            Task_Array (I).Init (Item => This.Waights (I).all);
            Idx := Idx + 1;
         end loop;
      end Init_Waight_Tensor;

      --this procedure initializing activate functions array
      procedure Init_Activates is
      begin
         for I in This.Activates'Range loop
            This.Activates (I) := Layers (I).F;
         end loop;
      end Init_Activates;

   begin
      Init_Values_Tensor;
      Init_Waight_Tensor;
      Init_Activates;
   end Make;

在C ++中,我是这样的:

    #include<cstddef>
    #include<utility>
    #include<array>
    #include<tuple>

template<typename T>
struct Sigmoid{
    void Function(){

    }
};

template<typename T, std::size_t num, template<typename> class policy>
struct Layer{
    using value_type = T;
    using value_arr_type = std::array<T, num>;
    static constexpr std::size_t _valuesNum{num};
};

template<typename Tuple, std::size_t... I>
constexpr auto tensor_impl(Tuple t, std::index_sequence<I...>){
    using namespace std;
    constexpr std::array res{std::get<I>(t)._valuesNum...};
    std::tuple<array<array<float, get<I>(t)._valuesNum>, get<I+1>(t)._valuesNum>...> tup{};
    return tup;
}

template<typename... Args, typename Indices = std::make_index_sequence<sizeof...(Args)-1>>
constexpr auto tensor_helper(){
    constexpr std::tuple<Args...> args;
    constexpr std::tuple arr{tensor_impl(args, Indices{})};

    return arr;
}

template<typename T, typename... Args> requires(
    (std::is_same_v<typename T::value_type, typename Args::value_type>) && ...)
class Net{
    std::tuple<typename T::value_arr_type, typename Args::value_arr_type...> values{};
//    std::tuple<std::array<std::array<typename T::value_type, 4>, sizeof...(Args)>> waights{};
public:
    decltype(tensor_helper<T, Args...>()) _waights{tensor_helper<T, Args...>()};
    decltype(auto) tensors(){return _waights;}
};

int main(){
    using layer1 = Layer<float, 2, Sigmoid>;
    using layer2 = Layer<float, 3, Sigmoid>;
    using layer3 = Layer<float, 2, Sigmoid>;

    Net<layer1, layer2, layer3> net{};

}

2 个答案:

答案 0 :(得分:1)

是的,请查看通用包,然后可以实例化该包并从那里创建新的元组类型。

答案 1 :(得分:0)

避免使用new的主要技巧是避免使用访问类型。

删除所有访问类型的声明,并使用实际的类型。

如果您不想自己使用new,则可以使用标准库中的各种不确定的容器。

如果必须避免完全使用堆/存储池,则可以声明变体记录:

type R (S : T := D) is
   record
      F1 : T1;
      case S is
         when V2 =>
            F2 : T2;
         when V3 =>
            F3 : T3;
      end case;
   end record;

您可以仅使用堆栈来制作类型为R的常规数组。