def _solve_(node, errList1, errList2, herr): errList2.append(herr * pow(2, -53)) expr1 = sum([seng.Abs(erri) for erri in errList1]) expr2 = sum([seng.Abs(erri) for erri in errList2]) if (seng.count_ops(expr1) >= opMax): # print("Solving Ferror @depth: ", node.depth) print("\nSolving f@depth :", node.depth) errList1 = [solve_remaining_error(expr1)] expr2_ops = seng.count_ops(expr2) #print("Solving h@depth :", node.depth) #errList2 = [solve_remaining_error(expr2)] if expr2_ops >= SopMax: print("\nSolving", expr2_ops, " h@depth :", node.depth) #errList2 = [solve_remaining_error(errList2)] errList2 = [_partial_solve_(errList2)] else: print("bwahahaha!", expr2_ops, expr2, SopMax) #errList2 = [solve_remaining_error(errList2+[herr*pow(2,-53)])] #if(seng.count_ops(expr2) > opMax): # print("Solving Herror @depth: ", node.depth, expr2_ops) # errList2 = [_partial_solve_(errList2+[herr*pow(2,-53)])] #else: # print("Else:", seng.count_ops(expr2_ops)) # errList2.append(herr*pow(2,-53)) return [errList1, errList2]
def rec_eval(obj): ch_lexpr = [child.rec_eval(child) for child in obj.children] lexpr = ops._FOPS[obj.token.type](ch_lexpr) if (seng.Abs(ch_lexpr[0])==1.0 or \ seng.Abs(ch_lexpr[1])==1.0): obj.rnd = 0.0 else: obj.rnd = max([max([child.rnd for child in obj.children]), 1.0]) return obj.simplify(lexpr)
def _HSIN_(node, S1, S2): f = node.children[0].f_expression errList1 = [node.f_expression] + \ [seng.Abs(Si*seng.cos(f)) for Si in S1] errList2 = [seng.Abs(Si.seng.cos(f)) for Si in S2] herr = seng.Abs( seng.sin(f + sum([seng.Abs(Si * pow(2, -53)) for Si in S1 + S2])) * sum([seng.Abs(Si * Sj) for Si in S1 + S2 for Sj in S1 + S2])) return _solve_(node, errList1, errList2, herr)
def _HEXP_(node, S1, S2): f = node.children[0].f_expression errList1 = [node.f_expression] + \ [seng.expand(Si*node.f_expression) for Si in S1] errList2 = [seng.expand(Si * node.f_expression) for Si in S2] ferr = sum([seng.Abs(Si * pow(2, -53)) for Si in S1 + S2]) + node.f_expression herr = sum([ seng.Abs(Si * Sj * seng.exp(ferr)) for Si in S1 + S2 for Sj in S1 + S2 ]) return _solve_(node, errList1, errList2, herr)
def _HLOG_(node, S1, S2): f = node.children[0].f_expression errList1 = [node.f_expression] + \ [Si/f for Si in S1] errList2 = [Si / f for Si in S2] hdenorm = (node.f_expression + 0.5 * sum([seng.Abs(Si * pow(2, -53)) for Si in S1 + S2]))**2 herr = sum([seng.Abs(Si * Sj) for Si in S for Sj in S]) / hdenorm return _solve_(node, errList1, errList2, herr)
def _solve1_(node, errList1, errList2, herr): expr1 = sum([seng.Abs(erri) for erri in errList1]) expr2 = sum([seng.Abs(erri) for erri in errList2]) + herr * pow(2, -53) #if(seng.count_ops(expr1) > opMax): # print("Solving Ferror @depth: ", node.depth) print("\nSolving f@depth :", node.depth) errList1 = [solve_remaining_error(expr1)] expr2_ops = seng.count_ops(expr2) print("Solving h@depth :", expr2, node.depth) errList2 = [solve_remaining_error(expr2)] return [errList1, errList2]
def eval(obj): lexpr = ops._FOPS[obj.token.type]( [child.f_expression for child in obj.children]) obj.rnd = max([min([child.rnd for child in obj.children]), obj.rnd]) if ((seng.Abs(obj.children[0].f_expression)==1.0 or \ seng.Abs(obj.children[1].f_expression)==1.0) and obj.token.type==MUL): obj.rnd = 0.0 else: #print("Before overwrite:", obj.rnd) obj.rnd = max( [max([child.rnd for child in obj.children]), obj.rnd, 1.0]) #print("After overwrite:", obj.rnd) lexpr = obj.simplify(lexpr) #print(seng.count_ops(lexpr), obj.depth) return lexpr
def _HINV_(node, S1, S2): f = node.f_expression inv_expr = 1.0 / f S1 = [solve_remaining_error(S1)] S2 = [solve_remaining_error(S2)] errList1 = [inv_expr] + [-Si / (f * f) for Si in S1] errList2 = [-Si / (f * f) for Si in S2] herr_denorm = (f + sum([seng.Abs(Si * pow(2, -53)) for Si in S1 + S2]))**3 herr = sum( [seng.Abs(Si * Sj) / herr_denorm for Si in S1 + S2 for Sj in S1 + S2]) return _solve_(node, errList1, errList2, herr)
def solve_remaining_error2(errList): #expr = sum([seng.Abs(erri) for erri in errList]) if type(errList).__name__ == 'list': expr = sum([seng.Abs(erri) for erri in errList]) else: expr = errList return max(utils.generate_signature_herror(expr))
def __init__( self, duration: Union[int, ParameterExpression], amp: Union[complex, ParameterExpression], sigma: Union[float, ParameterExpression], beta: Union[float, ParameterExpression], name: Optional[str] = None, limit_amplitude: Optional[bool] = None, ): """Create new pulse instance. Args: duration: Pulse length in terms of the sampling period `dt`. amp: The amplitude of the Drag envelope. sigma: A measure of how wide or narrow the Gaussian peak is; described mathematically in the class docstring. beta: The correction amplitude. name: Display name for this pulse envelope. limit_amplitude: If ``True``, then limit the amplitude of the waveform to 1. The default is ``True`` and the amplitude is constrained to 1. """ parameters = {"amp": amp, "sigma": sigma, "beta": beta} # Prepare symbolic expressions _t, _duration, _amp, _sigma, _beta = sym.symbols("t, duration, amp, sigma, beta") _center = _duration / 2 _gauss = _lifted_gaussian(_t, _center, _duration + 1, _sigma) _deriv = -(_t - _center) / (_sigma**2) * _gauss envelope_expr = _amp * (_gauss + sym.I * _beta * _deriv) consts_expr = _sigma > 0 valid_amp_conditions_expr = sym.And(sym.Abs(_amp) <= 1.0, sym.Abs(_beta) < _sigma) super().__init__( pulse_type=self.__class__.__name__, duration=duration, parameters=parameters, name=name, limit_amplitude=limit_amplitude, envelope=envelope_expr, constraints=consts_expr, valid_amp_conditions=valid_amp_conditions_expr, ) self.validate_parameters()
def generate_schedule_blocks(): """Standard QPY testcase for schedule blocks.""" from qiskit.pulse import builder, channels, library from qiskit.utils import optionals # Parameterized schedule test is avoided. # Generated reference and loaded QPY object may induce parameter uuid mismatch. # As workaround, we need test with bounded parameters, however, schedule.parameters # are returned as Set and thus its order is random. # Since schedule parameters are validated, we cannot assign random numbers. # We need to upgrade testing framework. schedule_blocks = [] # Instructions without parameters with builder.build() as block: with builder.align_sequential(): builder.set_frequency(5e9, channels.DriveChannel(0)) builder.shift_frequency(10e6, channels.DriveChannel(1)) builder.set_phase(1.57, channels.DriveChannel(0)) builder.shift_phase(0.1, channels.DriveChannel(1)) builder.barrier(channels.DriveChannel(0), channels.DriveChannel(1)) builder.play(library.Gaussian(160, 0.1, 40), channels.DriveChannel(0)) builder.play(library.GaussianSquare(800, 0.1, 64, 544), channels.ControlChannel(0)) builder.play(library.Drag(160, 0.1, 40, 1.5), channels.DriveChannel(1)) builder.play(library.Constant(800, 0.1), channels.MeasureChannel(0)) builder.acquire(1000, channels.AcquireChannel(0), channels.MemorySlot(0)) schedule_blocks.append(block) # Raw symbolic pulse if optionals.HAS_SYMENGINE: import symengine as sym else: import sympy as sym duration, amp, t = sym.symbols("duration amp t") # pylint: disable=invalid-name expr = amp * sym.sin(2 * sym.pi * t / duration) my_pulse = library.SymbolicPulse( pulse_type="Sinusoidal", duration=100, parameters={"amp": 0.1}, envelope=expr, valid_amp_conditions=sym.Abs(amp) <= 1.0, ) with builder.build() as block: builder.play(my_pulse, channels.DriveChannel(0)) schedule_blocks.append(block) # Raw waveform my_waveform = 0.1 * np.sin(2 * np.pi * np.linspace(0, 1, 100)) with builder.build() as block: builder.play(my_waveform, channels.DriveChannel(0)) schedule_blocks.append(block) return schedule_blocks
def _HMINUS_(node, S1, S2, T1, T2): f = node.children[0].f_expression g = node.children[1].f_expression errList1 = [node.f_expression] + S1 + [-t for t in T1] errList2 = S2 + [-t for t in T2] herr = sum([seng.Abs(Si) for Si in S1 + S2 + T1 + T2]) return _solve_(node, errList1, errList2, herr)
def _HSQRT_(node, S1, S2): f = node.children[0].f_expression S1 = [solve_remaining_error(S1)] S2 = [solve_remaining_error2(S2)] errList1 = [node.f_expression] + \ [Si/(2*node.f_expression) for Si in S1] errList2 = [Si / (2 * node.f_expression) for Si in S2] herr_denorm = (f + sum([seng.Abs(Si * pow(2, -53)) for Si in S1 + S2]))**(3.0 / 2) herr = 0.125 * sum( [seng.Abs(Si * Sj) / herr_denorm for Si in S1 + S2 for Sj in S1 + S2]) return _solve_(node, errList1, errList2, herr)
def if_eq_zero(condition, if_result, else_result): """ A short expression which can be compiled quickly. :type condition: Union[float, Symbol] :type if_result: Union[float, Symbol] :type else_result: Union[float, Symbol] :return: if_result if condition == 0 else else_result :rtype: Union[float, Symbol] """ condition = se.Abs(sign(condition)) return (1 - condition) * if_result + condition * else_result
def _HMUL_(node, S1, S2, T1, T2): f = node.children[0].f_expression g = node.children[1].f_expression errList1 = [node.f_expression] + \ [seng.expand( g * Si) for Si in S1] + \ [seng.expand( f * Tj) for Tj in T1] errList2 = [seng.expand( g * Si) for Si in S2] + \ [seng.expand( f * Tj) for Tj in T2] herr = sum( [seng.Abs(seng.expand(Si * Tj)) for Si in S1 + S2 for Tj in T1 + T2]) return _solve_(node, errList1, errList2, herr)
def _HDIV_(node, S1, S2, T1, T2): [TerrList1, TerrList2] = _HINV_(node.children[1], T1, T2) f = node.children[0].f_expression g = (1 / node.children[1].f_expression) errList1 = [node.f_expression] + \ [seng.expand(f * Ti) for Ti in TerrList1] + \ [seng.expand(g * Si) for Si in S1] errList2 = [seng.expand(f * Ti) for Ti in TerrList2] + \ [seng.expand(g * Si) for Si in S2] herr = sum( [seng.Abs(Si * Tj) for Si in S1 + S2 for Tj in TerrList1 + TerrList2]) return _solve_(node, errList1, errList2, herr)
def _partial_solve_(errList): expr = sum([seng.Abs(erri) for erri in errList]) expr_ops = seng.count_ops(expr) print("New partial:", expr_ops) size = len(errList) if size == 1 or expr_ops < SopMax: print("Unit level calls", size) #print(expr) val = max(utils.generate_signature_herror(expr)) print("VAL : ", val) return val else: print("**************", size, expr_ops) return _partial_solve_(errList[0:int(size / 2)]) + _partial_solve_( errList[int(size / 2):size])
def __init__( self, duration: Union[int, ParameterExpression], amp: Union[complex, ParameterExpression], name: Optional[str] = None, limit_amplitude: Optional[bool] = None, ): """Create new pulse instance. Args: duration: Pulse length in terms of the sampling period `dt`. amp: The amplitude of the constant square pulse. name: Display name for this pulse envelope. limit_amplitude: If ``True``, then limit the amplitude of the waveform to 1. The default is ``True`` and the amplitude is constrained to 1. """ parameters = {"amp": amp} # Prepare symbolic expressions _t, _amp, _duration = sym.symbols("t, amp, duration") # Note this is implemented using Piecewise instead of just returning amp # directly because otherwise the expression has no t dependence and sympy's # lambdify will produce a function f that for an array t returns amp # instead of amp * np.ones(t.shape). This does not work well with # ParametricPulse.get_waveform(). # # See: https://github.com/sympy/sympy/issues/5642 envelope_expr = _amp * sym.Piecewise((1, sym.And(_t >= 0, _t <= _duration)), (0, True)) valid_amp_conditions_expr = sym.Abs(_amp) <= 1.0 super().__init__( pulse_type=self.__class__.__name__, duration=duration, parameters=parameters, name=name, limit_amplitude=limit_amplitude, envelope=envelope_expr, valid_amp_conditions=valid_amp_conditions_expr, ) self.validate_parameters()
def __init__( self, duration: Union[int, ParameterExpression], amp: Union[complex, ParameterExpression], sigma: Union[float, ParameterExpression], width: Optional[Union[float, ParameterExpression]] = None, risefall_sigma_ratio: Optional[Union[float, ParameterExpression]] = None, name: Optional[str] = None, limit_amplitude: Optional[bool] = None, ): """Create new pulse instance. Args: duration: Pulse length in terms of the sampling period `dt`. amp: The amplitude of the Gaussian and of the square pulse. sigma: A measure of how wide or narrow the Gaussian risefall is; see the class docstring for more details. width: The duration of the embedded square pulse. risefall_sigma_ratio: The ratio of each risefall duration to sigma. name: Display name for this pulse envelope. limit_amplitude: If ``True``, then limit the amplitude of the waveform to 1. The default is ``True`` and the amplitude is constrained to 1. Raises: PulseError: When width and risefall_sigma_ratio are both empty or both non-empty. """ # Convert risefall_sigma_ratio into width which is defined in OpenPulse spec if width is None and risefall_sigma_ratio is None: raise PulseError( "Either the pulse width or the risefall_sigma_ratio parameter must be specified." ) if width is not None and risefall_sigma_ratio is not None: raise PulseError( "Either the pulse width or the risefall_sigma_ratio parameter can be specified" " but not both." ) if width is None and risefall_sigma_ratio is not None: width = duration - 2.0 * risefall_sigma_ratio * sigma parameters = {"amp": amp, "sigma": sigma, "width": width} # Prepare symbolic expressions _t, _duration, _amp, _sigma, _width = sym.symbols("t, duration, amp, sigma, width") _center = _duration / 2 _sq_t0 = _center - _width / 2 _sq_t1 = _center + _width / 2 _gaussian_ledge = _lifted_gaussian(_t, _sq_t0, -1, _sigma) _gaussian_redge = _lifted_gaussian(_t, _sq_t1, _duration + 1, _sigma) envelope_expr = _amp * sym.Piecewise( (_gaussian_ledge, _t <= _sq_t0), (_gaussian_redge, _t >= _sq_t1), (1, True) ) consts_expr = sym.And(_sigma > 0, _width >= 0, _duration >= _width) valid_amp_conditions_expr = sym.Abs(_amp) <= 1.0 super().__init__( pulse_type=self.__class__.__name__, duration=duration, parameters=parameters, name=name, limit_amplitude=limit_amplitude, envelope=envelope_expr, constraints=consts_expr, valid_amp_conditions=valid_amp_conditions_expr, ) self.validate_parameters()