J'ai été surpris que je ne puisse pas trouver cette question existante. J'ai essayé de le généralaliser (avec un bon code non testé) à quelque chose que tout le monde peut bénéficier de.
Supposons que j'ai un point Maintenant, je crée un tableau multidimensionnel d'entre eux: P> multidimensionnel code>: p> //Example: dim==1
for (int x=0; x<counts[0]; ++x) {
Point<1>& point = array[x];
point.data[0] = (x+0.5) / (double)counts[0];
}
//Example: dim==2
for (int y=0; y<counts[1]; ++y) {
for (int x=0; x<counts[0]; ++x) {
Point<2>& point = array[y*counts[0]+x];
point.data[0] = (x+0.5) / (double)counts[0];
point.data[1] = (y+0.5) / (double)counts[1];
}
}
//Example: dim==3
for (int z=0; z<counts[2]; ++z) {
for (int y=0; y<counts[1]; ++y) {
for (int x=0; x<counts[0]; ++x) {
Point<3>& point = array[(z*counts[1]+y)*counts[0]+x];
point.data[0] = (x+0.5) / (double)counts[0];
point.data[1] = (y+0.5) / (double)counts[1];
point.data[2] = (z+0.5) / (double)counts[2];
}
}
}
3 Réponses :
Si vous avez besoin de performance et de "élégance", je voudrais: p> J'ai donc trouvé une solution suivante qui est assez cohérente avec votre implémentation et vos besoins et essayez de rester simple. P> J'ai géré la réécriture d'une petite classe multi barreaux dans une «moderne C ++ 11 Way». Je considère ici que les dimensions code> code> ne sont peut-être pas connues à l'heure de la compilation d'où l'utilisation de Vivez sur Coliru kbd> strud> p> Comme vous pouvez le voir dans les résultats Réponse originale forte> p> J'avais besoin d'une grille multidimensionnelle pour mes besoins et de poser des améliorations de mon code sur Code Examen . Voici un travail de travail exemple Où certaines fonctionnalités peuvent être inutiles pour vous ... Ma mise en œuvre se rapporte sur le modèle et compiler des calculs de temps. Notez que la taille des dimensions doit être connue au moment de la compilation. P> brièvement, la classe ressemblerait à ceci: p> , puis vous pouvez construire votre réseau multidimensionnel et l'initialiser de ces manières: p> < Pré> xxx pré> Si vous devez spécifier un algorithme pour des boucles imbriquées par variadiques pour remplir les valeurs que vous pouvez jeter un coup d'oeil ici et faites-le de cette façon avec la première réponse: p> Si vous avez besoin de quelque chose que je manque dans ma mise en œuvre, n'hésitez pas à demander. Je serais aussi heureux que quelqu'un puisse souligner des améliorations. p> p>
Nouveau code>, Aucun pointeur, utilisez une approche moderne C ++ avec std :: vecteur code> ou std :: tableau code>. Li>.
Dims code> au moment de la compilation. LI>
ul> std :: vecteur code> maintenant. Il est bien sûr possible d'avoir un code temporel plus générique et compilé avec std :: array code> voir ma réponse d'origine ci-dessous. p> Data _ code> peut être initialisé de manière générale pour n code> dimensions. Si vous avez besoin d'une classe abstraite de niveau supérieur, vous pouvez vérifier ci-dessous ma réponse d'origine dans laquelle vous pouvez effectuer certaines opérations pratiques (c'est-à-dire accès à grille [{i, j, k}] code> pour remplir les valeurs). P>
Comment cela généralisez-t-il des boucles nichées de profondeur?
Avec un modèle variadique, vous pouvez avoir un réseau multis dimensionnel. par exemple. Multigramme
@COINCOIN GLENN indique le problème ici. Je peux facilement faire une matrice multidimensionnelle qui a l'air jolie, mais remplissage i> n'est toujours pas. Les tableaux imbriqués par exemple que j'ai donné sont le comportement Je veux I> Je veux, pas la mise en œuvre: je ne veut pas écrire à l'aide de boucles à la main pour toutes les dimensions possibles que je pouvais m'occuper d'utiliser . La difficulté est l'initialisation des points de grille, comme je l'ai montré dans mon exemple.
Qu'en est-il de mon deuxième exemple où vous pouvez remplir la matrice via les itérateurs (boucle unique)? Je pense qu'il est possible de le faire dépendre de la façon dont vous remplissez vos valeurs pouvez-vous expliquer comment vous souhaitez l'initialiser afin de voir si nous pouvons faire mieux?
La boucle unique pourrait fonctionner, mais seulement si vous pouvez mieux préciser comment. Le comportement est comme dans mon exemple ci-dessus. Dans pseudocode, pour chaque élément de tableau, do matry [A] [b] [c] ... [z] = nouveau point (A, B, C, ..., Z); code>.
Voici ma solution, en utilisant des modèles de variadiques C ++ 11 et des extensions de paquet.
My "Foobar" compile comme une fonction comme pour l'élégance, vous pouvez être le juge, mais je pense que c'est plutôt bien. P> Fondamentalement, l'idée est de remplacer Le code est totalement autonome Enregistrer pour Il compile pour moi à la norme C ++ 11 avec GCC 4.8.2 et Clang 3.6. P> Remarque: Si vous souhaitez utiliser la même technique pour le code où les dimensions sont un paramètre de temps d'exécution, essentiellement de quoi Vous feriez est de réilementer le consexpr code> Donc, je dirais que c'est assez efficace: p p > pour code> boucles avec une programmation fonctionnelle de faire L'itération, où nous cherchons simplement à construire explicitement l'ensemble que nous voulons itérer sur la première. Ce code peut ensuite être généralisé à une dimensionnalité arbitraire de manière plus simple. P> cartésian_product code> métafonctionné ci-dessous sous la forme d'une fonction d'exécution à l'aide de quelque chose comme std :: vecteur Dim code> Nombre de produits Cartésiens et itérer sur celui utilisant un seul pour la boucle pour remplir le résultat. P> #include <array>
#include <iostream>
/////////////////////////////////////////////
// The point class from problem statement
/////////////////////////////////////////////
template <size_t dims> class Point { public: double data[dims]; };
// Some basic type list and meta function objects to work with
// List of indices
template<size_t... sl>
struct StList {
static constexpr size_t length = sizeof...(sl);
};
// Metafunction to compute a volume
template <typename T>
struct Compute_Volume;
template<size_t s>
struct Compute_Volume<StList<s>> {
static constexpr size_t value = s;
};
template <size_t s1, size_t s2, size_t... sl>
struct Compute_Volume<StList<s1, s2, sl...>> {
static constexpr size_t value = s1 * Compute_Volume<StList<s2, sl...>>::value;
};
// Concatenate
template<typename TL, typename TR>
struct Concat;
template<size_t... SL, size_t... SR>
struct Concat<StList<SL...>, StList<SR...>> {
typedef StList<SL..., SR...> type;
};
template<typename TL, typename TR>
using Concat_t = typename Concat<TL, TR>::type;
// Meta function to check if a typelist is component-wise less than another typelist
// For testing purposes
template <typename TL, typename TR>
struct all_less_than;
template <size_t l1, size_t... SL, size_t r1, size_t... SR>
struct all_less_than<StList<l1, SL...>, StList<r1, SR...>> {
static constexpr bool value = (l1 < r1) && all_less_than<StList<SL...>, StList<SR...>>::value;
};
template<>
struct all_less_than<StList<>, StList<>> {
static constexpr bool value = true;
};
/////////////////////////////////////////////////////////////////////////////
// constexpr template function for the point initializations you described
/////////////////////////////////////////////////////////////////////////////
template <typename index, typename dims>
struct point_maker;
template <size_t... idx, size_t... dim>
struct point_maker<StList<idx...>, StList<dim...>> {
static_assert(sizeof...(idx) == sizeof...(dim), "misuse of 'point_maker' template, idx and dim must have same number of coordinates");
static_assert(all_less_than<StList<idx...>, StList<dim...>>::value, "misuse of 'point_maker' template, idx is out of bounds");
static constexpr Point<sizeof...(idx)> make_point() {
return {{ ((idx + 0.5) / static_cast<double>(dim))... }};
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// Now we need to abstract the for loops. We need a little more infrastructure for this.
//////////////////////////////////////////////////////////////////////////////////////////
// A basic typelist object
template <typename... tl>
struct TypeList {
static constexpr size_t length = sizeof...(tl);
};
// Specialization for the Concat metafunction
template<typename... TL, typename... TR>
struct Concat<TypeList<TL...>, TypeList<TR...>> {
typedef TypeList<TL..., TR...> type;
};
// Metafunction to compute the cartesian product of two lists of lists, and evaluate the `Concat` metafunction for each pair.
template <typename S, typename T>
struct Cartesian_Product;
template <typename s1, typename s2, typename... sl, typename T>
struct Cartesian_Product<TypeList<s1, s2, sl...>, T> {
typedef Concat_t<typename Cartesian_Product<TypeList<s1>, T>::type, typename Cartesian_Product<TypeList<s2, sl...>, T>::type> type;
};
template <typename s, typename t1, typename t2, typename... tl>
struct Cartesian_Product<TypeList<s>, TypeList<t1, t2, tl...>> {
typedef Concat_t<typename Cartesian_Product<TypeList<s>, TypeList<t1>>::type, typename Cartesian_Product<TypeList<s>, TypeList<t2, tl...>>::type> type;
};
template <typename s, typename t>
struct Cartesian_Product<TypeList<s>, TypeList<t>> {
typedef TypeList<Concat_t<s, t>> type;
};
template <typename S, typename T>
using Cartesian_Product_t = typename Cartesian_Product<S, T>::type;
// Some unit tests for the above :)
static_assert( std::is_same<Cartesian_Product_t<TypeList<StList<1>, StList<2>>, TypeList<StList<3>, StList<4>>>, TypeList<StList<1,3>, StList<1,4>, StList<2,3>, StList<2,4>>>::value , "cartesian product not working");
static_assert( std::is_same<Cartesian_Product_t<TypeList<StList<1,5>, StList<2>>, TypeList<StList<3>, StList<4>>>, TypeList<StList<1,5,3>, StList<1,5,4>, StList<2,3>, StList<2,4>>>::value , "cartesian product not working");
static_assert( std::is_same<Cartesian_Product_t<TypeList<StList<1,5>, StList<2>>, TypeList<StList<>>>, TypeList<StList<1,5>, StList<2>>>::value , "cartesian product not working");
// Metafunction to count from 0 to n
// Count from zero to n-1, and make a sequence of singleton sets containing the numbers
template<size_t s>
struct Count {
typedef Concat_t<typename Count<s-1>::type, TypeList<StList<s-1>>> type;
};
template<>
struct Count<0> {
typedef TypeList<> type;
};
template<size_t s>
using Count_t = typename Count<s>::type;
// Metafunction to abstract a series of for loops, generating the list of all the index tuples the collection of loops would generate
template <typename T>
struct Volume_Maker;
template <>
struct Volume_Maker<StList<>> {
typedef TypeList<StList<>> type;
};
template <size_t s, size_t... sl>
struct Volume_Maker<StList<s, sl...>> {
typedef Cartesian_Product_t<Count_t<s>, typename Volume_Maker<StList<sl...>>::type> type;
};
template <typename T>
using Volume_t = typename Volume_Maker<T>::type;
// Some more quick unit tests
template <typename T>
struct Volume_Test {
static_assert( Volume_t<T>::length == Compute_Volume<T>::value, "volume computation mismatch");
};
Volume_Test<StList<1,2,3>> test1{};
Volume_Test<StList<1,1,1>> test2{};
Volume_Test<StList<1>> test3{};
Volume_Test<StList<7,6,8>> test4{};
/////////////////
// Grand finale
/////////////////
template <typename dim_list, typename idx_list = Volume_t<dim_list>>
struct foobar_helper;
template <size_t... dim, typename... idx>
struct foobar_helper<StList<dim...>, TypeList<idx...>> {
typedef StList<dim...> dim_list;
typedef std::array<Point<sizeof...(dim)>, sizeof...(idx)> array_type;
static constexpr array_type make_array() {
return {{ point_maker<idx, dim_list>::make_point()... }};
}
};
template <size_t... dim>
constexpr std::array<Point<sizeof...(dim)>, Compute_Volume<StList<dim...>>::value> foobar() {
return foobar_helper<StList<dim...>>::make_array();
}
/////////////////
// Example usage
/////////////////
template <size_t ndim>
std::ostream & operator << (std::ostream & s, const Point<ndim> & p) {
s << "[ ";
for (size_t i = 0; i < ndim; ++i) {
if (i) { s << ", "; }
s << p.data[i];
}
s << " ]";
return s;
}
template<size_t ndim, size_t N>
void print_array(std::ostream & s, const std::array<Point<ndim>, N> & a) {
for (size_t i = 0; i < N; ++i) {
s << a[i] << std::endl;
}
}
int main() {
constexpr auto array1 = foobar<2,2,2>();
print_array(std::cout, array1);
constexpr auto array2 = foobar<3,3,3,3>();
print_array(std::cout, array2);
}
Vous semblez être amusant aussi :)
aller de ou p> dans un tableau 7 x 3 x 5, Z = 3, Y = 1, x = 2 serait à dans un tableau 7 x 3 x 5, Z = 4, y = 2, x = 3 serait à Si nous conservons les produits cumulatifs dans un tableau, points à la matrice plate: p > matrice plate à des points: p> Nous pouvons ensuite itérer sur F (réseau plat), ingénieur inversé de l'index dans Le tableau plat Tout points: x, y, ... comme ci-dessus et que vous voulez l'initialisation que vous souhaitez dans une boucle générique: p> donnée x, y, z code> à la matrice aplatie (f) Nous avons l'équation suivante 3 code> * 3 * 5 + 1 code> 1 code> * 5 + 2 code> = 45 + 5 + 2 = 52 code> p> 4 code> * 3 * 5 + 2 code> * 5 + 3 code> = 60 + 10 + 3 = 73 code> p> mul code> {1, X, x * y, x * y * z, ...} code> et tous les points d'une matrice, val code> p> mul code> comme MUT [0] = 1; MUL [D + 1] = MUL [D] * Nombre [D]; CODE> P> for (int i = 0; i < total_count; ++i) {
for (int d=0; d < dims; ++d) {
int dim=(i%mult[d+1])/mult[d];
point.data[d] = (dim+0.5) / (double)counts[d];
}
}
Quelle est la source de valeurs? c'est-à-dire à quoi i> nous initialisons
@Drop "Initialisez ce tableau à ses points de grille multidimensionnels". Ensuite, voyez l'exemple de la suite?
Je l'ai, mais d'où obtenez-vous des valeurs exactes pour votre tableau de points? Juste à partir de ceci:
point.data [i] = (v [i] +0.5) / (double) compte [i]; code>? Je pense que je ne comprends pas ce qui est "ses points de grille multidimensionnels".@Drop je pense que je ne comprends pas ce que vous demandez. Ce code exemple est paramètre i> les valeurs dans le tableau. Je les définis vers les indices de grille
x code>,y code> etz code> (normalisé à [0,1]) - c'est-à-dire leur position dans la matrice multidimensionnelle.Récursion pourrait toujours fonctionner, vous ne recueillez que au plus la quantité de dimensions, pourriez-vous mieux définir "High Dimensional"
Il devrait également être possible de le faire en inversant la cartographie de N DIM à 1 et simplement en boucle à travers la projection 1D, mais je devrai penser à ce sujet.