def test_almost_equal(self): self.assertTrue(almost_equal(sympy.sin(a) * 0.5, sympy.sin(a) / 2)) self.assertIsNone(almost_equal(sympy.sin(a) * 0.5, sympy.sin(b) / 2)) self.assertFalse(almost_equal(sympy.sin(a), sympy.sin(a) + 1e-14)) self.assertTrue( almost_equal(sympy.sin(a), sympy.sin(a) + 1e-14, epsilon=1e-13))
def __init__(self, *subtemplates: Union[AtomicPulseTemplate, MappingTuple, MappingPulseTemplate], external_parameters: Optional[Set[str]] = None, identifier: Optional[str] = None, parameter_constraints: Optional[List] = None, measurements: Optional[List[MeasurementDeclaration]] = None, registry: PulseRegistryType = None, duration: Union[str, Expression, bool] = False) -> None: """Parallels multiple AtomicPulseTemplates of the same duration. The duration equality check is performed on construction by default. If the duration keyword argument is given the check is performed on instantiation (when build_waveform is called). duration can be a Expression to enforce a certain duration or True for an unspecified duration. Args: *subtemplates: Positional arguments are subtemplates to combine. identifier: Forwarded to AtomicPulseTemplate.__init__ parameter_constraints: Forwarded to ParameterConstrainer.__init__ measurements: Forwarded to AtomicPulseTemplate.__init__ duration: Enforced duration of the pulse template on instantiation. build_waveform checks all sub-waveforms have this duration. If True the equality of durations is only checked durtin instantiation not construction. external_parameters: No functionality. (Deprecated) """ AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements) ParameterConstrainer.__init__( self, parameter_constraints=parameter_constraints) self._subtemplates = [ st if isinstance(st, PulseTemplate) else MappingPulseTemplate.from_tuple(st) for st in subtemplates ] for subtemplate in self._subtemplates: if isinstance(subtemplate, AtomicPulseTemplate): continue elif isinstance(subtemplate, MappingPulseTemplate): if isinstance(subtemplate.template, AtomicPulseTemplate): continue else: raise TypeError( 'Non atomic subtemplate of MappingPulseTemplate: {}'. format(subtemplate.template)) else: raise TypeError( 'Non atomic subtemplate: {}'.format(subtemplate)) if not self._subtemplates: raise ValueError('Cannot create empty MultiChannelPulseTemplate') defined_channels = [st.defined_channels for st in self._subtemplates] # check there are no intersections between channels for i, channels_i in enumerate(defined_channels): for j, channels_j in enumerate(defined_channels[i + 1:]): if channels_i & channels_j: raise ChannelMappingException( 'subtemplate {}'.format(i + 1), 'subtemplate {}'.format(i + 2 + j), (channels_i | channels_j).pop()) if external_parameters is not None: warnings.warn( "external_parameters is an obsolete argument and will be removed in the future.", category=DeprecationWarning) if not duration: duration = self._subtemplates[0].duration for subtemplate in self._subtemplates[1:]: if almost_equal(duration.sympified_expression, subtemplate.duration.sympified_expression): continue else: raise ValueError( 'Could not assert duration equality of {} and {}'. format(duration, subtemplate.duration)) self._duration = None elif duration is True: self._duration = None else: self._duration = ExpressionScalar(duration) self._register(registry=registry)