Week 2 - GSoC '21

Progress in Week-2:

  1. Added the new page in the docs of control module demonstrating the use cases through Textbook examples (similar to sympy.physics.continuum_mechanics). It is currently in the #21556 PR. Still, I plan to add these examples through another PR after all the PRs related to TransferFunctionMatrix and other MIMO functionalities (Series, Parallel, and Feedback support) are merged.
  2. Improved the docstrings for Series and Parallel classes. I have divided them into separate headings for SISO and MIMO systems. Since printing the Series and Parallel objects in the old docs made interpretation hard for the user (especially with MIMO systems), I added a few examples demonstrating the pprint feature. It will now be helpful to the users who don’t have prior experience with SymPy and want to use the control module features efficiently, without the need to search docs for unknown functionalities.
  3. Week-2 has mainly been refactoring and improving upon the features added/modified in Week-1:
    • I had a video call with both mentors (@moorepants and @namannimmo10) in which they suggested changes in the current implementation to make things compatible with SymPy’s conventions.
    • As the new PR for TransferFunctionMatrix (#21556) has grown very big and messy (about 2800 lines of changes and that too without the unit tests added for most of the part till now), I was suggested to chunk it up in 3-4 smaller PRs for easing the review process. The first PR I opened as a part of this process is #21634. It mainly contains the TransferFunction’s documentation changes, to_expr (yes, it’s not a private method now), and a new classmethod from_rational_expression (TransferFunction can now be instantiated from rational expressions by using classmethod and not directly like in Week-1) along with documentation and unit tests. The classmethod idea was suggested by @moorepants (following PEP 20), and it makes more sense now to do it like that. Expansion of expressions to their polynomial form is also removed now, keeping in mind that SymPy is a symbolic library and not a numerical one. This PR is approved and will hopefully be merged in a day or two.
  4. @oscarbenjamin is working on deprecating non-expr support in all the Matrix classes in SymPy. Since the new implementation of TransferFunctionMatrix had ImmutableDenseMatrix as its superclass, it was causing an issue in the process. Therefore, there will also be design changes in the new TransferFunctionMatrix constructor. For now, I have decided to go ahead with this constructor after getting positive feedback from my mentors:

     class TransferFunctionMatrix(Basic):
    
         def __new__(cls, arg): 
    
             expr_mat_arg = []
             var = arg[0][0].var
             for row in range(len(arg)):
                 temp = []
                 for col in range(len(arg[row])):
                     if not isinstance(arg[row][col], (TransferFunction, Series, Parallel)):
                         raise TypeError("Incompatible type found as the element of TransferFunctionMatrix")
    
                     if var != arg[row][col].var:
                         raise ValueError("Conflicting value(s) found for `var`. All TransferFunction instances in "
                                 "TransferFunctionMatrix should use the same complex variable in Laplace domain.")
    
                     if isinstance(arg[row][col], TransferFunction):
                         temp.append(arg[row][col]._to_expr())
                     else:
                         temp.append(arg[row][col].doit()._to_expr())
                 expr_mat_arg.append(temp)
                        
    
             if isinstance(arg, (tuple, list, Tuple)):
                 # Making nested Tuple (sympy.core.containers.Tuple) from nested list or nested python tuple
                 arg = Tuple(*(Tuple(*r, sympify=False) for r in arg), sympify=False)
                
             obj = super(TransferFunctionMatrix, cls).__new__(cls, arg)
             obj._expr_mat = ImmutableMatrix(expr_mat_arg)
             obj._var = arg[0][0].var
             obj._num_outputs, obj._num_inputs = obj._expr_mat.shape
             return obj
    

    I have talked about advantages of this constructor here. Note that this might not be the final form and there might be some changes in the future.