diff --git a/CMakeLists.txt b/CMakeLists.txt
index 18c228b21659c5ea442e1904e9d4b1a1a959d6e7..b53e89fd20e56f3d48a8000b1f08cc5638cb1c81 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
 # link time optimisation (LTO) for release and release with debug info builds
 set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
 set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)
-
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 
 # Finding dependencies
 find_package(CLI11 REQUIRED)
@@ -22,11 +22,15 @@ find_package(spdlog REQUIRED)
 add_executable(pdptw src/main.cpp 
                 src/input/data.cpp
                 src/input/location.cpp
+                src/input/pair.cpp
                 src/input/pdptw_data.cpp
                 src/input/time_window.cpp
                 src/input/json_parser.cpp
                 src/lns/solution/route.cpp 
                 src/lns/solution/solution.cpp
+                src/lns/constraints/constraint.cpp
+                src/lns/constraints/capacity/capacity_constraint.cpp
+                src/lns/constraints/time_window/time_window_constraint.cpp
                 src/lns/modification/pair/insert_pair.cpp 
                 src/lns/modification/pair/remove_pair.cpp
                 src/lns/modification/route/insert_route_with_pair.cpp
@@ -34,4 +38,6 @@ add_executable(pdptw src/main.cpp
                 src/lns/modification/route/remove_route.cpp
                 )
 
-target_link_libraries(pdptw PRIVATE CLI11::CLI11 nlohmann_json::nlohmann_json spdlog::spdlog)
\ No newline at end of file
+target_link_libraries(pdptw PRIVATE CLI11::CLI11 nlohmann_json::nlohmann_json spdlog::spdlog)
+
+target_include_directories(pdptw PUBLIC ${CMAKE_SOURCE_DIR}/src)
diff --git a/src/input/data.cpp b/src/input/data.cpp
index 3ace1f48c596759cbeb502fcbe0118a359713f25..ded751825e988bf1caa07d2415f15075532d8fa8 100644
--- a/src/input/data.cpp
+++ b/src/input/data.cpp
@@ -46,6 +46,12 @@ double data::TravelCost(PDPTWData const &data, int index1, int index2)
     return data.getMatrix()[index1][index2];
 }
 
+double data::TravelTime(PDPTWData const &data, int from, int to)
+{
+    return data.getMatrix()[from][to];
+}
+
+
 double data::SegmentCost(PDPTWData const &data, Route const &route, int start, int end)
 {
     // TO DO
diff --git a/src/input/data.h b/src/input/data.h
index 0570d5ac808ef2834a3d11273382b2ed86ee1852..72771500c65e344f7604f73660e8549731c3bea3 100644
--- a/src/input/data.h
+++ b/src/input/data.h
@@ -39,4 +39,10 @@ namespace data
      * (take location id in parameters)
      */
     double TravelCost(PDPTWData const &data, int index1, int index2);
+
+    /**
+     * Return the travel time between two location
+     * (take location id in parameters)
+     */
+     double TravelTime(PDPTWData const &data, int from, int to);
 }
\ No newline at end of file
diff --git a/src/input/pair.cpp b/src/input/pair.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ccdccb07ba15c1385c410a2af0382fc7a1489fc7
--- /dev/null
+++ b/src/input/pair.cpp
@@ -0,0 +1,14 @@
+#include "pair.h"
+
+Pair::Pair(const Location& pickupLoc, const Location& deliveryLoc)
+: pickup(pickupLoc), delivery(deliveryLoc) {}
+
+const Location& Pair::getPickup() const 
+{
+    return pickup.get();
+}
+
+const Location& Pair::getDelivery() const 
+{
+    return delivery.get();
+}
\ No newline at end of file
diff --git a/src/input/pair.h b/src/input/pair.h
new file mode 100644
index 0000000000000000000000000000000000000000..4183a20293d914095f70d9c07ff5b1e61f2b6e35
--- /dev/null
+++ b/src/input/pair.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "location.h"
+
+// Represent a pair pickup/delivery of location
+class Pair
+{
+private:
+    std::reference_wrapper<Location const> pickup;
+    std::reference_wrapper<Location const> delivery;
+
+public:
+    Pair(const Location& pickupLoc, const Location& deliveryLoc);
+
+    const Location& getPickup() const;
+    const Location& getDelivery() const;
+};
\ No newline at end of file
diff --git a/src/input/pdptw_data.cpp b/src/input/pdptw_data.cpp
index ee78a2b8ef0ffafdc25b475ed3068f3c01fc9ef5..6b819c615a70b00aeb010b95a5f0d25ebfedd692 100644
--- a/src/input/pdptw_data.cpp
+++ b/src/input/pdptw_data.cpp
@@ -12,7 +12,7 @@ unsigned int PDPTWData::getSize()
     return size;
 }
 
-int PDPTWData::getCapacity()
+int PDPTWData::getCapacity() const
 {
     return capacity;
 }
diff --git a/src/input/pdptw_data.h b/src/input/pdptw_data.h
index d3f8510d028c980e551fe4e436d88e81e9e108f8..b7a504ec783ccf480076fe0a1924f1c7089b1ac9 100644
--- a/src/input/pdptw_data.h
+++ b/src/input/pdptw_data.h
@@ -57,7 +57,7 @@ public:
     Matrix const &getMatrix() const;
 
     unsigned int getSize();
-    int getCapacity();
+    int getCapacity() const;
 
     void print() const;
 };
diff --git a/src/lns/constraints/capacity/capacity_constraint.cpp b/src/lns/constraints/capacity/capacity_constraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..44d3c775a4fce4c7df4709d6e71e7c460c98e8fe
--- /dev/null
+++ b/src/lns/constraints/capacity/capacity_constraint.cpp
@@ -0,0 +1,163 @@
+#include "capacity_constraint.h"
+
+
+CapacityConstraint::CapacityConstraint(Solution const &solution) : Constraint(solution)
+{
+    // Init an empty vector of reach time for all routes
+    //std::vector<CapacityVector> routeCapacities(getSolution().getRoutes().size(), CapacityVector());
+    routeCapacities.resize(getSolution().getRoutes().size());
+}
+
+std::unique_ptr<Constraint> CapacityConstraint::clone(Solution const &newOwningSolution) const {
+    std::unique_ptr<CapacityConstraint> clonePtr = std::make_unique<CapacityConstraint>(newOwningSolution);
+    clonePtr->routeCapacities = routeCapacities;
+    return clonePtr;
+}
+
+
+void CapacityConstraint::initCapacities()
+{
+    routeCapacities = std::vector<CapacityVector>();
+    for (const Route& route : getSolution().getRoutes()) 
+    {
+        CapacityVector capacities;
+        int currentCapacity = 0;
+        
+        for (int locationID : route.getRoute()) 
+        {
+            currentCapacity += getSolution().getData().getLocation(locationID).getDemand();
+            capacities.push_back(currentCapacity);
+        }
+        
+        routeCapacities.push_back(capacities);
+    }
+}
+
+
+std::vector<int> const & CapacityConstraint::getRouteCapacities(int routeIndex) const
+{
+    return routeCapacities[routeIndex];
+}
+
+// check for every location between the pickupPosition and the deliveryPosition
+// not ideal
+bool CapacityConstraint::checkModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition) const
+{
+    std::cout << "\n";
+    int max_capacity = getSolution().getData().getCapacity();
+
+    // guardrail
+    if (pair.getPickup().getDemand() > max_capacity)
+    {
+        return false;
+    }
+
+    // check if the disponible capacity is enough are not
+    for (int i = PickupPosition; i <= DeliveryPosition; ++i) {
+        
+        if ((i!=0) && (getRouteCapacities(routeIndex).at(i-1) + pair.getPickup().getDemand() >= max_capacity))
+        {
+            return false;
+        }
+    } 
+    return true;
+}
+
+// update the route and the weight
+// not ideal
+void CapacityConstraint::applyModif(Pair const &pair, int routeIndex, int PickupPosition,  int DeliveryPosition, bool addPair)
+{
+    std::cout << "ok \n";
+    if (addPair)
+    {   
+        // Insert new values
+        routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+DeliveryPosition, 0);
+        if (DeliveryPosition != 0)
+        {
+            routeCapacities[routeIndex][DeliveryPosition] += routeCapacities[routeIndex][DeliveryPosition-1];
+        }
+        routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+PickupPosition, pair.getPickup().getDemand());
+        if (PickupPosition != 0)
+        {
+            routeCapacities[routeIndex][PickupPosition] += routeCapacities[routeIndex][PickupPosition-1];
+        }
+
+        // Update value
+        for (int i = PickupPosition + 1; i < DeliveryPosition + 1; ++i) 
+        {
+            routeCapacities[routeIndex][i] += pair.getPickup().getDemand();
+        } 
+    }
+    else 
+    {
+        for (int i = PickupPosition + 1; i < DeliveryPosition; ++i) 
+        {
+            routeCapacities[routeIndex][i] += pair.getDelivery().getDemand();
+        }
+
+        // remove pair
+        routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + DeliveryPosition);
+        routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + PickupPosition);
+    }    
+}
+
+
+bool CapacityConstraint::check(InsertPair const &op) const
+{
+    return checkModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion());
+}
+void CapacityConstraint::apply(InsertPair const &op)
+{
+    applyModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true);
+}
+
+
+bool CapacityConstraint::check(InsertRoute const &op) const
+{
+    return true;
+}
+void CapacityConstraint::apply(InsertRoute const &op)
+{
+    // add new empty route
+    routeCapacities.emplace_back();
+}   
+
+
+bool CapacityConstraint::check(RemovePair const &op) const
+{
+    // Remove a pair (always true)
+    return true;
+}
+void CapacityConstraint::apply(RemovePair const &op)
+{
+    applyModif(op.getPair(), op.getRouteIndex(), op.getPickupDeletion(), op.getDeliveryDeletion(), false);
+}
+
+
+bool CapacityConstraint::check(RemoveRoute const &op) const
+{
+    return true;
+}   
+void CapacityConstraint::apply(RemoveRoute const &op)
+{
+    // add new empty route
+    routeCapacities.erase(routeCapacities.begin() + op.getRouteIndex());
+}
+
+void CapacityConstraint::print() const
+{
+    std::cout << "Used capacity : \n";
+    int i = 0;
+    for (const auto& capaVector : routeCapacities)
+    {
+        std::cout << "#" << i << " : ";
+        for (const int capa : capaVector)
+        {
+            std::cout << capa << ", ";
+        }
+        std::cout << "\n ";
+        i++;
+    }
+    std::cout << "\n";
+}
+
diff --git a/src/lns/constraints/capacity/capacity_constraint.h b/src/lns/constraints/capacity/capacity_constraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..31149539a47361619559564bfcb73e4c060fda97
--- /dev/null
+++ b/src/lns/constraints/capacity/capacity_constraint.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "./../constraint.h"
+#include "./../../../input/pair.h"
+
+/**
+ * Capacity constraint.
+ * To check this, we keep track of the sum of all requests and check it against the max capacity.
+ * TO DO, verification in O(1) by storing a matrix !
+ */
+class CapacityConstraint : public Constraint
+{
+public:
+    using CapacityVector = std::vector<int>;
+private:
+
+    std::vector<CapacityVector> routeCapacities;
+
+    void apply(InsertPair const &op) override;
+    void apply(InsertRoute const &op) override;
+    void apply(RemovePair const &op) override;
+    void apply(RemoveRoute const &op) override;
+
+    bool check(InsertPair const &op) const override;
+    bool check(InsertRoute const &op) const override;
+    bool check(RemovePair const &op) const override;
+    bool check(RemoveRoute const &op) const override;
+public:
+
+    explicit CapacityConstraint(Solution const &);
+    CapacityConstraint(CapacityConstraint const &) = default;
+
+    std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const override;
+
+    /*
+    *   Given the solution, calculate the capacities when leaving each location
+    *   Modify the routeCapacities vector !
+    */
+    void initCapacities();
+
+    /*
+    *   Return capacity vector of a route
+    */
+    CapacityVector const &getRouteCapacities(int routeIndex) const;
+
+    /*
+    *   Check if a modification is valid or not
+    *   (for now, check only the position of the pickup)
+    *   TO DO (1 or 2)
+    *   1) check if every index on the path can take the new capacity
+    *   2) store a matrix / Segment Tree ?? to evaluate the maximum load between two part of the route 
+    *      -> a matrix but check in O(1) (update in O(n))
+    */
+    bool checkModif(Pair const &pair, int routeIndex, int position, int DeliveryPosition) const;
+
+    /*
+    *   Update the weight
+    */
+    void applyModif(Pair const &pair, int routeIndex, int PickupPosition,  int DeliveryPosition, bool addPair);
+
+    void print() const;
+};
\ No newline at end of file
diff --git a/src/lns/constraints/constraint.cpp b/src/lns/constraints/constraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51f375e42af71712c048049c594b2a9072e3a047
--- /dev/null
+++ b/src/lns/constraints/constraint.cpp
@@ -0,0 +1,36 @@
+#include "constraint.h"
+
+
+Constraint::Constraint(Solution const &solution) : solution(solution) {}
+
+Solution const &Constraint::getSolution() const
+{
+    return solution.get();
+}
+
+PDPTWData const &Constraint::data() const
+{
+    return getSolution().getData();
+}
+
+void Constraint::setSolution(Solution const &newSolutionOwner)
+{
+    solution = newSolutionOwner;
+}
+
+
+void ModificationVisitor::applyVariant(ModificationApplyVariant const &applyModificationVariant)
+{
+    // lambda auto&& + std::visit combo
+    // allows to split the variant to each strongly typed function for each modification (see the protected pure virtual functions apply)
+    // If compilation breaks here, it is likely that a type T in the ModificationApplyVariant has no function ModificationVisitor::apply(T const &) associated
+    std::visit([this](auto &&op) { this->apply(op); }, applyModificationVariant);   
+}
+
+bool ConstraintVisitor::checkVariant(ModificationCheckVariant const &checkModificationVariant)
+{
+    // lambda auto&& + std::visit combo
+    // allows to split the variant to each strongly typed function for each modification (see the protected pure virtual functions apply)
+    // If compilation breaks here, it is likely that a type T in the ModificationCheckVariant has no function ConstraintVisitor::apply(T const &) associated
+    return std::visit([this](auto &&op) { return this->check(op); }, checkModificationVariant);
+}
diff --git a/src/lns/constraints/constraint.h b/src/lns/constraints/constraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..f41e778eab64f2a6c3869012dfbd34615667df7a
--- /dev/null
+++ b/src/lns/constraints/constraint.h
@@ -0,0 +1,98 @@
+#pragma once
+#include <variant>
+#include "./../solution/solution.h"
+
+// all modifications
+#include "./../modification/pair/insert_pair.h"
+#include "./../modification/pair/remove_pair.h"
+#include "./../modification/route/insert_route.h"
+#include "./../modification/route/remove_route.h"
+
+
+using ModificationApplyVariant =
+        std::variant<std::reference_wrapper<InsertPair const>, std::reference_wrapper<InsertRoute const>,
+                     std::reference_wrapper<RemovePair const>, std::reference_wrapper<RemoveRoute const>>;
+
+// defines the variant that can store all the modifications that can be checked (recreation modifications)
+using ModificationCheckVariant =
+        std::variant<std::reference_wrapper<InsertPair const>, std::reference_wrapper<InsertRoute const>,
+                     std::reference_wrapper<RemovePair const>, std::reference_wrapper<RemoveRoute const>>;
+
+
+/**
+ * Visitor pattern for the modifications.
+ * It splits the variant into separate apply functions for each Modification.
+ */
+class ModificationVisitor
+{
+protected:
+    // A child class must handle all the modification types ie. implement all these functions
+    virtual void apply(InsertPair const &op) = 0;
+    virtual void apply(InsertRoute const &op) = 0;
+    virtual void apply(RemovePair const &op) = 0;
+    virtual void apply(RemoveRoute const &op) = 0;
+
+public:
+    /**
+     * A modification has been applied to the solution,
+     * the constraint can use information from the modification to update its state.
+     */
+    void applyVariant(ModificationApplyVariant const &applyModificationVariant);
+};
+
+
+/**
+ * Visitor pattern for the constraint. Adds the check part that constraints must implement
+ * It splits the variant into separate check/apply functions for each Modification.
+ */
+class ConstraintVisitor : public ModificationVisitor
+{
+protected:
+    // A child class must handle all the modification types ie. implement all these functions
+    virtual bool check(InsertPair const &op) const = 0;
+    virtual bool check(InsertRoute const &op) const = 0;
+    virtual bool check(RemovePair const &op) const = 0;
+    virtual bool check(RemoveRoute const &op) const = 0;
+
+
+public:
+virtual ~ConstraintVisitor() = default;
+    /**
+     * Checks that a modification is valid for the solution
+     * If a check fails it must return false.
+     */
+    bool checkVariant(ModificationCheckVariant const &checkModificationVariant);
+};
+
+
+/**
+ * Base class for a constraint.
+ * It has to define all checks (from ConstraintVisitor),
+ * and can modify its state with the apply (from ModificationVisitor), it looks like a listener pattern
+ */
+class Constraint : public ConstraintVisitor
+{
+    std::reference_wrapper<Solution const> solution;
+
+protected:
+    explicit Constraint(Solution const &);
+    PDPTWData const &data() const;
+
+public:
+    /**
+     * It is expected that the new Solution is in valid state regarding precedence graph and times when cloning
+     */
+    virtual std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const = 0;
+
+    Solution const &getSolution() const;
+
+    // used when a solution is moved, we must update the owner
+    void setSolution(Solution const &newSolutionOwner);
+     ~Constraint() override = default;
+
+    /**
+     * Callback when many destruction are done. It is expected that checks work after a call to this.
+     * Defaults to no op
+    */
+    virtual void endOfDestructionCallback() {}
+};
\ No newline at end of file
diff --git a/src/lns/constraints/time_window/time_window_constraint.cpp b/src/lns/constraints/time_window/time_window_constraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fe4134e7e243056ab7e1fc05f85d2b140563def8
--- /dev/null
+++ b/src/lns/constraints/time_window/time_window_constraint.cpp
@@ -0,0 +1,137 @@
+#include "time_window_constraint.h"
+#include "input/data.h"
+#include "input/pdptw_data.h"
+#include "input/time_window.h"
+#include "lns/solution/solution.h"
+
+
+TimeWindowConstraint::TimeWindowConstraint(Solution const &solution) : Constraint(solution)
+{
+    // Empty
+}
+
+std::unique_ptr<Constraint> TimeWindowConstraint::clone(Solution const &newOwningSolution) const {
+    std::unique_ptr<TimeWindowConstraint> clonePtr = std::make_unique<TimeWindowConstraint>(newOwningSolution);
+    clonePtr->allRouteReachTimes = allRouteReachTimes;
+    return clonePtr;
+}
+
+
+// Copie le vecteur de reach time de la route concernée
+// Insère les positions pickup/delivery
+// refait l'ordo sur le nouveau vecteur
+bool TimeWindowConstraint::checkInsertion(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos) const
+{
+    ReachTimeVector const &reachTimes = allRouteReachTimes.at(routeIndex);
+
+    // COPY route vector
+    std::vector<int> route(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end()) ;
+    // COPY reachTimes vector
+    ReachTimeVector newReachTimes(reachTimes.begin(), reachTimes.end());
+
+    // Insert pickup and delivery
+    route.insert(route.begin() + pickupPos, pair.getPickup().getId());
+    route.insert(route.begin() + deliveryPos, pair.getDelivery().getId());
+
+    // Compute new reach time
+    computeReachTimes(data, route, newReachTimes);
+
+    // Check Time Windows
+    for (int i = 0; i < reachTimes.size(); ++i) 
+    {
+        if (! data.getLocation(route[i]).getTimeWindow().isValid(newReachTimes.at(i)) )
+        {
+            return false;
+        }
+    }
+    return true;    
+}
+
+void TimeWindowConstraint::computeReachTimes(const PDPTWData& data, const std::vector<int> & routeIDs, ReachTimeVector & reachTimes) const
+{
+    // Adjust the size of reachTimes vector
+    reachTimes.resize(routeIDs.size(), 0);
+    // Time to the first location
+    reachTimes[0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
+    // Compute other reachTimes (max between arrival and start of the time window)
+    for (int i = 1; i < routeIDs.size(); ++i) {
+        TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]);
+        TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration();
+        TimeInteger startTW = data.getLocation(routeIDs[i]).getTimeWindow().getStart();
+        reachTimes[i] = std::max(reachTimes[i - 1] + serviceTime + travelTime, startTW);
+    }
+}
+
+
+void TimeWindowConstraint::ApplyModif(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos, bool addPair)
+{
+    // COPY route vector
+    std::vector<int> routeIDs(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end());
+    
+    // Adjust pickup and delivery
+    if (addPair)
+    {
+        routeIDs.insert(routeIDs.begin() + pickupPos, pair.getPickup().getId());
+        routeIDs.insert(routeIDs.begin() + deliveryPos, pair.getDelivery().getId());
+    }
+    else
+    {
+        routeIDs.erase(routeIDs.begin() + deliveryPos);  
+        routeIDs.erase(routeIDs.begin() + pickupPos); 
+    }
+
+    // Adjust the size of reachTimes vector
+    allRouteReachTimes[routeIndex].resize(routeIDs.size(), 0);
+    // Time to the first location
+    allRouteReachTimes[routeIndex][0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
+    // Compute other reachTimes (max between arrival and start of the time window)
+    for (int i = 1; i < routeIDs.size(); ++i) {
+        TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]);
+        TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration();
+        TimeInteger startTW = data.getLocation(routeIDs[i]).getTimeWindow().getStart();
+        allRouteReachTimes[routeIndex][i] = std::max(allRouteReachTimes[routeIndex][i - 1] + serviceTime + travelTime, startTW);
+    }
+}
+
+
+bool TimeWindowConstraint::check(InsertPair const &op) const
+{
+    return checkInsertion(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion()); 
+}
+void TimeWindowConstraint::apply(InsertPair const &op)
+{
+    ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true); 
+}
+
+bool TimeWindowConstraint::check(InsertRoute const &op) const
+{
+    return true;
+}
+void TimeWindowConstraint::apply(InsertRoute const &op)
+{
+    allRouteReachTimes.emplace_back();
+}
+
+
+bool TimeWindowConstraint::check(RemovePair const &op) const
+{
+    return true;
+}
+void TimeWindowConstraint::apply(RemovePair const &op)
+{
+    ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupDeletion(), op.getDeliveryDeletion(), false); 
+}
+
+
+bool TimeWindowConstraint::check(RemoveRoute const &op) const
+{
+    return true;
+}
+void TimeWindowConstraint::apply(RemoveRoute const &op)
+{
+    allRouteReachTimes.erase(allRouteReachTimes.begin() + op.getRouteIndex());
+}
+
+
+
+
diff --git a/src/lns/constraints/time_window/time_window_constraint.h b/src/lns/constraints/time_window/time_window_constraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..89bc0554cb5788eeeda339aac70fca22191d6888
--- /dev/null
+++ b/src/lns/constraints/time_window/time_window_constraint.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "lns/constraints/constraint.h"
+#include "input/pair.h"
+#include "input/time_window.h"
+#include <vector>
+
+/**
+ * Time Window Constraint
+ * Check that the time windows are respected.
+ * For now, compute all time window in a route
+ * TO DO FTS
+ */
+class TimeWindowConstraint : public Constraint
+{
+public:
+    explicit TimeWindowConstraint(Solution const &);
+    TimeWindowConstraint(TimeWindowConstraint const &) = default;
+
+    std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const override;
+    
+private:
+    using ReachTimeVector = std::vector<TimeInteger>;
+    
+
+
+    /**
+    *   For each route, store the reach time of each location
+    */
+    std::vector<ReachTimeVector> allRouteReachTimes;  
+
+    // Recalcul tous les reachTimes pour une route
+    ReachTimeVector computeReachTimes(const Route& route) const;
+    bool updateReachTimes(const PDPTWData& data, Pair & pair,int routeIndex, int pickupPos, int deliveryPos);
+
+    /**
+    *   Check if the insertion of a pair pickup/delivery is valid or not.
+    *   COPY the route where we insert the pair !
+    */
+    bool checkInsertion(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos) const; 
+
+    /**
+    *   Given route IDs, compute the reachTimes of the route.
+    *   If a vehicule is in advance, set the reach time to start of the timeWindow.
+    *   Modify reachTimes vector !
+    */
+    void computeReachTimes(const PDPTWData& data, const std::vector<int> & routeIDs, ReachTimeVector & reachTimes) const;
+
+    /**
+    *   Given route IDs, modify the reachTimes
+    */
+    void ApplyModif(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos,  bool addPair);
+
+
+    void apply(InsertPair const &op) override;
+    void apply(InsertRoute const &op) override;
+    void apply(RemovePair const &op) override;
+    void apply(RemoveRoute const &op) override;
+ 
+    bool check(InsertPair const &op) const override;
+    bool check(InsertRoute const &op) const override;
+    bool check(RemovePair const &op) const override;
+    bool check(RemoveRoute const &op) const override;
+
+public: 
+
+};
\ No newline at end of file
diff --git a/src/lns/modification/pair/insert_pair.cpp b/src/lns/modification/pair/insert_pair.cpp
index 46160fd88bbe9a00b3ad9f7d5ce5a846f593e467..206d66f81936e1b3f1dcafae56f2911c86b2ed89 100644
--- a/src/lns/modification/pair/insert_pair.cpp
+++ b/src/lns/modification/pair/insert_pair.cpp
@@ -8,7 +8,17 @@ InsertPair::InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertio
       pickupInsertion(pickupInsertion), 
       deliveryInsertion(deliveryInsertion), 
       pickupLocation(pickupLocation), 
-      deliveryLocation(deliveryLocation) {}
+      deliveryLocation(deliveryLocation),
+      pair(Pair(pickupLocation, deliveryLocation)) {}
+
+InsertPair::InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion, 
+    Pair const &pair) 
+    : routeIndex(routeIndex), 
+      pickupInsertion(pickupInsertion), 
+      deliveryInsertion(deliveryInsertion), 
+      pickupLocation(pair.getPickup()), 
+      deliveryLocation(pair.getDelivery()),
+      pair(pair) {}
 
 
 void InsertPair::modifySolution(Solution &solution) 
@@ -79,3 +89,9 @@ const Location *InsertPair::getAddedLocation() const
     return &pickupLocation;
 }
 
+const Pair &InsertPair::getPair() const 
+{
+    return pair;
+}
+
+
diff --git a/src/lns/modification/pair/insert_pair.h b/src/lns/modification/pair/insert_pair.h
index a2537b504a3dcd75c7eb374e8e58302edfd964e1..ddeea7f9d389a828abe7fcb47e9ceb196f74fb28 100644
--- a/src/lns/modification/pair/insert_pair.h
+++ b/src/lns/modification/pair/insert_pair.h
@@ -3,6 +3,7 @@
 #include "./../atomic_recreation.h"
 #include "./../../solution/solution.h"
 #include "./../../../input/location.h"
+#include "./../../../input/pair.h"
 #include <functional>
 
 class Route;
@@ -37,8 +38,11 @@ class InsertPair : public AtomicRecreation
      */
     Location const & deliveryLocation;
 
+    Pair const & pair;
+
 public:
     InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion, Location const &pickupLocation, Location const &deliveryLocation);
+    InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion, Pair const &pair);
 
     void modifySolution(Solution &solution) override;
     double evaluate(Solution const &solution) const override;
@@ -48,6 +52,7 @@ public:
     int getRouteIndex() const;
     Location const &getPickupLocation() const;
     Location const &getDeliveryLocation() const;
+    Pair const &getPair() const;
 
     Location const *getAddedLocation() const override;
     
diff --git a/src/lns/modification/pair/remove_pair.cpp b/src/lns/modification/pair/remove_pair.cpp
index d279e85c89734ff69cb4ed725249a79378919cd9..fcb2fb40fa9b32fea860edffe311c2fcf85968d0 100644
--- a/src/lns/modification/pair/remove_pair.cpp
+++ b/src/lns/modification/pair/remove_pair.cpp
@@ -7,8 +7,18 @@ RemovePair::RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion,
     routeIndex(routeIndex), 
     pickupDeletion(pickupDeletion), 
     deliveryDeletion(deliveryDeletion), 
-    pickupLocation(pickupLocation),
-    deliveryLocation(deliveryLocation) {}
+    pickupLocation(pickupLocation), 
+    deliveryLocation(deliveryLocation),
+    pair(Pair(pickupLocation, deliveryLocation)) {}
+
+RemovePair::RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, 
+    Pair const &pair) :
+    routeIndex(routeIndex), 
+    pickupDeletion(pickupDeletion), 
+    deliveryDeletion(deliveryDeletion), 
+    pickupLocation(pair.getPickup()), 
+    deliveryLocation(pair.getDelivery()),
+    pair(pair) {}
 
 void RemovePair::modifySolution(Solution &solution)
 {
@@ -78,4 +88,9 @@ Location const & RemovePair::getDeliveryLocation() const
 std::vector<int> const & RemovePair::getDeletedRequests() const
 {
     return removedLocationID;
+}
+
+Pair const &RemovePair::getPair() const
+{
+    return pair;
 }
\ No newline at end of file
diff --git a/src/lns/modification/pair/remove_pair.h b/src/lns/modification/pair/remove_pair.h
index d71a9629b9aa39be849cdcfa46de70fdcf01dfff..cb543e724c4cfb36c1a5f05f40420c012624b4e5 100644
--- a/src/lns/modification/pair/remove_pair.h
+++ b/src/lns/modification/pair/remove_pair.h
@@ -3,6 +3,7 @@
 #include "./../atomic_destruction.h"
 #include "./../../solution/solution.h"
 #include "./../../../input/location.h"
+#include "./../../../input/pair.h"
 #include <functional>
 
 class Route;
@@ -35,6 +36,7 @@ class RemovePair : public AtomicDestruction
      */
     Location const & deliveryLocation;
 
+    Pair const & pair;
 
     /**
      * Removed Location ID (empty before ModifySolution is called)
@@ -44,6 +46,7 @@ class RemovePair : public AtomicDestruction
 public:
     
     RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, Location const &pickupLocation, Location const &deliveryLocation);
+    RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, Pair const &pair);
 
     void modifySolution(Solution &solution) override;
     double evaluate(Solution const &solution) const override;
@@ -54,6 +57,8 @@ public:
     Location const &getPickupLocation() const;
     Location const &getDeliveryLocation() const;
 
+    Pair const &getPair() const;
+
     /**
      *  Return the location ID of location that has been deleted
      */
diff --git a/src/lns/solution/route.h b/src/lns/solution/route.h
index 5f645698614e6fa64afe312234a0c0c938ffd19d..67686cfd8bbaba29dff91caadf984dcc3d785498 100644
--- a/src/lns/solution/route.h
+++ b/src/lns/solution/route.h
@@ -11,8 +11,9 @@ class Route
 {
 
 private:
-    int cost;
     std::vector<int> route;
+    int cost;
+    
 
 
     /* Stocké dans les contraintes
diff --git a/src/main.cpp b/src/main.cpp
index 21ba0830faf30f4b9912421f7190cb30c02c511a..7c736af9788670fc1a0bf7902534f0f5bfe223d7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -13,6 +13,8 @@
 #include "input/time_window.h"
 #include "input/json_parser.h"
 #include "input/data.h"
+#include "lns/constraints/capacity/capacity_constraint.h"
+#include "lns/constraints/time_window/time_window_constraint.h"
 #include "lns/solution/solution.h"
 #include "lns/modification/pair/insert_pair.h"
 #include "lns/modification/route/insert_route.h"
@@ -24,10 +26,9 @@ using json = nlohmann::json;
 
 int main(int argc, char const *argv[])
 {
-    /* code */
-
     //std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/test_inst.json"; 
-    std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/n100/bar-n100-1.json";
+    //std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/n100/bar-n100-1.json";
+    std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/Nantes_1.json";
     //std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/n5000/bar-n5000-1.json";
 
     std::cout << filepath << "\n";
@@ -38,58 +39,58 @@ int main(int argc, char const *argv[])
     /* 
     * test 
     */
+    Solution emptySol = Solution(data);
+
+    // SOLUTION 1-6-2-7 (time ; 104)
+
+    Solution::RequestBank bank {3,4,5,8,9,10};
+
+    std::vector<int> path {1,2,6,7};
+    Route route = Route(path, 0);
+    std::vector<Route> routes;
+    routes.push_back(route);
 
-    // Empty Solution
-    Solution sol = Solution(data);
+    int totalCost = 0;
     
-    InsertRoute op1 = InsertRoute();
+    Solution sol = Solution(data, bank, routes, totalCost);
+
+    sol.print();
 
-    // Ajoute une route vide
-    op1.modifySolution(sol);
 
-    Location r1P = data.getLocations()[0];
-    Location r1D = data.getLocations()[50];
+    // Couple pickup/delivery
     Location r2P = data.getLocations()[1];
-    Location r2D = data.getLocations()[51];
+    Location r2D = data.getLocations()[6];
     Location r3P = data.getLocations()[2];
-    Location r3D = data.getLocations()[52];
+    Location r3D = data.getLocations()[7];
 
-    // Opération : Ajoute une paire pickup delivery à la route 0 en position 0 et 0
-    InsertPair op2 = InsertPair(0, 0, 0, r1P, r1D);
-    op2.modifySolution(sol);
-    InsertPair op3 = InsertPair(0, 0, 2, r2P, r2D);
-    op3.modifySolution(sol);
-    std::cout << "--- \n";
+    Pair pair2 = Pair(r2P, r2D);
+    Pair pair3 = Pair(r3P, r3D);
+    
+    // Modification 
+    InsertPair opInsert = InsertPair(0, 2, 2, pair3);
 
-    data::routeCost(data, sol.getRoute(0));
+    /*
 
-    InsertPair op4 = InsertPair(0, 3, 4, r3P, r3D);
-    std::cout << "cout d'insert : "<< op4.evaluate(sol) << "\n";
-    op4.modifySolution(sol);
+    CapacityConstraint cap_const = CapacityConstraint(sol);
     
-    std::cout << "--- \n";
-    sol.print();
-    data::routeCost(data, sol.getRoute(0));
-
-    // TO DO
-    // Test supr
-    std::cout << "--- \n";
-    RemovePair op5 = RemovePair(0, 3, 5, r3P, r3D);
 
-    std::cout << "cout de supr : "<< op5.evaluate(sol) << "\n";
+    cap_const.initCapacities();
+    cap_const.print();
 
-    op5.modifySolution(sol);
-    sol.print();
+    std::cout << "Is Valid ? : " << cap_const.checkVariant(opInsert) << "\n";
 
-    data::routeCost(data, sol.getRoute(0));
+    cap_const.applyVariant(opInsert);
 
-    RemoveRoute op6 = RemoveRoute(0);
+    cap_const.print();
 
-    std::cout << "cout de supr : "<< op6.evaluate(sol) << "\n";
+    RemovePair opRemove = RemovePair(0, 2, 3, pair3);
 
-    op6.modifySolution(sol);
+    cap_const.applyVariant(opRemove);
+    
+    cap_const.print();
+    */
 
-    sol.print();
 
+    TimeWindowConstraint twconst = TimeWindowConstraint(sol);
     return 0;
 }