Repository: qutech/qupulse
Issue: RepetitionPulseTemplate sequences body if repetition count is null

The adding of the repetition instruction and sequencing of the body should only happen if the repetition count is larger null

Changed files:
qctoolkit/pulses/repetition_pulse_template.py, tests/pulses/repetition_pulse_template_tests.py

diff --git a/qctoolkit/pulses/repetition_pulse_template.py b/qctoolkit/pulses/repetition_pulse_template.py
index faef71cc..438001c7 100644
--- a/qctoolkit/pulses/repetition_pulse_template.py
+++ b/qctoolkit/pulses/repetition_pulse_template.py
@@ -102,9 +102,12 @@ class RepetitionPulseTemplate(LoopPulseTemplate, ParameterConstrainer, Measureme
 
         repetition_count = ExpressionScalar.make(repetition_count)
 
-        if (repetition_count < 0) is True:
+        if repetition_count < 0:
             raise ValueError('Repetition count may not be negative')
 
+        if repetition_count == 0:
+            warn("Repetition pulse template with 0 repetitions on construction.")
+
         self._repetition_count = repetition_count
 
     @property
@@ -143,20 +146,23 @@ class RepetitionPulseTemplate(LoopPulseTemplate, ParameterConstrainer, Measureme
                        channel_mapping: Dict[ChannelID, Optional[ChannelID]],
                        instruction_block: InstructionBlock) -> None:
         self.validate_parameter_constraints(parameters=parameters)
-
-        body_block = InstructionBlock()
-        body_block.return_ip = InstructionPointer(instruction_block, len(instruction_block))
-
         try:
             real_parameters = {v: parameters[v].get_value() for v in self._repetition_count.variables}
         except KeyError:
             raise ParameterNotProvidedException(next(v for v in self.repetition_count.variables if v not in parameters))
+
         self.insert_measurement_instruction(instruction_block,
                                             parameters=parameters,
                                             measurement_mapping=measurement_mapping)
-        instruction_block.add_instruction_repj(self.get_repetition_count_value(real_parameters), body_block)
-        sequencer.push(self.body, parameters=parameters, conditions=conditions,
-                       window_mapping=measurement_mapping, channel_mapping=channel_mapping, target_block=body_block)
+
+        repetition_count = self.get_repetition_count_value(real_parameters)
+        if repetition_count > 0:
+            body_block = InstructionBlock()
+            body_block.return_ip = InstructionPointer(instruction_block, len(instruction_block))
+
+            instruction_block.add_instruction_repj(repetition_count, body_block)
+            sequencer.push(self.body, parameters=parameters, conditions=conditions,
+                           window_mapping=measurement_mapping, channel_mapping=channel_mapping, target_block=body_block)
 
     def requires_stop(self,
                       parameters: Dict[str, Parameter],
diff --git a/tests/pulses/repetition_pulse_template_tests.py b/tests/pulses/repetition_pulse_template_tests.py
index c82f2caa..f947ffe4 100644
--- a/tests/pulses/repetition_pulse_template_tests.py
+++ b/tests/pulses/repetition_pulse_template_tests.py
@@ -1,4 +1,5 @@
 import unittest
+import warnings
 
 import numpy as np
 
@@ -89,6 +90,11 @@ class RepetitionPulseTemplateTest(unittest.TestCase):
         with self.assertRaises(ValueError):
             RepetitionPulseTemplate(body, Expression(-1))
 
+        with warnings.catch_warnings(record=True) as w:
+            RepetitionPulseTemplate(body, 0)
+            self.assertEqual(1, len(w), msg='RepetitionPulseTemplate did not raise a warning for 0 repetitions on consruction.')
+            self.assertTrue('0 repetitions' in str(w[-1].message), msg='RepetitionPulseTemplate did not raise a warning for 0 repetitions on consruction.')
+
     def test_parameter_names_and_declarations(self) -> None:
         body = DummyPulseTemplate()
         t = RepetitionPulseTemplate(body, 5)
@@ -229,6 +235,42 @@ class RepetitionPulseTemplateSequencingTests(unittest.TestCase):
         pt = RepetitionPulseTemplate(DummyPulseTemplate(parameter_names={'a'}), 'n', parameter_constraints=['a<c'])
         self.assertEqual(pt.parameter_names, {'a','c', 'n'})
 
+    def test_rep_count_zero_constant(self) -> None:
+        repetitions = 0
+        parameters = {}
+        measurement_mapping = {}
+        conditions = {}
+        channel_mapping = {}
+
+        with warnings.catch_warnings(record=True):
+            t = RepetitionPulseTemplate(self.body, repetitions)
+            t.build_sequence(self.sequencer, parameters, conditions, measurement_mapping, channel_mapping, self.block)
+
+            self.assertFalse(self.block.embedded_blocks) # no new blocks created
+            self.assertFalse(self.block.instructions) # no instructions added to block
+
+    def test_rep_count_zero_declaration(self) -> None:
+        t = self.template
+        parameters = dict(foo=ConstantParameter(0))
+        measurement_mapping = {}
+        conditions = {}
+        channel_mapping = {}
+        t.build_sequence(self.sequencer, parameters, conditions, measurement_mapping, channel_mapping, self.block)
+
+        self.assertFalse(self.block.embedded_blocks) # no new blocks created
+        self.assertFalse(self.block.instructions) # no instructions added to block
+
+    def test_rep_count_neg_declaration(self) -> None:
+        t = self.template
+        parameters = dict(foo=ConstantParameter(-1))
+        measurement_mapping = {}
+        conditions = {}
+        channel_mapping = {}
+        t.build_sequence(self.sequencer, parameters, conditions, measurement_mapping, channel_mapping, self.block)
+
+        self.assertFalse(self.block.embedded_blocks)  # no new blocks created
+        self.assertFalse(self.block.instructions)  # no instructions added to block
+
 
 class RepetitionPulseTemplateSerializationTests(unittest.TestCase):