diff --git a/src/topupopt/problems/esipp/time.py b/src/topupopt/problems/esipp/time.py
index 7fc02bb54917c22c185ce6335b8609a151551635..378483afc0cd638454288f59a92303314269249b 100644
--- a/src/topupopt/problems/esipp/time.py
+++ b/src/topupopt/problems/esipp/time.py
@@ -134,8 +134,13 @@ class TimeFrame:
 
     def consecutive_qpk(self, qpk_keyed_dict: dict) -> bool:
         "Returns True if all (q,p,k) tuple keys are valid and consecutive."
-        # TODO: here
-        raise NotImplementedError
+        # all k intervals have to be consecutive for each (q,p) pair
+        set_qp = set(qpk[0:2] for qpk in qpk_keyed_dict.keys())
+        for qp in set_qp:
+            for k in range(self.number_time_intervals(qp[0])):
+                if (*qp,k) not in qpk_keyed_dict:
+                    return False
+        return True
 
     # *************************************************************************
     # *************************************************************************
diff --git a/tests/test_esipp_time.py b/tests/test_esipp_time.py
index 349f2701aaaa9e784f9310a89942352c012566ec..18bdd01fa3b29e5e445c80717a442678a7d944df 100644
--- a/tests/test_esipp_time.py
+++ b/tests/test_esipp_time.py
@@ -202,6 +202,28 @@ class TestTimeFrame:
         assert not tf.complete_qpk(
             {(0, 0, 0): 1, (0, 0, 1): 1, (0, 1, 0): 1, (0, 1, 1): 1}
         )
+        # qpk: consecutive
+        assert tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 1): 1,
+                (0, 1, 0): 1,
+                (0, 1, 1): 1,
+                (0, 2, 0): 1,
+                (0, 2, 1): 1,
+            }
+        )
+        # qpk: not consecutive
+        assert not tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 1): 1,
+                (0, 1, 1): 1,
+                (0, 1, 2): 1,
+                (0, 2, 0): 1,
+                (0, 2, 1): 1,
+            }
+        )
 
         qk_dict = {qk: None for qk in tf.qk()}
         qp_dict = {qp: None for qp in tf.qp()}
@@ -357,6 +379,28 @@ class TestTimeFrame:
         assert not tf.complete_qpk(
             {(0, 0, 0): 1, (0, 0, 1): 1, (1, 1, 0): 1, (1, 1, 1): 1}
         )
+        # qpk: consecutive
+        assert tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 1): 1,
+                (1, 1, 0): 1,
+                (1, 1, 1): 1,
+                (1, 2, 0): 1,
+                (1, 2, 1): 1,
+            }
+        )
+        # qpk: not consecutive
+        assert not tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 3): 1,
+                (1, 1, 0): 1,
+                (1, 1, 1): 1,
+                (1, 2, 0): 1,
+                (1, 2, 1): 1,
+            }
+        )
 
         qk_dict = {qk: None for qk in tf.qk()}
         qp_dict = {qp: None for qp in tf.qp()}
@@ -507,6 +551,30 @@ class TestTimeFrame:
                 (1, 2, 1): 1,
             }
         )
+        # qpk: consecutive
+        assert tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 1): 1,
+                (0, 1, 0): 1,
+                (0, 1, 1): 1,
+                (1, 2, 0): 1,
+                (1, 2, 1): 1,
+                (1, 2, 2): 1,
+            }
+        )
+        # qpk: not consecutive
+        assert not tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 1): 1,
+                (0, 1, 0): 1,
+                (0, 1, 1): 1,
+                (1, 2, 0): 1,
+                (1, 2, 1): 1,
+                (1, 2, 3): 1,
+            }
+        )
 
         qk_dict = {qk: None for qk in tf.qk()}
         qp_dict = {qp: None for qp in tf.qp()}
@@ -672,6 +740,40 @@ class TestTimeFrame:
                 (1, 2, 1): 1,
             }
         )
+        # qpk: consecutive
+        assert tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 1): 1,
+                (0, 1, 0): 1,
+                (0, 1, 1): 1,
+                (0, 2, 0): 1,
+                (0, 2, 1): 1,
+                (1, 0, 0): 1,
+                (1, 0, 1): 1,
+                (1, 1, 0): 1,
+                (1, 1, 1): 1,
+                (1, 2, 0): 1,
+                (1, 2, 1): 1,
+            }
+        )
+        # qpk: not consecutive
+        assert not tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (0, 0, 1): 1,
+                (0, 1, 0): 1,
+                (0, 1, 1): 1,
+                (0, 2, 0): 1,
+                (0, 2, 2): 1,
+                (1, 0, 0): 1,
+                (1, 0, 1): 1,
+                (1, 1, 0): 1,
+                (1, 1, 1): 1,
+                (1, 2, 0): 1,
+                (1, 2, 1): 1,
+            }
+        )
 
         qk_dict = {qk: None for qk in tf.qk()}
         qp_dict = {qp: None for qp in tf.qp()}
@@ -905,6 +1007,40 @@ class TestTimeFrame:
                 # (5, 2, 1): 1,
             }
         )
+        # qpk: consecutive
+        assert tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (1, 0, 0): 1,
+                (2, 1, 0): 1,
+                (3, 1, 0): 1,
+                (4, 2, 0): 1,
+                (5, 2, 0): 1,
+                (0, 0, 1): 1,
+                (1, 0, 1): 1,
+                (2, 1, 1): 1,
+                (3, 1, 1): 1,
+                (4, 2, 1): 1,
+                (5, 2, 1): 1,
+            }
+        )
+        # qpk: not consecutive
+        assert not tf.consecutive_qpk(
+            {
+                (0, 0, 0): 1,
+                (1, 0, 0): 1,
+                (2, 1, 0): 1,
+                (3, 1, 0): 1,
+                (4, 2, 0): 1,
+                (5, 2, 0): 1,
+                (0, 0, 2): 1,
+                (1, 0, 1): 1,
+                (2, 1, 1): 1,
+                (3, 1, 1): 1,
+                (4, 2, 1): 1,
+                (5, 2, 1): 1,
+            }
+        )
 
         qk_dict = {qk: None for qk in tf.qk()}
         qp_dict = {qp: None for qp in tf.qp()}