8000 add (skipped) function for desired binary operator conversions · python-control/python-control@172d318 · GitHub
[go: up one dir, main page]

Skip to content

Commit 172d318

Browse files
committed
add (skipped) function for desired binary operator conversions
1 parent d788eb5 commit 172d318

File tree

1 file changed

+70
-2
lines changed

1 file changed

+70
-2
lines changed

control/tests/type_conversion_test.py

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def sys_dict():
1515
sdict = {}
1616
sdict['ss'] = ct.ss([[-1]], [[1]], [[1]], [[0]])
1717
sdict['tf'] = ct.tf([1],[0.5, 1])
18+
sdict['tfx'] = ct.tf([1, 1],[1]) # non-proper transfer function
1819
sdict['frd'] = ct.frd([10+0j, 9 + 1j, 8 + 2j], [1,2,3])
1920
sdict['lio'] = ct.LinearIOSystem(ct.ss([[-1]], [[5]], [[5]], [[0]]))
2021
sdict['ios'] = ct.NonlinearIOSystem(
@@ -29,7 +30,7 @@ def sys_dict():
2930
'ios': ct.InterconnectedSystem, 'arr': np.ndarray, 'flt': float}
3031

3132
#
32-
# Table of expected conversions
33+
# Current table of expected conversions
3334
#
3435
# This table describes all of the conversions that are supposed to
3536
# happen for various system combinations. This is written out this way
@@ -50,6 +51,10 @@ def sys_dict():
5051
# Note 2: eventually the operator entry for this table can be pulled out and
5152
# tested as a separate parameterized variable (since all operators should
5253
# return consistent values).
54+
#
55+
# Note 3: this table documents the current state, but not actually the desired
56+
# state. See bottom of the file for the (eventual) desired behavior.
57+
#
5358

5459
rtype_list = ['ss', 'tf', 'frd', 'lio', 'ios', 'arr', 'flt']
5560
conversion_table = [
@@ -97,7 +102,7 @@ def sys_dict():
97102
test_matrix.append([opname, ltype, rtype, expected])
98103

99104
@pytest.mark.parametrize("opname, ltype, rtype, expected", test_matrix)
100-
def test_xferfcn_ndarray_precedence(opname, ltype, rtype, expected, sys_dict):
105+
def test_operator_type_conversion(opname, ltype, rtype, expected, sys_dict):
101106
op = getattr(operator, opname)
102107
leftsys = sys_dict[ltype]
103108
rightsys = sys_dict[rtype]
@@ -117,3 +122,66 @@ def test_xferfcn_ndarray_precedence(opname, ltype, rtype, expected, sys_dict):
117122

118123
# Print out what we are testing in case something goes wrong
119124
assert isinstance(result, type_dict[expected])
125+
126+
#
127+
# Updated table that describes desired outputs for all operators
128+
#
129+
# General rules (subject to change)
130+
#
131+
# * For LTI/LTI, keep the type of the left operand whenever possible. This
132+
# prioritizes the first operand, but we need to watch out for non-proper
133+
# transfer functions (in which case TransferFunction should be returned)
134+
#
135+
# * For FRD/LTI, convert LTI to FRD by evaluating the LTI transfer function
136+
# at the FRD frequencies (can't got the other way since we can't convert
137+
# an FRD object to state space/transfer function).
138+
#
139+
# * For IOS/LTI, convert to IOS. In the case of a linear I/O system (LIO),
140+
# this will preserve the linear structure since the LTI system will
141+
# be converted to state space.
142+
#
143+
# * When combining state space or transfer with linear I/O systems, the
144+
# * output should be of type Linear IO system, since that maintains the
145+
# * underlying state space attributes.
146+
#
147+
# Note: tfx = non-proper transfer function, order(num) > order(den)
148+
#
149+
150+
type_list = ['ss', 'tf', 'tfx', 'frd', 'lio', 'ios', 'arr', 'flt']
151+
conversion_table = [
152+
# L / R ['ss', 'tf', 'tfx', 'frd', 'lio', 'ios', 'arr', 'flt']
153+
('ss', ['ss', 'ss', 'tf' 'frd', 'lio', 'ios', 'ss', 'ss' ]),
154+
('tf', ['tf', 'tf', 'tf' 'frd', 'lio', 'ios', 'tf', 'tf' ]),
155+
('tfx', ['tf', 'tf', 'tf', 'frd', 'E', 'E', 'tf', 'tf' ]),
156+
('frd', ['frd', 'frd', 'frd', 'frd', 'E', 'E', 'frd', 'frd']),
157+
('lio', ['lio', 'lio', 'E', 'E', 'lio', 'ios', 'lio', 'lio']),
158+
('ios', ['ios', 'ios', 'E', 'E', 'ios', 'ios', 'ios', 'ios']),
159+
('arr', ['ss', 'tf', 'tf' 'frd', 'lio', 'ios', 'arr', 'arr']),
160+
('flt', ['ss', 'tf', 'tf' 'frd', 'lio', 'ios', 'arr', 'flt'])]
161+
162+
@pytest.mark.skip(reason="future test; conversions not yet fully implemented")
163+
# @pytest.mark.parametrize("opname", ['add', 'sub', 'mul', 'truediv'])
164+
# @pytest.mark.parametrize("ltype", type_list)
165+
# @pytest.mark.parametrize("rtype", type_list)
166+
def test_binary_op_type_conversions(opname, ltype, rtype, sys_dict):
167+
op = getattr(operator, opname)
168+
leftsys = sys_dict[ltype]
169+
rightsys = sys_dict[rtype]
170+
expected = \
171+
conversion_table[type_list.index(ltype)][1][type_list.index(rtype)]
172+
173+
# Get rid of warnings for InputOutputSystem objects by making a copy
174+
if isinstance(leftsys, ct.InputOutputSystem) and leftsys == rightsys:
175+
rightsys = leftsys.copy()
176+
177+
# Make sure we get the right result
178+
if expected == 'E' or expected[0] == 'x':
179+
# Exception expected
180+
with pytest.raises(TypeError):
181+
op(leftsys, rightsys)
182+
else:
183+
# Operation should work and return the given type
184+
result = op(leftsys, rightsys)
185+
186+
# Print out what we are testing in case something goes wrong
187+
assert isinstance(result, type_dict[expected])

0 commit comments

Comments
 (0)
0