Skip to content

_PyfarMultichannel class#837

Open
h-chmeruk wants to merge 18 commits intodevelop_base_classesfrom
BaseClasses/NumPyLike
Open

_PyfarMultichannel class#837
h-chmeruk wants to merge 18 commits intodevelop_base_classesfrom
BaseClasses/NumPyLike

Conversation

@h-chmeruk
Copy link
Copy Markdown
Contributor

@h-chmeruk h-chmeruk commented Sep 1, 2025

As proposed in the Issue #835, here is a draft implementation of the _NumPyBase class. This abstract class should define the NumPy-like functions that must then be implemented by the _Audio, Coordinates and other classes.

Edit: From the fourth commit , the class _NumPyBase is now called _PyfarMultichannel.

@h-chmeruk h-chmeruk added audio Classes pyfar.classes.audio coordinates labels Sep 1, 2025
@sikersten sikersten requested review from ahms5 and sikersten September 1, 2025 12:04
Copy link
Copy Markdown
Member

@sikersten sikersten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for getting this started!
To keep it simple, please create a new pull request for every new method and only contain existing methods in this pull request.

@h-chmeruk h-chmeruk requested a review from sikersten September 2, 2025 11:33
@h-chmeruk h-chmeruk changed the title First draft of the _NumPyLike class First draft of the _PyfarMultichannel class Sep 2, 2025
Copy link
Copy Markdown
Member

@ahms5 ahms5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks already very nice, thank you.

Comment on lines +69 to +78
@abstractmethod
def flatten(self):
"""Return a copy of the object collapsed into one channel dimension."""

pass
@abstractmethod
def transpose(self):
"""Returns a copy of the object with channel axes transposed."""

pass
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think flatten and transpose can also be implemented based on reshape, see _Audio class as an example

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works for flatten, not sure about transpose

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transpose is quite extensive for _Audio and not defined for other classes (please correct me if I'm wrong), so I would leave it as an abstract method...

Comment on lines +98 to +115
@abstractmethod
def broadcast_cdim(self, cdim):
"""
Broadcast an copy of the object wth a certain channel dimension
(`cdim`).

Parameters
----------
cdim : int
The cdim to which the object is broadcasted.

Returns
-------
object : _PyfarMultichannel
Broadcasted copy of the object.
"""

pass
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other remark, based on what broadcast_cdim does, i would wonder if this function really make sence, no such numpy method exists.
inserting new dimension can also be done via e.g. reshape

Copy link
Copy Markdown
Member

@sikersten sikersten Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree! It is essentially a convenience function to prepend dimensions. I think we can leave it if properly documented.

@abstractmethod
def cshape(self):
"""
Return channel shape.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extend doc, similar to cdim

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the docs should state here :P

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how to extend the description of cshape, as it returns the shape excluding one dimension for _Audio and Coordinates, and does not yet exist for Orientations and Filters. There is a cshape for TransmissionMatrix, as it inherits from FrequencyData, and there is also abcd_cshape, which excludes two dimensions from the cshape.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahms5
Copy link
Copy Markdown
Member

ahms5 commented Sep 2, 2025

i have just noticed, that __getitem__ and __setitem__ are not there yet, this is the implentation for slicing, see eg audio classes

@ahms5 ahms5 added this to the v0.9.0 milestone Sep 2, 2025
@ahms5 ahms5 moved this from Backlog to Drafting Phase in Weekly Planning Sep 2, 2025
@sikersten sikersten changed the base branch from develop to enhance/base_classes September 3, 2025 08:11
Comment on lines +69 to +78
@abstractmethod
def flatten(self):
"""Return a copy of the object collapsed into one channel dimension."""

pass
@abstractmethod
def transpose(self):
"""Returns a copy of the object with channel axes transposed."""

pass
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works for flatten, not sure about transpose

Comment on lines +98 to +115
@abstractmethod
def broadcast_cdim(self, cdim):
"""
Broadcast an copy of the object wth a certain channel dimension
(`cdim`).

Parameters
----------
cdim : int
The cdim to which the object is broadcasted.

Returns
-------
object : _PyfarMultichannel
Broadcasted copy of the object.
"""

pass
Copy link
Copy Markdown
Member

@sikersten sikersten Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree! It is essentially a convenience function to prepend dimensions. I think we can leave it if properly documented.

@github-project-automation github-project-automation bot moved this from Drafting Phase to Require review in Weekly Planning Sep 3, 2025
@ahms5 ahms5 moved this from Require review to Open Discussion in Weekly Planning Sep 4, 2025
@ahms5 ahms5 requested review from ahms5 and sikersten September 9, 2025 12:32
Copy link
Copy Markdown
Member

@ahms5 ahms5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to assume that _data contains the data for defuld behaviour. And we could still add tests.

def transpose(self, caxes=None):
"""Returns a copy of the object with channel axes transposed."""

pass
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Broadcasted copy of the object.
"""

pass
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the fle jsut contains one class i would rename it to _PyfarMultichannel.py

@github-project-automation github-project-automation bot moved this from Open Discussion to Require review in Weekly Planning Oct 8, 2025
@ahms5 ahms5 changed the base branch from enhance/base_classes to develop_base_classes October 10, 2025 14:35
@sikersten sikersten requested a review from artpelling October 14, 2025 07:35
@h-chmeruk h-chmeruk force-pushed the BaseClasses/NumPyLike branch from f138bd7 to ee2cfa7 Compare November 18, 2025 14:34
@h-chmeruk h-chmeruk changed the title First draft of the _PyfarMultichannel class _PyfarMultichannel class Nov 18, 2025
@h-chmeruk h-chmeruk changed the base branch from develop_base_classes to BaseClasses/PyfarBase November 18, 2025 14:35
@h-chmeruk h-chmeruk marked this pull request as ready for review November 18, 2025 14:36
@h-chmeruk h-chmeruk requested a review from ahms5 November 18, 2025 14:36
Base automatically changed from BaseClasses/PyfarBase to develop_base_classes November 28, 2025 15:23
Copy link
Copy Markdown
Member

@ahms5 ahms5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you Hanna, looks almost ready imo. I just have small comments on tests

Comment on lines +17 to +18
'_pyfar_multichannel',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'_pyfar_multichannel',

from . import filter
from . import transmission_matrix
from . import warnings
from . import _pyfar_multichannel
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from . import _pyfar_multichannel

abstract classes are not part of the official pyfar api. you can still acess them via pyfar.classes._pyfar_multichannel._PyfarMultichannel

from math import prod
from pyfar.classes._pyfar_base import _PyfarBase

class _PyfarMultichannel(_PyfarBase, ABC):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class _PyfarMultichannel(_PyfarBase, ABC):
class _PyfarMultichannel(_PyfarBase):

_PyfarBase already inherit from ABC

Broadcasted copy of the object.
"""

signal = self.copy()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here the input check is missing

@patch.multiple(_PyfarMultichannel, __abstractmethods__=set())
def test_cshape():
"""Test the cshape property."""
data = np.array([[[1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2]]])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data = np.array([[[1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2]]])
data = np.ones((2,2,2))

this would be much easier to read

@pytest.mark.parametrize('cshape', [(5, 1), (2, 3)])
def test_reshape_value_error(cshape):
"""Test whether ValueError is raised for the reshape method."""
data = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

@patch.multiple(_PyfarMultichannel, __abstractmethods__=set())
def test_flatten():
"""Test the flatten method."""
data = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

Comment on lines +100 to +101
rng = np.random.default_rng()
data = rng.random((6, 2, 5, 256))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rng = np.random.default_rng()
data = rng.random((6, 2, 5, 256))
data = np.arange(2*3*4).reshape((1, 2, 3, 4))

better not to use randomized values in tests. tests should be determistic

@pytest.mark.parametrize('taxis', [(2, 0, 1), (-1, 0, -2)])
def test_transpose_positional_arguments(taxis):
rng = np.random.default_rng()
data = rng.random((6, 2, 5, 256))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see abve

@patch.multiple(_PyfarMultichannel, __abstractmethods__=set())
def test_transpose_errors():
rng = np.random.default_rng()
data = rng.random((10, 10, 256))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

Comment on lines +122 to +123
cshape : tuple, list, np.ndarray
The channel shape to which the object is broadcasted.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure, is it a good idea to allow all these data types for cshape?

@h-chmeruk h-chmeruk requested a review from ahms5 February 4, 2026 09:54
@mberz mberz moved this from Require review to Implementation in progress in Weekly Planning Mar 18, 2026
@ahms5 ahms5 force-pushed the develop_base_classes branch from 9c5d755 to 796276a Compare April 1, 2026 07:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

audio Classes pyfar.classes.audio base_classes coordinates

Projects

Status: Implementation in progress

Development

Successfully merging this pull request may close these issues.

4 participants