Skip to content

Commit

Permalink
Fix complex dtype detection (#67) and index in equal (#66)
Browse files Browse the repository at this point in the history
change _qfmt and _fxpfmt to methods
  • Loading branch information
francof2a committed Nov 10, 2022
1 parent 89dc03a commit 0dac8b8
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 23 deletions.
55 changes: 32 additions & 23 deletions fxpmath/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,14 @@ def get_dtype(self, notation=None):
self._update_dtype(notation) # update dtype
return self._dtype

_qfmt = re.compile(r'(s|u|q|uq|qu)(\d+)(\.\d+)?')
_fxpfmt = re.compile(r'fxp-(s|u)(\d+)/(\d+)(-complex)?')
def _qfmt(self):
return re.compile(r'(s|u|q|uq|qu)(\d+)(\.\d+)?')
def _fxpfmt(self):
return re.compile(r'fxp-(s|u)(\d+)/(\d+)(-complex)?')

def _parseformatstr(self, fmt):
fmt = fmt.casefold()
mo = self._qfmt.match(fmt)
mo = self._qfmt().match(fmt)
if mo:
# Q/S notation counts the sign bit as an integer bit, such that
# the total number of bits is always int+frac
Expand All @@ -333,7 +335,7 @@ def _parseformatstr(self, fmt):
n_word = n_frac + n_int
complex_dtype = False
else:
mo = self._fxpfmt.match(fmt)
mo = self._fxpfmt().match(fmt)
if mo:
signed = mo.group(1) == 's'
n_word = int(mo.group(2))
Expand Down Expand Up @@ -570,12 +572,12 @@ def reshape(self, shape, order='C'):
If an integer, then the result will be a 1-D array of that length.
One shape dimension can be -1. In this case, the value is inferred from the length of the array and remaining dimensions.
order : {‘C’, ‘F’, ‘A’}, optional
order : {'C', 'F', 'A'}, optional
Read the elements of a using this index order, and place the elements into the reshaped array using this index order.
‘C’ means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest.
‘F’ means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest.
Note that the ‘C’ and ‘F’ options take no account of the memory layout of the underlying array, and only refer to the order of indexing.
‘A’ means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise.
'C' means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest.
'F' means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest.
Note that the 'C' and 'F' options take no account of the memory layout of the underlying array, and only refer to the order of indexing.
'A' means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise.
Returns
---
Expand All @@ -594,12 +596,12 @@ def flatten(self, order='C'):
Parameters
---
order{‘C’, ‘F’, ‘A’, ‘K’}, optional
‘C’ means to flatten in row-major (C-style) order.
‘F’ means to flatten in column-major (Fortran- style) order.
‘A’ means to flatten in column-major order if a is Fortran contiguous in memory, row-major order otherwise.
‘K’ means to flatten a in the order the elements occur in memory.
The default is ‘C’.
order{'C', 'F', 'A', 'K'}, optional
'C' means to flatten in row-major (C-style) order.
'F' means to flatten in column-major (Fortran- style) order.
'A' means to flatten in column-major order if a is Fortran contiguous in memory, row-major order otherwise.
'K' means to flatten a in the order the elements occur in memory.
The default is 'C'.
Returns
---
Expand Down Expand Up @@ -750,7 +752,9 @@ def _update_dtype(self, notation=None):
self._dtype = 'fxp-{sign}{nword}/{nfrac}{comp}'.format(sign='s' if self.signed else 'u',
nword=self.n_word,
nfrac=self.n_frac,
comp='-complex' if (self.val.dtype == complex or self.vdtype == complex) else '')
comp='-complex' if (isinstance(self.val, complex) or \
self.val.dtype == complex or \
self.vdtype == complex) else '')
else:
self._dtype = 'fxp-{sign}{nword}/{nfrac}'.format(sign='s' if self.signed else 'u',
nword=self.n_word,
Expand Down Expand Up @@ -1014,7 +1018,7 @@ def uraw(self):
"""
return np.where(self.val < 0, (1 << self.n_word) + self.val, self.val)

def equal(self, x):
def equal(self, x, index=None):
"""
Sets the value of the Fxp using the value of other Fxp object.
If `x` is not a Fxp, this method set the value just like `set_val` method.
Expand All @@ -1025,6 +1029,9 @@ def equal(self, x):
x : Fxp object, None, int, float, complex, list of numbers, numpy array, str (bin, hex, dec)
Value(s) to be stored in fractional fixed-point (base 2) format.
index : int, optional, default=None
Index of the element to be overwritten in list or array of values by `val` input.
Returns
---
Expand All @@ -1033,10 +1040,15 @@ def equal(self, x):
"""

if isinstance(x, Fxp):
new_val_raw = x.val * 2**(self.n_frac - x.n_frac)
self.set_val(new_val_raw, raw=True)
if index is None:
raw_val = x.val[index]
else:
raw_val = x.val

new_val_raw = raw_val * 2**(self.n_frac - x.n_frac)
self.set_val(new_val_raw, raw=True, index=index)
else:
self.set_val(x)
self.set_val(x, index=index)
return self

# behaviors
Expand Down Expand Up @@ -1857,9 +1869,6 @@ def item(self, *args):
items = args[0]
return self.astype(item=items)

# ToDo:
# nonzero

def clip(self, a_min=None, a_max=None, **kwargs):
from .functions import clip

Expand Down
52 changes: 52 additions & 0 deletions tests/test_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,55 @@ def test_issue_62_v0_4_7():
y[0][0] = y[0][0] + 1.0

assert y[0][0]() == 0.0

def test_issue_66_v0_4_8():
x = Fxp(np.array([1.25, 0.5]), dtype='S8.4')
y = Fxp(np.array([2.25, 1.5]), dtype='S16.6')
# x[0].equal(y[0]) # it does NOT work
# x[0] = y[0] # it works
x.equal(y[0], index=0) # it works

assert x[0]() == y[0]()

def test_issue_67_v0_4_8():
input_size = Fxp(None, dtype='fxp-s32/23')
f = [0,10+7j,20-0.65j,30]
f = Fxp(f, like = input_size)

def FFT(f):
N = len(f)
if N <= 1:
return f

# division: decompose N point FFT into N/2 point FFT
even= FFT(f[0::2])
odd = FFT(f[1::2])

# store combination of results
temp = np.zeros(N, dtype=complex)
# temp = Fxp(temp, dtype='fxp-s65/23')
temp = Fxp(temp, dtype='fxp-s65/46')

for u in range(N//2):
W = Fxp(np.exp(-2j*np.pi*u/N), like=input_size)
temp[u] = even[u] + W* odd[u]
temp[u+N//2] = even[u] - W*odd[u]

return temp

# testing the function to see if it matches the manual computation
F_fft = FFT(f)

def test_issue_73_v0_4_8():
# single unsigned value does work
a = Fxp(10, False, 14, 3)
b = Fxp(15, False, 14, 3)
c = a - b
assert c() == 0.0 # 0.0 --> correct

# unsigned list does not work
d = Fxp([10, 21], False, 14, 3)
e = Fxp([15, 15], False, 14, 3)
f = d - e
assert f[0]() == 0.0 # [4095.875 6.0] --> 4095.875 is the upper limit
assert f[1]() == 6.0

0 comments on commit 0dac8b8

Please sign in to comment.