pqcprep.psi_tools

Collection of functions relating to the phase function $\Psi$ to be evaluated by the QCNN.

  1r"""
  2Collection of functions relating to the phase function $\Psi$ to be evaluated by the QCNN.
  3"""
  4import numpy as np 
  5from .binary_tools import bin_to_dec, dec_to_bin
  6
  7def x_trans(x):
  8    """
  9    Transform a scalar to match the frequency scaling used for the gravitational wave binary system inspiral
 10    in [Hayes 2023](https://arxiv.org/pdf/2306.11073). 
 11
 12    Arguments:
 13    ----
 14    - **x** : *float*
 15
 16        Scalar to be transformed. 
 17
 18    Returns:
 19    ----
 20    - **x_t** : *float*
 21
 22        Transformed scalar.     
 23
 24    """
 25    n = 6 
 26    nint = n 
 27    fmin=40.
 28    fmax=168. 
 29    df = (fmax-fmin)/(2**n)
 30
 31    xmax = np.power(2,nint) - np.power(2,nint-n)
 32    x = x/xmax
 33    x = x*(fmax-fmin-df)
 34    x = x + fmin
 35    x_t =x
 36    return x_t 
 37
 38
 39def x_trans_arr(n):
 40    """
 41
 42    Generate an array of frequency values according to the frequency scaling used for the gravitational wave binary system inspiral
 43    in [Hayes 2023](https://arxiv.org/pdf/2306.11073). 
 44
 45    Arguments:
 46    ----
 47    - **n** : *int*
 48
 49        Controls array size: length of the array is `2**n`. 
 50
 51    Returns:
 52    ----
 53    - **x_arr** : *array_like*
 54
 55        Array of values.    
 56
 57    """
 58    x_min = 40
 59    x_max = 168 
 60    dx = (x_max-x_min)/(2**n) 
 61    x_arr = np.arange(x_min, x_max, dx) 
 62
 63    return x_arr 
 64
 65def psi_H(x):
 66    r"""
 67    The phase function $\Psi$ for the gravitational wave binary system inspiral
 68    in [Hayes 2023](https://arxiv.org/pdf/2306.11073). 
 69
 70    Arguments:
 71    ----
 72    - **x** : *float*
 73
 74        $x$. 
 75
 76    Returns:
 77    ----
 78    - **out** : *float*
 79
 80        $\Psi(x)$.     
 81
 82    """
 83
 84    # gravitational wave features 
 85    n = 6 
 86    fmin=40.
 87    fmax=168. 
 88    m1=(4.926e-6)*35
 89    m2=(4.926e-6)*30. 
 90    beta=0.
 91    sig=0.
 92    Tfrac = 100.
 93    df = (fmax-fmin)/(2**n)
 94    T = 1./df
 95    tc = T + (T/Tfrac)
 96    DT = tc%T
 97    Mt = m1 + m2
 98    nu = (m1*m2)/Mt
 99    eta = nu/Mt
100    Mc = Mt*eta**(3./5)
101
102    # transform x to frequency scale 
103    x = x_trans(x)
104
105    # apply function
106    out = (((3./128))*((np.pi*Mc*x)**(-5./3))*( 1.+ (20./9)*((743./336)+(11./4)*eta)*(np.pi*Mt*x)**(2./3) -4.*(4.*np.pi - beta)*(np.pi*Mt*x) + 10.*((3058673./1016064) + (eta*5429./1008) + (617*(eta**2)/144) - sig)*(np.pi*Mt*x)**(4./3)) + 2.*np.pi*x*DT)/(2.*np.pi) 
107
108    return out 
109
110def psi(x, mode="psi"):
111    r"""
112    A wrapper for different phase functions. 
113
114    Inputs are scaled via `x_trans()` in all cases. 
115
116    Arguments:
117    ---
118    - **x** : *float* 
119
120        $x$.  
121
122    - **mode** : *str*
123
124        Options are `'psi'` (corresponding to `psi_H()`), `'linear'` (corresponding to `psi_linear()`), `'quadratic'` (corresponding to `psi_quadratic()`),
125        `'sin'` (corresponding to `psi_sine()`). Default is `'psi'`. 
126
127    Returns:
128    ----
129    - **out** : *float* 
130
131        $\Psi(x)$ for the $\Psi$ selected via `mode`. 
132        
133
134    """
135    if mode=="sine":
136        out = psi_sine(x)
137    elif mode=="quadratic":    
138        out = psi_quadratic(x)
139    elif mode=="linear":    
140        out = psi_linear(x)
141    elif mode=="psi":     
142        out = psi_H(x)
143    else:
144        raise ValueError('Unrecognised phase function mode. Options are "psi", "linear", "quadratic", "sine".')    
145    
146    return out
147
148def psi_linear(x):
149    r"""
150    A simple linear phase function $\Psi$. 
151
152    Arguments:
153    ----
154    - **x** : *float*
155
156        $x$. 
157
158    Returns:
159    ----
160    - **out** : *float*
161
162        $\Psi(x) \sim x$.     
163
164    """    
165    x = x_trans(x)
166    out= 0.5 + 0.01*x
167
168    return out 
169
170def psi_quadratic(x):
171    r"""
172    A simple quadratic phase function $\Psi$. 
173
174    Arguments:
175    ----
176    - **x** : *float*
177
178        $x$. 
179
180    Returns:
181    ----
182    - **out** : *float*
183
184        $\Psi(x) \sim x^2$.     
185
186    """    
187    x = x_trans(x)
188    out= 0.0001* x**2
189
190    return out 
191
192def psi_sine(x):
193    r"""
194    A simple sinusoidal phase function $\Psi$. 
195
196    Arguments:
197    ----
198    - **x** : *float*
199
200        $x$. 
201
202    Returns:
203    ----
204    - **out** : *float*
205
206        $\Psi(x) \sim \sin x$.     
207
208    """     
209    x = x_trans(x)
210    out =  np.pi /2 *(1+ np.sin(x /4 )) 
211
212    return out 
213
214def get_phase_target(m, psi_mode, phase_reduce=True, mint=0):
215    r"""
216    
217    Generate an array of phase function values taking into account rounding due to the limited 
218    size of the target register. 
219
220    The number of values in the array is determined for the same frequency scaling as in `x_trans()`. 
221
222    Arguments:
223    ---
224    - **m** : *int* 
225
226        Number of qubits in the target register. 
227
228    - **psi_mode** : *str* 
229
230        String specifying the phase function. Must be one of the options for the `mode` argument of `psi()`.    
231
232    - **phase_reduce** : *boolean*
233
234        If True, phase function is reduced to the interval $[0, 2 \pi]$ before rounding. Default is True.     
235
236    - **mint** : *int* 
237
238        Number of integer qubits. Default is 0.     
239
240    Returns:
241    ---
242    - **phase_rounded** : *array_like*
243
244        Array containing phase function values rounded to the precision 
245        afforded by the target register size. 
246
247
248    """
249
250    # define x array 
251    n = 6
252    x_min = 40
253    x_max = 168 
254    dx = (x_max-x_min)/(2**n) 
255    x_arr = np.arange(x_min, x_max, dx) 
256
257    # calculate target output for phase 
258    phase_target = psi(np.linspace(0, 2**n, len(x_arr)),mode=psi_mode)
259
260    # calculate target for phase taking into account rounding 
261    if phase_reduce:
262        phase_reduced = np.modf(phase_target / (2* np.pi))[0] 
263    phase_reduced_bin = [dec_to_bin(i,m, "unsigned mag", mint) for i in phase_reduced]
264    phase_reduced_dec =  np.array([bin_to_dec(i,"unsigned mag", mint) for i in phase_reduced_bin])
265    if phase_reduce:
266        phase_rounded = 2 * np.pi * phase_reduced_dec
267
268    return phase_rounded
269
270
271def A(x, mode="x76"):
272    r"""
273    A wrapper for different amplitude functions. 
274
275    Arguments:
276    ---
277    - **x** : *float* 
278
279        $x$.  
280
281    - **mode** : *str*
282
283        Options are `'x76'` (corresponding to $A(x) \sim x^{-7/6}$), `'uniform'` (corresponding to $A(x) \sim 1$), and `'linear'` (corresponding to $A(x) \sim x$).
284        Default is `'x76'`. 
285
286    Returns:
287    ----
288    - **out** : *float* 
289
290        $A(x)$ for the $A$ selected via `mode`. 
291        
292
293    """
294    if mode=="x76":
295        out = x**(-7/6)
296    elif mode=="uniform":    
297        out = 1
298    elif mode=="linear":
299        out= x   
300    else:
301        raise ValueError('Unrecognised phase function mode. Options are "x76", "uniform", "linear".')     
302
303    return out
def x_trans(x):
 8def x_trans(x):
 9    """
10    Transform a scalar to match the frequency scaling used for the gravitational wave binary system inspiral
11    in [Hayes 2023](https://arxiv.org/pdf/2306.11073). 
12
13    Arguments:
14    ----
15    - **x** : *float*
16
17        Scalar to be transformed. 
18
19    Returns:
20    ----
21    - **x_t** : *float*
22
23        Transformed scalar.     
24
25    """
26    n = 6 
27    nint = n 
28    fmin=40.
29    fmax=168. 
30    df = (fmax-fmin)/(2**n)
31
32    xmax = np.power(2,nint) - np.power(2,nint-n)
33    x = x/xmax
34    x = x*(fmax-fmin-df)
35    x = x + fmin
36    x_t =x
37    return x_t 

Transform a scalar to match the frequency scaling used for the gravitational wave binary system inspiral in Hayes 2023.

Arguments:

  • x : float

    Scalar to be transformed.

Returns:

  • x_t : float

    Transformed scalar.

def x_trans_arr(n):
40def x_trans_arr(n):
41    """
42
43    Generate an array of frequency values according to the frequency scaling used for the gravitational wave binary system inspiral
44    in [Hayes 2023](https://arxiv.org/pdf/2306.11073). 
45
46    Arguments:
47    ----
48    - **n** : *int*
49
50        Controls array size: length of the array is `2**n`. 
51
52    Returns:
53    ----
54    - **x_arr** : *array_like*
55
56        Array of values.    
57
58    """
59    x_min = 40
60    x_max = 168 
61    dx = (x_max-x_min)/(2**n) 
62    x_arr = np.arange(x_min, x_max, dx) 
63
64    return x_arr 

Generate an array of frequency values according to the frequency scaling used for the gravitational wave binary system inspiral in Hayes 2023.

Arguments:

  • n : int

    Controls array size: length of the array is 2**n.

Returns:

  • x_arr : array_like

    Array of values.

def psi_H(x):
 66def psi_H(x):
 67    r"""
 68    The phase function $\Psi$ for the gravitational wave binary system inspiral
 69    in [Hayes 2023](https://arxiv.org/pdf/2306.11073). 
 70
 71    Arguments:
 72    ----
 73    - **x** : *float*
 74
 75        $x$. 
 76
 77    Returns:
 78    ----
 79    - **out** : *float*
 80
 81        $\Psi(x)$.     
 82
 83    """
 84
 85    # gravitational wave features 
 86    n = 6 
 87    fmin=40.
 88    fmax=168. 
 89    m1=(4.926e-6)*35
 90    m2=(4.926e-6)*30. 
 91    beta=0.
 92    sig=0.
 93    Tfrac = 100.
 94    df = (fmax-fmin)/(2**n)
 95    T = 1./df
 96    tc = T + (T/Tfrac)
 97    DT = tc%T
 98    Mt = m1 + m2
 99    nu = (m1*m2)/Mt
100    eta = nu/Mt
101    Mc = Mt*eta**(3./5)
102
103    # transform x to frequency scale 
104    x = x_trans(x)
105
106    # apply function
107    out = (((3./128))*((np.pi*Mc*x)**(-5./3))*( 1.+ (20./9)*((743./336)+(11./4)*eta)*(np.pi*Mt*x)**(2./3) -4.*(4.*np.pi - beta)*(np.pi*Mt*x) + 10.*((3058673./1016064) + (eta*5429./1008) + (617*(eta**2)/144) - sig)*(np.pi*Mt*x)**(4./3)) + 2.*np.pi*x*DT)/(2.*np.pi) 
108
109    return out 

The phase function $\Psi$ for the gravitational wave binary system inspiral in Hayes 2023.

Arguments:

  • x : float

    $x$.

Returns:

  • out : float

    $\Psi(x)$.

def psi(x, mode='psi'):
111def psi(x, mode="psi"):
112    r"""
113    A wrapper for different phase functions. 
114
115    Inputs are scaled via `x_trans()` in all cases. 
116
117    Arguments:
118    ---
119    - **x** : *float* 
120
121        $x$.  
122
123    - **mode** : *str*
124
125        Options are `'psi'` (corresponding to `psi_H()`), `'linear'` (corresponding to `psi_linear()`), `'quadratic'` (corresponding to `psi_quadratic()`),
126        `'sin'` (corresponding to `psi_sine()`). Default is `'psi'`. 
127
128    Returns:
129    ----
130    - **out** : *float* 
131
132        $\Psi(x)$ for the $\Psi$ selected via `mode`. 
133        
134
135    """
136    if mode=="sine":
137        out = psi_sine(x)
138    elif mode=="quadratic":    
139        out = psi_quadratic(x)
140    elif mode=="linear":    
141        out = psi_linear(x)
142    elif mode=="psi":     
143        out = psi_H(x)
144    else:
145        raise ValueError('Unrecognised phase function mode. Options are "psi", "linear", "quadratic", "sine".')    
146    
147    return out

A wrapper for different phase functions.

Inputs are scaled via x_trans() in all cases.

Arguments:

Returns:

  • out : float

    $\Psi(x)$ for the $\Psi$ selected via mode.

def psi_linear(x):
149def psi_linear(x):
150    r"""
151    A simple linear phase function $\Psi$. 
152
153    Arguments:
154    ----
155    - **x** : *float*
156
157        $x$. 
158
159    Returns:
160    ----
161    - **out** : *float*
162
163        $\Psi(x) \sim x$.     
164
165    """    
166    x = x_trans(x)
167    out= 0.5 + 0.01*x
168
169    return out 

A simple linear phase function $\Psi$.

Arguments:

  • x : float

    $x$.

Returns:

  • out : float

    $\Psi(x) \sim x$.

def psi_quadratic(x):
171def psi_quadratic(x):
172    r"""
173    A simple quadratic phase function $\Psi$. 
174
175    Arguments:
176    ----
177    - **x** : *float*
178
179        $x$. 
180
181    Returns:
182    ----
183    - **out** : *float*
184
185        $\Psi(x) \sim x^2$.     
186
187    """    
188    x = x_trans(x)
189    out= 0.0001* x**2
190
191    return out 

A simple quadratic phase function $\Psi$.

Arguments:

  • x : float

    $x$.

Returns:

  • out : float

    $\Psi(x) \sim x^2$.

def psi_sine(x):
193def psi_sine(x):
194    r"""
195    A simple sinusoidal phase function $\Psi$. 
196
197    Arguments:
198    ----
199    - **x** : *float*
200
201        $x$. 
202
203    Returns:
204    ----
205    - **out** : *float*
206
207        $\Psi(x) \sim \sin x$.     
208
209    """     
210    x = x_trans(x)
211    out =  np.pi /2 *(1+ np.sin(x /4 )) 
212
213    return out 

A simple sinusoidal phase function $\Psi$.

Arguments:

  • x : float

    $x$.

Returns:

  • out : float

    $\Psi(x) \sim \sin x$.

def get_phase_target(m, psi_mode, phase_reduce=True, mint=0):
215def get_phase_target(m, psi_mode, phase_reduce=True, mint=0):
216    r"""
217    
218    Generate an array of phase function values taking into account rounding due to the limited 
219    size of the target register. 
220
221    The number of values in the array is determined for the same frequency scaling as in `x_trans()`. 
222
223    Arguments:
224    ---
225    - **m** : *int* 
226
227        Number of qubits in the target register. 
228
229    - **psi_mode** : *str* 
230
231        String specifying the phase function. Must be one of the options for the `mode` argument of `psi()`.    
232
233    - **phase_reduce** : *boolean*
234
235        If True, phase function is reduced to the interval $[0, 2 \pi]$ before rounding. Default is True.     
236
237    - **mint** : *int* 
238
239        Number of integer qubits. Default is 0.     
240
241    Returns:
242    ---
243    - **phase_rounded** : *array_like*
244
245        Array containing phase function values rounded to the precision 
246        afforded by the target register size. 
247
248
249    """
250
251    # define x array 
252    n = 6
253    x_min = 40
254    x_max = 168 
255    dx = (x_max-x_min)/(2**n) 
256    x_arr = np.arange(x_min, x_max, dx) 
257
258    # calculate target output for phase 
259    phase_target = psi(np.linspace(0, 2**n, len(x_arr)),mode=psi_mode)
260
261    # calculate target for phase taking into account rounding 
262    if phase_reduce:
263        phase_reduced = np.modf(phase_target / (2* np.pi))[0] 
264    phase_reduced_bin = [dec_to_bin(i,m, "unsigned mag", mint) for i in phase_reduced]
265    phase_reduced_dec =  np.array([bin_to_dec(i,"unsigned mag", mint) for i in phase_reduced_bin])
266    if phase_reduce:
267        phase_rounded = 2 * np.pi * phase_reduced_dec
268
269    return phase_rounded

Generate an array of phase function values taking into account rounding due to the limited size of the target register.

The number of values in the array is determined for the same frequency scaling as in x_trans().

Arguments:

  • m : int

    Number of qubits in the target register.

  • psi_mode : str

    String specifying the phase function. Must be one of the options for the mode argument of psi().

  • phase_reduce : boolean

    If True, phase function is reduced to the interval $[0, 2 \pi]$ before rounding. Default is True.

  • mint : int

    Number of integer qubits. Default is 0.

Returns:

  • phase_rounded : array_like

    Array containing phase function values rounded to the precision afforded by the target register size.

def A(x, mode='x76'):
272def A(x, mode="x76"):
273    r"""
274    A wrapper for different amplitude functions. 
275
276    Arguments:
277    ---
278    - **x** : *float* 
279
280        $x$.  
281
282    - **mode** : *str*
283
284        Options are `'x76'` (corresponding to $A(x) \sim x^{-7/6}$), `'uniform'` (corresponding to $A(x) \sim 1$), and `'linear'` (corresponding to $A(x) \sim x$).
285        Default is `'x76'`. 
286
287    Returns:
288    ----
289    - **out** : *float* 
290
291        $A(x)$ for the $A$ selected via `mode`. 
292        
293
294    """
295    if mode=="x76":
296        out = x**(-7/6)
297    elif mode=="uniform":    
298        out = 1
299    elif mode=="linear":
300        out= x   
301    else:
302        raise ValueError('Unrecognised phase function mode. Options are "x76", "uniform", "linear".')     
303
304    return out

A wrapper for different amplitude functions.

Arguments:

  • x : float

    $x$.

  • mode : str

    Options are 'x76' (corresponding to $A(x) \sim x^{-7/6}$), 'uniform' (corresponding to $A(x) \sim 1$), and 'linear' (corresponding to $A(x) \sim x$). Default is 'x76'.

Returns:

  • out : float

    $A(x)$ for the $A$ selected via mode.