   const char *includeNames[] = {"header.h"};
 
   PTXPtr ptx;
-  Apply1Hash hash(op, ta_type, index_type, A);
-  auto found_hash = apply1cache.find(hash);
-  if(found_hash == apply1cache.end())
+  ApplyHash hash(op, ta_type, index_type, A);
+  auto found_hash = applycache.find(hash);
+  if(found_hash == applycache.end())
   {
     ptx = PTXPtr(new PTX());
     compilePTX(src, headers, includeNames, *ptx);
-    apply1cache.emplace(hash, ptx);
+    applycache.emplace(hash, ptx);
   }
   else
     ptx = found_hash->second;


#include "compile_ptx.h"

struct Apply1Hash {
  std::string op;
  std::string index_type;
  std::string ta_type;
  int Adim;

  Apply1Hash(std::string op, std::string ta_type, std::string index_type, int Adim) :
    op(op),
    ta_type(ta_type),
    index_type(index_type),
    Adim(Adim)
  {}

  bool operator == (const Apply1Hash& other) const
  {
    return op == other.op &&
           ta_type == other.ta_type &&
           index_type == other.index_type &&
           Adim == other.Adim;
  }
};

struct Apply2Hash {
  std::string op;
  std::string type;
  int Adim, Bdim;

  Apply2Hash(std::string op, std::string type, int Adim, int Bdim) : op(op), type(type), Adim(Adim), Bdim(Bdim) {}

  bool operator == (const Apply2Hash& other) const
  {
    return op == other.op && type == other.type && Adim == other.Adim && Bdim == other.Bdim;
  }
};

struct Apply3Hash {
  std::string op;
  std::string type;
  int Adim, Bdim, Cdim;

  Apply3Hash(std::string op, std::string type, int Adim, int Bdim, int Cdim) :
    op(op), type(type), Adim(Adim), Bdim(Bdim), Cdim(Cdim) {}

  bool operator == (const Apply3Hash& other) const
  {
    return op == other.op && type == other.type && Adim == other.Adim && Bdim == other.Bdim && Cdim == other.Cdim;
  }
};

namespace std
{
  template<>
  struct hash<Apply1Hash>
  {
    typedef Apply1Hash argument_type;
    typedef std::size_t result_type;

    result_type operator()(argument_type const& s) const

      result_type const h1 ( std::hash<std::string>()(s.op));
      result_type const h2 ( std::hash<std::string>()(s.ta_type));
      result_type const h3 ( std::hash<std::string>()(s.index_type));
      result_type const h4 ( std::hash<int>()(s.dim));
      return ((h1 ^ (h2 << 1)) ^ (h3 << 1)) ^ (h4 << 1);
    }
  };
}

typedef std::vector<char> PTX;
typedef std::shared_ptr<PTX> PTXPtr;

typedef std::unordered_map<ApplyHash, std::shared_ptr<PTX>> ApplyCache;

ApplyCache applycache;

template <class T>
const char* getTypeString()
