diff --git a/CMakeLists.txt b/CMakeLists.txt
index 80c9ac985e391ef04812f47cf720329c8cbea4f5..e022547daa62330c6d8b5a06b631134ab94daf33 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,6 +36,8 @@ add_executable(pdptw src/mains/main.cpp
                 src/output/solution_checker.cpp
                 src/lns/operators/sorting_strategy.cpp
                 src/lns/operators/destruction/random_destroy.cpp
+                src/lns/operators/generation/enumerate.cpp 
+                src/lns/operators/generation/modification_generator.cpp 
                 src/lns/operators/selector/operator_selection.cpp
                 src/utils.cpp
                 )
diff --git a/src/lns/modification/atomic_recreation.h b/src/lns/modification/atomic_recreation.h
index 1d726a43a2bf7d7eeb56f2406803282779afcad2..227b4f913b79e54cd9e4a5e6b4876028c9e4da75 100644
--- a/src/lns/modification/atomic_recreation.h
+++ b/src/lns/modification/atomic_recreation.h
@@ -12,6 +12,13 @@ class AtomicRecreation : public AtomicModification
 public:
     ~AtomicRecreation() override = default;
 
+    /**
+     * Visitor pattern double dispatch.
+     * Only need to be implemented with `return *this;`
+     * Update ModificationCheckVariant alias when adding new recreate modification
+     */
+    virtual ModificationCheckVariant asCheckVariant() const = 0;
+    
     /**
      * @return the pickup location added to the solution, nullptr if none were added
      */
diff --git a/src/lns/modification/pair/insert_pair.cpp b/src/lns/modification/pair/insert_pair.cpp
index bf717d0d92c80742e187511107b8bd4febb3e61f..4206f3d7cdbb0110eac092c8c74d44eae32cdbb6 100644
--- a/src/lns/modification/pair/insert_pair.cpp
+++ b/src/lns/modification/pair/insert_pair.cpp
@@ -57,6 +57,11 @@ double InsertPair::evaluate(Solution const &solution) const {
 }
 
 
+ModificationCheckVariant InsertPair::asCheckVariant() const
+{
+    return *this;
+}
+
 int InsertPair::getPickupInsertion() const
 {
     return pickupInsertion;
diff --git a/src/lns/modification/pair/insert_pair.h b/src/lns/modification/pair/insert_pair.h
index 84fe9186a262aa9888d299b60d633cc44f0fdec5..14376aabf796ec6fc51f9a109948fe61e16d18b5 100644
--- a/src/lns/modification/pair/insert_pair.h
+++ b/src/lns/modification/pair/insert_pair.h
@@ -65,4 +65,5 @@ public:
     Pair const &getPair() const;
     Index getIndex() const;
 
+    ModificationCheckVariant asCheckVariant() const override;
 };  
\ No newline at end of file
diff --git a/src/lns/modification/route/insert_route.cpp b/src/lns/modification/route/insert_route.cpp
index 96cf368d0c64c197fb90a08020f3fd5d59bc9e41..7a6be790ae6fb456ad94c3253c0ec0d3565e9018 100644
--- a/src/lns/modification/route/insert_route.cpp
+++ b/src/lns/modification/route/insert_route.cpp
@@ -19,3 +19,7 @@ Location const *InsertRoute::getAddedLocation() const
     return nullptr;
 }
 
+ModificationCheckVariant InsertRoute::asCheckVariant() const
+{
+    return *this;
+}
diff --git a/src/lns/modification/route/insert_route.h b/src/lns/modification/route/insert_route.h
index e5d64134ce42048e2b06b98f05774ded731cc72f..877548964092882f44ac8292369c71ce2c9d8022 100644
--- a/src/lns/modification/route/insert_route.h
+++ b/src/lns/modification/route/insert_route.h
@@ -17,4 +17,6 @@ public:
     void modifySolution(Solution &solution) override;
     double evaluate(Solution const &solution) const override;
     Location const *getAddedLocation() const override;
+
+    ModificationCheckVariant asCheckVariant() const override;
 };  
\ No newline at end of file
diff --git a/src/lns/operators/generators/enumerate.cpp b/src/lns/operators/generators/enumerate.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b06b8179c0774e710b2a83b76d705fc17c8c1963
--- /dev/null
+++ b/src/lns/operators/generators/enumerate.cpp
@@ -0,0 +1,32 @@
+#include "enumerate.h"
+
+namespace enumeration
+{
+    /**
+     * Enumerate InsertPair modifications.
+     * consumeModification is called for each modification.
+     * Does some checks to cut some loops. (TO DO)
+     * @param solution
+     * @param pair
+     * @param consumeModification called when a modification is created
+     */
+    void enumerateAllInsertPair(Solution const &solution, Pair const &pair,
+                                    std::function<void(InsertPair &&)> const &consumeModification)
+    {   
+        int routeIndex = 0;
+        for (const Route &route : solution.getRoutes())
+        {
+            for (int p=0; p <= route.getSize(); p++)
+            {
+                for (int d=p; d <= route.getSize(); d++)
+                {
+                    Index index = std::make_tuple(routeIndex, p,d);
+                    consumeModification(InsertPair(index, pair));
+                }
+            }
+            ++routeIndex;
+        }
+    }
+
+
+}// namespace enumeration
\ No newline at end of file
diff --git a/src/lns/operators/generators/enumerate.h b/src/lns/operators/generators/enumerate.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e5a8277fe283278e243d838107d80f2491eec3e
--- /dev/null
+++ b/src/lns/operators/generators/enumerate.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "lns/modification/pair/insert_pair.h"
+
+#include <functional>
+
+namespace enumeration
+{
+
+    /**
+     * Enumerate InsertDelivery modifications.
+     * consumeModification is called for each modification.
+     * Does some checks to cut some loops.
+     * @param solution
+     * @param request
+     * @param consumeModification called when a modification is created (ex : keepBestSolution)
+     */
+    void enumerateAllInsertPair(Solution const &solution, Pair const &Pair,
+                                    std::function<void(InsertPair &&)> const &consumeModification);
+
+
+}// namespace enumeration
+
diff --git a/src/lns/operators/generators/modification_generator.cpp b/src/lns/operators/generators/modification_generator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..be8b0a290bd3726b9e72445b2ba02ff97f405248
--- /dev/null
+++ b/src/lns/operators/generators/modification_generator.cpp
@@ -0,0 +1,33 @@
+#include "modification_generator.h"
+
+#include "enumerate.h"
+
+namespace generator
+{
+    /**
+     *
+     * @tparam ModificationType the type of modification to be checked
+     * @param solution the solution to check the modification validity
+     * @param list the modification will be added to this list if valid
+     * @return a function that takes a ModificationType and add it to list iff it is valid
+     */
+    template<std::derived_from<AtomicRecreation> ModificationType>
+    std::function<void(ModificationType &&)> addToListIfValidTemplate(Solution const &solution,
+                                                                      ModificationContainer &list)
+    {
+        return [&](ModificationType &&modification) {
+            if (solution.checkModification(modification))
+            {
+                list.push_front(std::make_unique<ModificationType>(modification));
+            }
+        };
+    }
+
+    void AllTypedModifications<InsertPair>::populate(Solution const &solution, Pair const &request,
+                                                     std::forward_list<std::unique_ptr<AtomicRecreation>> &list)
+    {
+        enumeration::enumerateAllInsertPair(
+                solution, request, addToListIfValidTemplate<InsertPair>(solution, list));
+    }
+
+}// namespace generator
diff --git a/src/lns/operators/generators/modification_generator.h b/src/lns/operators/generators/modification_generator.h
new file mode 100644
index 0000000000000000000000000000000000000000..23026bc9899d66e695036474e28b41c0ea605872
--- /dev/null
+++ b/src/lns/operators/generators/modification_generator.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "input/pair.h"
+#include "lns/modification/atomic_recreation.h"
+#include "lns/modification/pair/insert_pair.h"
+
+#include <forward_list>
+#include <memory>
+
+namespace generator
+{
+    using ModificationContainer = std::forward_list<std::unique_ptr<AtomicRecreation>>;
+
+    /**
+     * Abstract class to generate valid modifications
+     */
+    class ModificationGenerator
+    {
+    public:
+        /**
+          * Adds valid insertions of request to the solution in the list provided as argument
+          */
+        virtual void populate(Solution const &solution, Pair const &, ModificationContainer &modificationList) = 0;
+
+        virtual ~ModificationGenerator() = default;
+    };
+
+    /**
+     * Empty template class to generate ALL valid modification of a specific type
+     * @tparam T the type of modification to generate
+     */
+    template<std::derived_from<AtomicRecreation> T>
+    class AllTypedModifications : public ModificationGenerator
+    {
+        // this assert will always fail. Needs a template specification
+        static_assert(sizeof(T) == 0, "The generator for type T has not been defined yet.");
+    };
+
+    template<>
+    class AllTypedModifications<InsertPair> : public ModificationGenerator
+    {
+    public:
+        void populate(Solution const &solution, Pair const &, ModificationContainer &list) override;
+    };
+
+
+}// namespace generator
\ No newline at end of file
diff --git a/src/lns/operators/reconstruction/list_heuristic_insertion.h b/src/lns/operators/reconstruction/list_heuristic_insertion.h
new file mode 100644
index 0000000000000000000000000000000000000000..4570caf3f153278e59a44e8503c8c6caaebdd6c2
--- /dev/null
+++ b/src/lns/operators/reconstruction/list_heuristic_insertion.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "input/data.h"
+#include "input/pdptw_data.h"
+#include "lns/operators/abstract_operator.h"
+#include "lns/operators/generators/modification_generator.h"
+#include "lns/operators/sorting_strategy.h"
+#include "utils.h"
+
+#include <optional>
+
+class AtomicRecreation;
+
+/**
+ * This is a template class for list heuristic operator.
+ * Implementation is in the .hpp file
+ * @tparam Strategy defines in which order we are treating the requests
+ * @tparam Generator defines which modifications are going to be used
+ */
+template<std::derived_from<sorting_strategy::SortingStrategy> Strategy,
+         std::derived_from<generator::ModificationGenerator> Generator>
+class ListHeuristicInsertion : public ReconstructionOperator
+{
+private:
+    using AtomicRecreationPtr = std::unique_ptr<AtomicRecreation>;
+
+public:
+    explicit ListHeuristicInsertion();
+
+    void reconstructSolution(Solution &solution, double blinkRate) const override;
+
+private:
+    /**
+     * @param blinkRate probability to ignore the request insertion
+     * @return the best insertion found
+     */
+    static std::unique_ptr<AtomicRecreation> choosingStrategy(Solution &solution, Pair const &pair,
+                                                              double blinkRate);
+};
diff --git a/src/lns/operators/reconstruction/list_heuristic_insertion.hpp b/src/lns/operators/reconstruction/list_heuristic_insertion.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..11fb7492121b61b5e34313d02f52d09484d4328f
--- /dev/null
+++ b/src/lns/operators/reconstruction/list_heuristic_insertion.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "list_heuristic_insertion.h"
+// This is a header, but it does define templates, so we can't put them in .cpp file
+// for forward declaration you can use the .h file, but if you need to use the class, you must include this one instead
+
+#include "lns/operators/generators/modification_generator.h"
+
+#include <concepts>
+
+
+template<std::derived_from<sorting_strategy::SortingStrategy> Strategy,
+         std::derived_from<generator::ModificationGenerator> Generator>
+ListHeuristicInsertion<Strategy, Generator>::ListHeuristicInsertion() = default;
+
+template<std::derived_from<sorting_strategy::SortingStrategy> Strategy,
+         std::derived_from<generator::ModificationGenerator> Generator>
+void ListHeuristicInsertion<Strategy, Generator>::reconstructSolution(Solution &solution, double blinkRate) const
+{
+    std::vector<int> sortedPairs = Strategy(solution).sortRequests();
+    AtomicRecreationPtr recreation;
+    for (int pairID: sortedPairs)
+    {
+        Pair const &pair = solution.getData().getPair(pairID);
+        recreation = ListHeuristicInsertion::choosingStrategy(solution, pair, blinkRate);
+        if (recreation)
+        {
+            solution.applyRecreateSolution(*recreation);
+        }
+    }
+}
+
+
+template<std::derived_from<sorting_strategy::SortingStrategy> Strategy,
+         std::derived_from<generator::ModificationGenerator> Generator>
+std::unique_ptr<AtomicRecreation> ListHeuristicInsertion<Strategy, Generator>::choosingStrategy(Solution &solution,
+                                                                                                Pair const &pair,
+                                                                                                double blinkRate)
+{
+    AtomicRecreationPtr bestInsertion;
+    double bestKnownInsertionCost = std::numeric_limits<double>::max();
+    generator::ModificationContainer modifications;
+    Generator().populate(solution, pair, modifications);
+    for (AtomicRecreationPtr &possibleRecreation: modifications)
+    {
+        if (util::getRandom() < 1 - blinkRate)
+        {
+            double newInsertionCost = possibleRecreation->evaluate(solution);
+            if (newInsertionCost < bestKnownInsertionCost)
+            {
+                bestKnownInsertionCost = newInsertionCost;
+                bestInsertion = std::move(possibleRecreation);
+            }
+        }
+    }
+    return bestInsertion;
+}
\ No newline at end of file
diff --git a/src/lns/operators/sorting_strategy.cpp b/src/lns/operators/sorting_strategy.cpp
index 08a16296a5fa064b68a205e56a014a14147ae289..a639b8e996baea1061a4b90d4051da7f9b9fca94 100644
--- a/src/lns/operators/sorting_strategy.cpp
+++ b/src/lns/operators/sorting_strategy.cpp
@@ -5,7 +5,7 @@
 #include <algorithm>
 #include <ranges>
 
-std::vector<int> const &sorting_strategy::Shuffle::sortRequests() const
+std::vector<int> const &sorting_strategy::Shuffle::sortPairs() const
 {
     auto &bank = getSolution().getPairBank();
     std::ranges::shuffle(bank, util::getRawRandom());
diff --git a/src/lns/operators/sorting_strategy.h b/src/lns/operators/sorting_strategy.h
index 55f46b4b31607b80c409add57aff9e068f03ea0b..590b698b4bb43f30c774631db5f4d2f2081f612a 100644
--- a/src/lns/operators/sorting_strategy.h
+++ b/src/lns/operators/sorting_strategy.h
@@ -14,7 +14,7 @@ namespace sorting_strategy
 
         Solution &getSolution() const { return solution; }
 
-        virtual std::vector<int> const &sortRequests() const = 0;
+        virtual std::vector<int> const &sortPairs() const = 0;
         virtual ~SortingStrategy() = default;
 
     private:
@@ -30,7 +30,7 @@ namespace sorting_strategy
         using SortingStrategy::SortingStrategy;
 
     public:
-        std::vector<int> const &sortRequests() const override;
+        std::vector<int> const &sortPairs() const override;
     };
 
 
diff --git a/src/lns/solution/solution.cpp b/src/lns/solution/solution.cpp
index f24844fe15642d69d03b8bd858150d923d819c7f..21d0c48654ccab14c1fc2174b2cfa120b4a6df07 100644
--- a/src/lns/solution/solution.cpp
+++ b/src/lns/solution/solution.cpp
@@ -143,6 +143,21 @@ int Solution::requestsFulFilledCount() const
     return count;
 }
 
+bool Solution::checkModification(AtomicRecreation const &modification) const 
+{
+    ModificationCheckVariant const &checkVariant = modification.asCheckVariant();
+    // visitor pattern
+    for (std::unique_ptr<Constraint> const &constraint: constraints)
+    {
+        if (!constraint->checkVariant(checkVariant))
+        {
+            return false;
+        }
+    }
+    return true; 
+}
+
+
 void Solution::beforeApplyModification(AtomicModification &modification)
 {
     // pre check to do ?
diff --git a/src/lns/solution/solution.h b/src/lns/solution/solution.h
index d5c1cd55f9f28c2d228cc4109865ef69bb3354fa..aa3ff6c0c6941312129cc136ace3f4321903b18c 100644
--- a/src/lns/solution/solution.h
+++ b/src/lns/solution/solution.h
@@ -68,6 +68,12 @@ public:
      */
     int requestsFulFilledCount() const;
 
+    /**
+     * Check that the modification is valid regarding all the constraints
+     * @param modification
+     * @return true if the modification is valid
+     */
+    bool checkModification(AtomicRecreation const &modification) const;
 
     /**
      *  Pre modification check.