Skip to content

With peibos#250

Closed
SimonRohou wants to merge 44 commits into
codac-team:codac2_devfrom
godardma:with_peibos
Closed

With peibos#250
SimonRohou wants to merge 44 commits into
codac-team:codac2_devfrom
godardma:with_peibos

Conversation

@SimonRohou

Copy link
Copy Markdown
Member

PR juste pour pouvoir ajouter des commentaires, l'interface ne semble pas le permettre autrement.

Comment thread examples/07_peibos/main.cpp Outdated
@@ -0,0 +1,85 @@
// Example from the publication:
// https://www.ensta-bretagne.fr/jaulin/paper_centeredActa.pdf

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

À retirer / changer

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},

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Les générators sont-ils une matrice d'entiers ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread examples/07_peibos/main.cpp Outdated

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}));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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]});

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pour info, sqr(y_3d[0]) peut désormais aussi s'écrire y_3d[0]^2 (et également y_3d[0]**2 en Python).

Comment thread examples/07_peibos/main.py Outdated
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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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}));

Comment thread examples/07b_peibos_capd/main.cpp Outdated
@@ -0,0 +1,61 @@
// Example from the publication:
// https://www.ensta-bretagne.fr/jaulin/paper_centeredActa.pdf

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idem

.def("vertices", &Parallelepiped::vertices,
VECTOR_VECTOR_PARALLELEPIPED_VERTICES_CONST)

.def_readwrite("z", &Parallelepiped::z)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Si les générateurs sont des indices de coefficients, il faudrait les shifter pour coller avec les conventions Matlab (premier indice à 1).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valeur par défaut à Vector::zero(..) pour offset ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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());

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vertices.push_back(z + A.col(0) + A.col(1) + A.col(2));


vector<Vector> Parallelepiped::vertices() const
{
assert(A.rows() == 3);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const OctaSym& s

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);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pourquoi restreindre à EvalMode::NATURAL ? Tu as peut-être perçu un bug avec le mode d'évaluation par défaut ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Peut-être intéressant de remplacer const vector<vector<int>> par une Matrix voire une Matrix<int>.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +43 to +47
for (int i = 0; i < ((int) generators.size()); i++)
{
OctaSym symmetry = OctaSym(generators[i]);
symmetries.push_back(symmetry);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Comment on lines +97 to +107
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());

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fonctionne uniquement pour les flat parallelepipeds ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +156 to +159
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()));
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tu pourrais ne faire qu'une fonction avec une valeur par défaut pour l'argument offset.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cf mon commentaire sur le binding python de cette même fonction

godardma added 29 commits June 30, 2025 10:00
@SimonRohou SimonRohou closed this Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants