With peibos#250
Conversation
| @@ -0,0 +1,85 @@ | |||
| // Example from the publication: | |||
| // https://www.ensta-bretagne.fr/jaulin/paper_centeredActa.pdf | |||
| VectorVar X_2d(1); | ||
| AnalyticFunction psi0_2d ({X_2d},{cos(X_2d[0]*PI/4.-PI/2),sin(X_2d[0]*PI/4.-PI/2)}); | ||
|
|
||
| vector<vector<int>> generators_2d ({{1,2}, |
There was a problem hiding this comment.
Les générators sont-ils une matrice d'entiers ?
There was a problem hiding this comment.
On peut le voir comme ça, mais je préfère le voir comme un vecteur dont chaque élément est un vector qui sert à créer une OctaSym. A partir des symmétries définies par l'utilisateur je "complète" avec la fonction generate_symmetries.
Dans les réflexions en cours je me demande si il ne vaut pas mieux demander à l'utilisateur de fournir directement la liste de symmétries pour qu'il puisse faire ce qu'il veut, quitte à le laisser appeler la fonction generate_symmetries par lui-même... à discuter
|
|
||
| Figure2D figure_2d ("Henon Map", GraphicOutput::VIBES); | ||
| figure_2d.set_window_properties({25,50},{500,500}); | ||
| figure_2d.set_axes(axis(0,{-1.4,2.2}), axis(1,{-0.4,0.3})); |
There was a problem hiding this comment.
D'un point de vue cosmétique il est possible d'écrire set_axes({0,{-1.4,2.2}}, {1,{-0.4,0.3}})
|
|
||
| // 3D example of the PEIBOS algorithm | ||
| VectorVar y_3d(3); | ||
| AnalyticFunction f_3d({y_3d},{sqr(y_3d[0])-sqr(y_3d[1])+y_3d[0],2*y_3d[0]*y_3d[1]+y_3d[1],y_3d[2]}); |
There was a problem hiding this comment.
Pour info, sqr(y_3d[0]) peut désormais aussi s'écrire y_3d[0]^2 (et également y_3d[0]**2 en Python).
| for p in v_par_nd: | ||
| for vertice in p.vertices(): | ||
| figure_2d_nd_xy.draw_point(vertice, [Color.red(), Color.red(0.5)]) | ||
| figure_2d_nd_zy.draw_point(vertice, [Color.red(), Color.red(0.5)]) No newline at end of file |
There was a problem hiding this comment.
Pas tout à fait, ce sont deux "vues 2D", chacun représente un plan (respectivement XY et ZY):
figure_2d_nd_xy.set_axes(axis(0,{-1.2,1.2}), axis(1,{-1.2,1.2}));
figure_2d_nd_zy.set_axes(axis(2,{-1.2,1.2}), axis(1,{-1.2,1.2}));
| @@ -0,0 +1,61 @@ | |||
| // Example from the publication: | |||
| // https://www.ensta-bretagne.fr/jaulin/paper_centeredActa.pdf | |||
| .def("vertices", &Parallelepiped::vertices, | ||
| VECTOR_VECTOR_PARALLELEPIPED_VERTICES_CONST) | ||
|
|
||
| .def_readwrite("z", &Parallelepiped::z) |
There was a problem hiding this comment.
La doc des attributs peut aussi être ajoutée
| void export_peibos(py::module& m) | ||
| { | ||
| m.def("PEIBOS", | ||
| [](const py::object& f, const py::object& psi_0, vector<vector<int>> generators, double epsilon) |
There was a problem hiding this comment.
vector<vector<int>> en const reference
| m.def("PEIBOS", | ||
| [](const py::object& f, const py::object& psi_0, vector<vector<int>> generators, double epsilon) | ||
| { | ||
| return PEIBOS(cast<AnalyticFunction<VectorType>>(f), cast<AnalyticFunction<VectorType>>(psi_0), generators, epsilon); |
There was a problem hiding this comment.
Si les générateurs sont des indices de coefficients, il faudrait les shifter pour coller avec les conventions Matlab (premier indice à 1).
There was a problem hiding this comment.
chaque générateur est utilisé tel quel (i.e. un vecteur d'entier) pour créer une OctaSym, donc pas de problème d'indice
| return PEIBOS(cast<AnalyticFunction<VectorType>>(f), cast<AnalyticFunction<VectorType>>(psi_0), generators, epsilon, offset); | ||
| }, | ||
| VECTOR_PARALLELEPIPED_PEIBOS_CONST_ANALYTICFUNCTION_VECTORTYPE_REF_CONST_ANALYTICFUNCTION_VECTORTYPE_REF_CONST_VECTOR_VECTOR_INT_REF_DOUBLE_CONST_VECTOR_REF, | ||
| "f"_a, "psi_0"_a, "generators"_a, "epsilon"_a, "offset"_a); |
There was a problem hiding this comment.
Valeur par défaut à Vector::zero(..) pour offset ?
There was a problem hiding this comment.
pas vraiment possible, d'où le doublon avec une fonction avec et une sans offset : la taille du vecteur d'offset dépend de la taille de sortie de la fonction psi_0. De fait comme je n'ai pas le droit d'écrire
Vector::Zero(psi_0.output_size())
comme valeur par défaut (puisque psi_0 est lui même un argument) je n'ai pas trouvé d'autre solution que d'avoir deux fonctions... peut-être qu'il existe une astuce pour contourner le problème ?
| Parallelepiped::Parallelepiped(const Vector& z_, const Matrix& A_) | ||
| : z(z_), A(A_) | ||
| { | ||
| assert(z.size() == A.rows()); |
There was a problem hiding this comment.
Je l'aurais plutôt mis en assert_release
| Vector v6 = z + A.col(0) + A.col(1) - A.col(2); | ||
| Vector v7 = z + A.col(0) - A.col(1) - A.col(2); | ||
| Vector v8 = z - A.col(0) - A.col(1) - A.col(2); | ||
| vertices.push_back(v1); |
There was a problem hiding this comment.
vertices.push_back(z + A.col(0) + A.col(1) + A.col(2));
|
|
||
| vector<Vector> Parallelepiped::vertices() const | ||
| { | ||
| assert(A.rows() == 3); |
There was a problem hiding this comment.
Je l'aurais aussi mis en assert_release pour donner des indications à l'utilisateur en cas de mauvais usage.
| return (a.cross(b)).norm()/((b-a).norm()); | ||
| } | ||
|
|
||
| bool contains (const vector<OctaSym>& symmetries, const OctaSym& symmetry, const AnalyticFunction<VectorType>& psi_0) |
There was a problem hiding this comment.
Peut-être des noms d'arguments plus différenciés ? symmetries, symmetry
| IntervalVector test_box = Interval(-1.,1.)*IntervalVector::Ones(psi_0.input_size()); | ||
| IntervalVector psi_0_x = psi_0.eval(EvalMode::NATURAL,test_box); | ||
|
|
||
| for (OctaSym s : symmetries) |
| bool contains (const vector<OctaSym>& symmetries, const OctaSym& symmetry, const AnalyticFunction<VectorType>& psi_0) | ||
| { | ||
| IntervalVector test_box = Interval(-1.,1.)*IntervalVector::Ones(psi_0.input_size()); | ||
| IntervalVector psi_0_x = psi_0.eval(EvalMode::NATURAL,test_box); |
There was a problem hiding this comment.
Pourquoi restreindre à EvalMode::NATURAL ? Tu as peut-être perçu un bug avec le mode d'évaluation par défaut ?
There was a problem hiding this comment.
J'ai "peur" que l'utilisation de la forme centrée puisse donner deux résultats très légèrement différents pour deux symmétries qui devraient être les mêmes (par exemple tourner à gauche de 90° deux fois ou tourner à droite de 90° deux fois). De plus ici je ne cherche pas un "bon résultat", juste à faire un test d'unicité, donc l'évaluation naturelle est suffisante.
| return false; | ||
| } | ||
|
|
||
| vector<OctaSym> generate_symmetries (const vector<vector<int>>& generators, const AnalyticFunction<VectorType>& psi_0) |
There was a problem hiding this comment.
Peut-être intéressant de remplacer const vector<vector<int>> par une Matrix voire une Matrix<int>.
There was a problem hiding this comment.
Voir mon commentaire précédent sur ce que représente ce vecteur de vecteur, mais dans l'absolu on pourrait effectivement utiliser une Matrix.
| for (int i = 0; i < ((int) generators.size()); i++) | ||
| { | ||
| OctaSym symmetry = OctaSym(generators[i]); | ||
| symmetries.push_back(symmetry); | ||
| } |
There was a problem hiding this comment.
Juste pour info :
for(const auto& g : generators)
symmetries.push_back(OctaSym(g)); // voire même symmetries.push_back({ g })| auto xc = X.mid(); | ||
|
|
||
| IntervalVector dX=X-xc; | ||
| IntervalMatrix JJg_punc=JJf_punc*IntervalMatrix(symmetry.permutation_matrix())*psi_0.diff(xc); |
There was a problem hiding this comment.
Pour info, tu peux écrire symmetry.permutation_matrix().template cast<Interval>() au lieu de IntervalMatrix(symmetry.permutation_matrix()). C'est probablement plus efficace pour Eigen (mais rien de fondamental).
| auto xc = X.mid(); | ||
|
|
||
| IntervalVector dX=X-xc; | ||
| IntervalMatrix JJg_punc=JJf_punc*IntervalMatrix(symmetry.permutation_matrix())*psi_0.diff(xc); | ||
|
|
||
| IntervalMatrix JJg=JJf*IntervalMatrix(symmetry.permutation_matrix())*psi_0.diff(X); | ||
|
|
||
| IntervalVector E = (JJg - JJg_punc)*dX; | ||
| Interval N = sqr(E[0]) + sqr(E[1]); | ||
|
|
||
| return std::sqrt(N.ub()); |
There was a problem hiding this comment.
Tu peux aussi choisir de ne pas typer explicitement dX, JJg_punc, JJg, E, N, avec auto, pour laisser Eigen faire ses optimisations par expressions templates. https://eigen.tuxfamily.org/index.php?title=Expression_templates
| } | ||
| } | ||
|
|
||
| Matrix inflate_flat_parallelepiped(const Matrix& Jz, double epsilon, double rho) |
There was a problem hiding this comment.
Fonctionne uniquement pour les flat parallelepipeds ?
There was a problem hiding this comment.
C'est une appellation un peu abusive effectivement. Au départ cette fonction prenait un parallelepipède 2D et le "gonflait" en 3D d'une valeur rho. Maintenant on part d'un parallélépipède m-D et on le gonfle en n-D (m<n), il faudrait peut-être changer le nom de la fonction pour être plus explicite.
| vector<Parallelepiped> PEIBOS(const AnalyticFunction<VectorType>& f, const AnalyticFunction<VectorType>& psi_0, const vector<vector<int>>& generators , double epsilon) | ||
| { | ||
| return PEIBOS(f, psi_0, generators, epsilon, Vector::Zero(psi_0.output_size())); | ||
| } |
There was a problem hiding this comment.
Tu pourrais ne faire qu'une fonction avec une valeur par défaut pour l'argument offset.
There was a problem hiding this comment.
Cf mon commentaire sur le binding python de cette même fonction
PR juste pour pouvoir ajouter des commentaires, l'interface ne semble pas le permettre autrement.