Hi all,

In response to a request by Poul Nielsen, I have produced a model demonstrating how this functionality might be used.

type_library.cellml is the beginnings of a type library, which provides a complex number type and some other types needed to support it. The complex number type is actually a function which takes a 'base type' and returns a type. For example, if you wanted to represent a 'vector' in a plane in metres as a complex number, you can call the function which returns a type with real_metres as the argument to get a type for storing a number of metres. This form implicitly requires that both cartesian co-ordinates have the same type.

Also included is a library of utilities for working with these complex numbers to get the cartesian and polar co-ordinates.

Writing this up has identified several places where there is room for improvement: => We require that the type attribute is present on variables in every component it is used (not just one of them), and these types are also variables which must be present everywhere. If types are all of type type, this isn't as bad, because it means that we only require one extra variable. However, if we only required that the type attribute was present in one of the connected network of variables (but allowed it to be present in more as long as the types match) we would reduce the burden on model authors. => Wildcard types, or even some sort of type inheritance scheme once more looks quite helpful. For example, we have a function called 'sign' which returns 1, 0, or -1 depending on the sign of the input. But we have to explicitly say what the type of the input is (not just 'any kind of real number' for instance). There will be many similar cases. Sometimes this is a good thing as it provides additional type safety, but in other cases, it is bad. We could have a unidirectional concept of compatibility as used in inheritance hierarchies (so for example, real_metre matches real_anything, but real_anything doesn't match real_metre, since real_metre inherits from real_anything). This can be worked around by using functions which return types, or by using the trick we used in type_utilities of having a variable you connect up to correct type, but the cost of having one import or defining a type just to call a basic function puts a lot of burden on model authors and makes models rather verbose.

Best wishes,
Andrew

<c11:model xmlns:c11="http://www.cellml.org/cellml/1.1#"; 
xmlns:c12="http://www.cellml.org/cellml/1.2#"; 
xmlns:m="http://www.w3.org/1998/Math/MathML";>
  <c11:component name="TypeLibrary">
    <!-- type_from_type_function_type: The type of a function which takes a 
type and returns a type. -->
    <c12:variable name="type_from_type_function_type" type="type" 
public_interface="yes" />
    <!-- cartesian_complex_type_function: A function which converts a scalar 
type (parameter)
           into the type of the cartesian form of the complex number as a 
vector of two reals
           having the type of the parameter. -->
    <c12:variable name="complex_type_function" 
type="type_from_type_function_type" public_interface="yes"/>

    <!-- The following variables are used locally for bvars and the like 
only... -->
    <c12:variable name="base_type" type="type" />

    <m:math>
      <m:apply id="type_from_type_function_eqn"><m:eq/>
        <m:ci>type_from_type_function</m:ci>
        <m:apply><c12:function_type />
          <m:ci>type</m:ci>
          <m:ci>type</m:ci>
        </m:apply>
      </m:apply>

      <!-- We might want to build this into CellML 1.2 core (with the option
           that secondary specification don't support it) but if not, this is
           how complex numbers in their cartesian form could be defined. We
           probably should 
        -->
      <m:apply id="cartesian_complex_type_function_eqn"><m:eq/>
        <m:ci>complex_type_function</m:ci>
        <m:lambda>
          <m:bvar><m:ci>base_type</m:ci></m:bvar>
        </m:lambda>
        <m:apply><c12:vector_type />
          <!-- First argument: type of vector elements... -->
          <m:ci>base_type</m:ci>
          <!-- Second argument: size of vector -->
          <m:cn c12:type="real_dimensionless">2</m:cn>
        </m:apply>
      </m:apply>
    </m:math>
  </c11:component>
</c11:model>
<c11:model xmlns:c11="http://www.cellml.org/cellml/1.1#"; 
xmlns:c12="http://www.cellml.org/cellml/1.2#"; 
xmlns:m="http://www.w3.org/1998/Math/MathML"; 
xmlns:xlink="http://www.w3.org/1999/xlink";>
  <c11:component name="ComplexUtilities">
    <!-- Connect up to the type you want this component to work with. -->
    <c12:variable name="base_type" type="type" public_interface="yes"/>

    <!-- The complex_type (can be computed from base_type). -->
    <c12:variable name="complex_type" type="type" public_interface="yes" />
    <c12:variable name="complex_to_base_function_type" type="type" 
public_interface="yes" />

    <!-- A function for fetching cartesian X co-ordinates. -->
    <c12:variable name="complex_get_cartesian_x" 
type="complex_to_base_function_type" public_interface="yes" />

    <c12:variable name="type_from_type_function_type" type="type" 
private_interface="yes" />
    <c12:variable name="complex_type_function" 
type="type_from_type_function_type" private_interface="yes"/>

    <!-- Local types -->
    <c12:variable name="base_type_to_dimensionless_function_type" type="type" />
    <c12:variable name="base_type_base_type_to_radians_function_type" 
type="type" />

    <!-- Local functions -->
    <c12:variable name="sign" type="base_type_to_dimensionless_function_type" />
    <c12:variable name="arctan2" 
type="base_type_base_type_to_radians_function_type" />

    <!-- Local bound variables -->
    <c12:variable name="complex" type="complex_type" />
    <c12:variable name="x" type="base_type" />
    <c12:variable name="y" type="base_type" />

    <m:math>
      <!-- An example of a units computation... -->
      <m:apply><m:eq/>
        <m:ci>complex_type</m:ci>
        <m:apply><m:ci>complex_type_function</m:ci>
          <m:ci>base_type</m:ci>
        </m:apply>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>complex_to_base_function_type</m:ci>
        <m:apply><c12:function_type/>
          <m:ci>base_type</m:ci>
          <m:ci>complex_type</m:ci>
        </m:apply>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>complex_get_real</m:ci>
        <m:lambda>
          <m:bvar><m:ci>complex</m:ci></m:bvar>
          <m:apply><c12:vector_element/>
            <m:ci>complex</m:ci>
            <m:cn c12:type="real_dimensionless">0</m:cn>
          </m:apply>
        </m:lambda>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>complex_get_imaginary</m:ci>
        <m:lambda>
          <m:bvar><m:ci>complex</m:ci></m:bvar>
          <m:apply><c12:vector_element/>
            <m:ci>complex</m:ci>
            <m:cn c12:type="real_dimensionless">1</m:cn>
          </m:apply>
        </m:lambda>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>complex_get_polar_modulus</m:ci>
        <m:lambda>
          <m:bvar><m:ci>complex</m:ci></m:bvar>
          <m:apply><m:root/>
            <m:apply><m:plus/>
              <m:apply><m:pow/>
                <m:apply><m:ci>complex_get_real</m:ci>
                  <m:ci>complex</m:ci>
                </m:apply>
                <m:cn c12:type="real_dimensionless">2</m:cn>
              </m:apply>
              <m:apply><m:pow/>
                <m:apply><m:ci>complex_get_imaginary</m:ci>
                  <m:ci>complex</m:ci>
                </m:apply>
                <m:cn c12:type="real_dimensionless">2</m:cn>
              </m:apply>
            </m:apply>
          </m:apply>
        </m:lambda>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>base_type_to_dimensionless_function_type</m:ci>
        <m:apply><c12:function_type/>
          <m:ci>real_dimensionless</m:ci>
          <m:ci>base_type</m:ci>
        </m:apply>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>base_type_base_type_to_radians_function_type</m:ci>
        <m:apply><c12:function_type/>
          <m:ci>real_radians</m:ci>
          <m:ci>base_type</m:ci>
          <m:ci>base_type</m:ci>
        </m:apply>
      </m:apply>

      <!-- This is a useful function; we could put it in another library. -->
      <m:apply><m:eq/>
        <m:ci>sign</m:ci>
        <m:lambda>
          <m:bvar>x</m:bvar>
          <m:piecewise>
            <m:piece>
              <m:cn c12:type="real_dimensionless">0</m:cn>
              <m:apply><m:eq/>
                <m:ci>x</m:ci>
                <m:cn c12:type="base_type">0</m:cn>
              </m:apply>
            </m:piece>
            <m:piece>
              <m:cn c12:type="real_dimensionless">-1</m:cn>
              <m:apply><m:lt/>
                <m:ci>x</m:ci>
                <m:cn c12:type="base_type">0</m:cn>
              </m:apply>
            </m:piece>
            <m:otherwise>
              <m:cn c12:type="real_dimensionless">1</m:cn>
            </m:otherwise>
          </m:piecewise>
        </m:lambda>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>arctan2</m:ci>
        <m:lambda>
          <m:bvar><m:ci>y</m:ci></m:bvar>
          <m:bvar><m:ci>x</m:ci></m:bvar>
          <m:apply><m:times/>
            <m:piecewise>
              <m:piece>
                <m:apply><m:divide/>
                  <m:pi/>
                  <m:cn c12:type="real_dimensionless">2</m:cn>
                </m:apply>
                <m:apply><m:eq/>
                  <m:ci>x</m:ci>
                  <m:cn c12:type="base_type">0</m:cn>
                </m:apply>
              </m:piece>
              
              <m:piece>
                <m:apply><m:arctan/>
                  <m:apply><m:abs/>
                    <m:apply><m:divide/>
                      <m:ci>y</m:ci>
                      <m:ci>x</m:ci>
                    </m:apply>
                  </m:apply>
                </m:apply>
                <m:apply><m:gt/>
                  <m:ci>x</m:ci>
                  <m:cn c12:type="base_type">0</m:cn>
                </m:apply>
              </m:piece>
              
              <m:otherwise>
                <m:apply><m:minus/>
                  <m:pi />
                  <m:apply><m:arctan/>
                    <m:apply><m:abs/>
                      <m:apply><m:divide/>
                        <m:ci>y</m:ci>
                        <m:ci>x</m:ci>
                      </m:apply>
                    </m:apply>
                  </m:apply>
                </m:apply>
              </m:otherwise>
            </m:piecewise>
            
            <m:apply><m:ci>sign</m:ci>
              <m:ci>y</m:ci>
            </m:apply>
          </m:apply>
        </m:lambda>
      </m:apply>

      <m:apply><m:eq/>
        <m:ci>complex_get_polar_argument</m:ci>
        <m:lambda>
          <m:bvar><m:ci>complex</m:ci></m:bvar>
          <m:apply><m:ci>arctan2</m:ci>
            <m:apply><m:ci>complex_get_cartesian_y</m:ci>
              <m:ci>complex</m:ci>
            </m:apply>
            <m:apply><m:ci>complex_get_cartesian_x</m:ci>
              <m:ci>complex</m:ci>
            </m:apply>
          </m:apply>
        </m:lambda>
      </m:apply>
    </m:math>
  </c11:component>
  
  <c11:import xlink:href="type_library.cellml">
    <c11:component name="TypeLibrary" component_ref="TypeLibrary"/>
  </c11:import>
  
  <c12:encapsulation>
    <c11:component_ref component_ref="ComplexUtilities">
      <c11:component_ref component_ref="TypeLibrary"/>
    </c11:component_ref>
  </c12:encapsulation>

  <c12:connection component_1="TypeLibrary" component_2="ComplexUtilities">
    <c11:map_variables variable_1="type_from_type_function_type" 
variable_2="type_from_type_function_type" />
    <c11:map_variables variable_1="complex_type_function" 
variable_2="complex_type_function" />
  </c12:connection>
</c11:model>
_______________________________________________
cellml-discussion mailing list
cellml-discussion@cellml.org
http://www.cellml.org/mailman/listinfo/cellml-discussion

Reply via email to