GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||
GeezerVison is showing github.com — Move _tf_close_coeff back to testing realm and make better use of assertion messages by bnavigator · Pull Request #1109 · python-control/python-control Conversation
Contributor
The OS/BLAS testing matrix started to fail with some macOS tests and the assertion messages make them hard to inspect: https://github.com/python-control/python-control/actions/runs/13087050463/job/36519541162#step:9:298 FAILED control/tests/statesp_test.py::TestStateSpace::test_pow - assert False + where False = _tf_close_coeff(TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2), TransferFunction(\n[[array([1.]), array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2)) + where TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2) = minreal() + where minreal = TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2).minreal + where TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2) = ss2tf(StateSpace(\narray([], shape=(0, 0), dtype=float64),\narray([], shape=(0, 2), dtype=float64),\narray([], shape=(2, 0), dtype=float64),\narray([[1., 0.],\n [0., 1.]]),\nstates=0, outputs=2, inputs=2)) + and TransferFunction(\n[[array([1.]), array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2) = minreal() + where minreal = TransferFunction(\n[[array([ 1., 3., -9., -41.]), \n array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n ...., 3., -9., -41.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1., 0., 0., 0.])]],\noutputs=2, inputs=2).minreal + where TransferFunction(\n[[array([ 1., 3., -9., -41.]), \n array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n ...., 3., -9., -41.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1., 0., 0., 0.])]],\noutputs=2, inputs=2) = ss2tf(StateSpace(\narray([[ 4.86563613, -0.22114886, -14.38268526],\n [ 3.86388385, -1.64824725, -16.2652334 ],\n ... [0.00000000e+00, 2.59786829e-16, 3.85014366e-15]]),\narray([[1., 0.],\n [0., 1.]]),\nstates=3, outputs=2, inputs=2)) Let's try to make this easier by using numpy's and pytest's assertion rewriting.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
|
There was an error while loading. Please reload this page.
|
coverage: 94.701% (+0.04%) from 94.659% |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Before: ___________________________ TestStateSpace.test_pow ____________________________ self = <control.tests.statesp_test.TestStateSpace object at 0x108ea1580> sys222 = StateSpace( array([[ 4., 1.], [ 2., -3.]]), array([[ 5., 2.], [-3., -3.]]), array([[ 2., -4.], [ 0., 1.]]), array([[ 3., 2.], [ 1., -1.]]), states=2, outputs=2, inputs=2) sys322 = StateSpace( array([[-3., 4., 2.], [-1., -3., 0.], [ 2., 5., 3.]]), array([[ 1., 4.], [-3., ..., -3.], [ 1., 4., 3.]]), array([[-2., 4.], [ 0., 1.]]), name='sys322', states=3, outputs=2, inputs=2) @slycotonly def test_pow(self, sys222, sys322): """Test state space powers.""" for sys in [sys222, sys322]: # Power of 0 result = sys**0 expected = StateSpace([], [], [], np.eye(2), dt=0) np.testing.assert_allclose(expected.A, result.A) np.testing.assert_allclose(expected.B, result.B) np.testing.assert_allclose(expected.C, result.C) np.testing.assert_allclose(expected.D, result.D) # Power of 1 result = sys**1 expected = sys np.testing.assert_allclose(expected.A, result.A) np.testing.assert_allclose(expected.B, result.B) np.testing.assert_allclose(expected.C, result.C) np.testing.assert_allclose(expected.D, result.D) # Power of -1 (inverse of biproper system) # Testing transfer function representations to avoid the # non-uniqueness of the state-space representation. Once MIMO # canonical forms are supported, can check canonical state-space # matrices instead. result = (sys * sys**-1).minreal() expected = StateSpace([], [], [], np.eye(2), dt=0) assert _tf_close_coeff( ss2tf(expected).minreal(), ss2tf(result).minreal(), ) result = (sys**-1 * sys).minreal() expected = StateSpace([], [], [], np.eye(2), dt=0) > assert _tf_close_coeff( ss2tf(expected).minreal(), ss2tf(result).minreal(), ) E assert False E + where False = _tf_close_coeff(TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2), TransferFunction(\n[[array([1.]), array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2)) E + where TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2) = minreal() E + where minreal = TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2).minreal E + where TransferFunction(\n[[array([1.]), array([0.])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([1.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2) = ss2tf(StateSpace(\narray([], shape=(0, 0), dtype=float64),\narray([], shape=(0, 2), dtype=float64),\narray([], shape=(2, 0), dtype=float64),\narray([[1., 0.],\n [0., 1.]]),\nstates=0, outputs=2, inputs=2)) E + and TransferFunction(\n[[array([1.]), array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n [array([0.]), array([1.])]],\n[[array([1.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1.])]],\noutputs=2, inputs=2) = minreal() E + where minreal = TransferFunction(\n[[array([ 1., 3., -9., -41.]), \n array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n ...., 3., -9., -41.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1., 0., 0., 0.])]],\noutputs=2, inputs=2).minreal E + where TransferFunction(\n[[array([ 1., 3., -9., -41.]), \n array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])],\n ...., 3., -9., -41.]), array([ 1., 3., -9., -41.])],\n [array([1.]), array([1., 0., 0., 0.])]],\noutputs=2, inputs=2) = ss2tf(StateSpace(\narray([[ 4.86563613, -0.22114886, -14.38268526],\n [ 3.86388385, -1.64824725, -16.2652334 ],\n ... [0.00000000e+00, 2.59786829e-16, 3.85014366e-15]]),\narray([[1., 0.],\n [0., 1.]]),\nstates=3, outputs=2, inputs=2)) control/tests/statesp_test.py:596: AssertionError After: ________________ TestStateSpace.test_pow_inv[sys322-inv*sys] __________________ self = <control.tests.statesp_test.TestStateSpace object at 0x10b398260> request = <FixtureRequest for <Function test_pow_inv[sys322-inv*sys]>> sysname = 'sys322', order = 'inv*sys' @slycotonly @pytest.mark.parametrize("order", ["inv*sys", "sys*inv"]) @pytest.mark.parametrize("sysname", ["sys222", "sys322"]) def test_pow_inv(self, request, sysname, order): """Power of -1 (inverse of biproper system). Testing transfer function representations to avoid the non-uniqueness of the state-space representation. Once MIMO canonical forms are supported, can check canonical state-space matrices instead. """ sys = request.getfixturevalue(sysname) if order == "inv*sys": result = (sys**-1 * sys).minreal() else: result = (sys * sys**-1).minreal() expected = StateSpace([], [], [], np.eye(2), dt=0) > assert_tf_close_coeff( ss2tf(expected).minreal(), ss2tf(result).minreal()) control/tests/statesp_test.py:601: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tf_a = TransferFunction( [[array([1.]), array([0.])], [array([0.]), array([1.])]], [[array([1.]), array([1.])], [array([1.]), array([1.])]], outputs=2, inputs=2) tf_b = TransferFunction( [[array([1.]), array([-2.76395297e-15, -1.35541257e-13, 9.01576541e-13])], [array([0.]), array([1.])]], [[array([1.]), array([ 1., 3., -9., -41.])], [array([1.]), array([1.])]], outputs=2, inputs=2) rtol = 1e-05, atol = 1e-08 def assert_tf_close_coeff(tf_a, tf_b, rtol=1e-5, atol=1e-8): """Check if two transfer functions have close coefficients. Parameters ---------- tf_a : TransferFunction First transfer function. tf_b : TransferFunction Second transfer function. rtol : float Relative tolerance for ``np.testing.assert_allclose``. atol : float Absolute tolerance for ``np.testing.assert_allclose``. Raises ------ AssertionError """ # Check number of outputs and inputs assert tf_a.noutputs == tf_b.noutputs assert tf_a.ninputs == tf_b.ninputs # Check timestep assert tf_a.dt == tf_b.dt # Check coefficient arrays for i in range(tf_a.noutputs): for j in range(tf_a.ninputs): > np.testing.assert_allclose( tf_a.num[i][j], tf_b.num[i][j], rtol=rtol, atol=atol) E AssertionError: E Not equal to tolerance rtol=1e-05, atol=1e-08 E E (shapes (1,), (3,) mismatch) E ACTUAL: array([0.]) E DESIRED: array([-2.763953e-15, -1.355413e-13, 9.015765e-13]) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
24af4fd to
ac5bdd9
Compare
|
In these tests, I'm trying to test I'm starting to think that this test might just be flawed and should be removed entirely. Though I'm not sure what the best way to test Thanks for making Sorry about the flaky unit tests 🙃 |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I came across this same issue at some point. The issues is that there are some very small numbers that pop up in the sys * sys**-1 on MacOS with OpenBLAS. If I remember correctly, this caused the numerator polynomial to have coefficients on order 1e-12. I thought I fixed this someplace and the documentation PR (#1094) doesn't have this problem. But I can't find the fix I used in that PR. I'll keep looking. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
13a262d to
2359299
Compare
|
How about: 2359299? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall. Some minor comments about import style, but since this is test code it doesn't matter so much.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| from control import (StateSpace, TransferFunction, defaults, evalfr, isctime, | ||
| isdtime, reset_defaults, rss, sample_system, set_defaults, | ||
| ss, ss2tf, tf, tf2ss, zpk) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Nonstandard. Use hanging indent.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| from control.statesp import (StateSpace, _convert_to_statespace, _rss_generate, | ||
| _statesp_defaults, drss, linfnorm, rss, ss, tf2ss) | ||
| from control.tests.conftest import (assert_tf_close_coeff, editsdefaults, | ||
| slycotonly) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
The default style for imports is to use "hanging indent" (isort -m2).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.