{"id":4913,"date":"2007-12-19T11:00:00","date_gmt":"2007-12-19T11:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2007\/12\/19\/higher-algebra-with-operator-overloads-brian-beckman\/"},"modified":"2024-07-05T14:35:36","modified_gmt":"2024-07-05T21:35:36","slug":"higher-algebra-with-operator-overloads-brian-beckman","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/higher-algebra-with-operator-overloads-brian-beckman\/","title":{"rendered":"Higher Algebra with Operator Overloads (Brian Beckman)"},"content":{"rendered":"<p><a class=\"\" href=\"https:\/\/channel9.msdn.com\/ShowPost.aspx?PostID=367090\" target=\"_blank\" rel=\"noopener\">Recently I did a Channel 9 interview<\/a> with <a class=\"\" href=\"http:\/\/blogs.msdn.com\/bethmassi\/\" target=\"_blank\" rel=\"noopener\">Beth Massi<\/a> where I walked through a Visual Basic program that used Generics and Operator overloads to perform some higher mathematics. I thought I&#8217;d follow up with a post explaining the details of exactly what I did. <\/p>\n<p>Operator overloads with Generics enable some beautiful designs for data types in Higher Algebra, a branch of mathematics, sometimes called Abstract Algebra. Consider <strong><em>fields<\/em><\/strong> and <strong><em>vector spaces<\/em><\/strong>. <font color=\"#ff0000\">I&#8217;ll show you operator overloads at THREE levels in a single design.<\/font> First, background: In this context, a &#8220;field&#8221; is a collection of unspecified objects, closed under two associative operators, + and *, that obey the distributive law. <\/p>\n<p>Closed means that for any a, b, and c in the field, a+b and a*c are in the field. Associative means <\/p>\n<p>a + (b + c) = (a + b) + c<\/p>\n<p>a * (b * c) = (a * b) * c<\/p>\n<p>Distributive means<\/p>\n<p>a * (b + c) = a * b + a * c<\/p>\n<p>(b + c) * a = b * a + c * a<\/p>\n<p>The field must also have two special members: the additive unit 0 and the multiplicative unit 1, where<\/p>\n<p>a + 0 = 0 + a = a<\/p>\n<p>a * 1 = 1 * a = a<\/p>\n<p>and must have for every a, an additive inverse, -a, such that a + -a = -a + a = 0. There must also be a multiplicative inverse for every element except 0, written 1\/a, such that a * 1\/a = 1\/a * a = 1.<\/p>\n<p>Some authors insist on the commutative laws (a + b = b + a, a * b = b * a), too, but we don&#8217;t, here. The most common examples of fields are the Rationals, the Real numbers, the Complex numbers, all of which have commutative addition and multiplication; and the Quaternions, which have non-commutative multiplication. <\/p>\n<p>Don&#8217;t confuse the mathematical &#8220;field&#8221; with a &#8220;field&#8221; in a record, structure or class. <\/p>\n<p>In each instance of a field, we define + and * to do anything we want so long as they obey the associative and distributive laws. A &#8220;vector space over a field&#8221; is the set of <em>n-tuples <\/em>or <em>vectors <\/em>built up from members of the field and closed under an additional linear combination law, written with no operator symbol, or sometimes with *. If v and w are any two vectors, and f and g are any two members of the underlying field, then f v + g w is a vector, and, furthermore, <\/p>\n<p>f (v + w) = f v + f w<\/p>\n<p>(v + w) g = v g + w g<\/p>\n<p>(f + g) v = f v + g v<\/p>\n<p>w (f + g) = w f + w g<\/p>\n<p>Vector spaces are central in physics and simulation. Imagine 6-vectors of real numbers; such things represent particle states in &#8220;phase space&#8221; in classical mechanics. Imagine 4-vectors of complex numbers; such things appear in quantum mechanics. Similar structures occur all over Quantum Theory and Gravitation <\/p>\n<p>References: <\/p>\n<ul>\n<li>&#8220;Vector Calculus, Linear Algebra, and Differential Forms&#8221; [VCLADF], by John H. Hubbard, Barbara Burke Hubbard; <\/li>\n<li>&#8220;Lie Groups, Lie Algebras, and Some of Their Applications,&#8221; by Robert Gilmore <\/li>\n<li>&#8220;The Geometry of Physics,&#8221; by Theodore Frankel <\/li>\n<\/ul>\n<p>Applications for vectors of quaternions are not so easy to come by, but, they are perfectly well defined, and, if we do our software design right, they &#8220;just work.&#8221; Ditto for vectors over a purely symbolic field or over any other kind. It&#8217;s not difficult to support field-like algebraic structures with non-associative multiplication within the same software design. Such things include the <em>Cayley numbers<\/em> or <em>octonions<\/em>, but, because of non-associativity, they don&#8217;t mesh easily with linear algebra, and that&#8217;s where we want to go. Stop with the quaternions.<\/p>\n<p>We extend the design to <strong><em>inner-product spaces<\/em><\/strong>, in which every vector has a dual, and to <strong><em>linear algebras<\/em><\/strong>: sets of linear transformations of vectors, realized as matrices. With just a little code, we build a general, extensible, optimizable library suitable for physics, engineering, and mathematics in any finite-dimensional vector spaces. <\/p>\n<p>We want three layers: <\/p>\n<ul>\n<li><strong><em>underlying<\/em><\/strong> types <\/li>\n<li><strong><em>field<\/em><\/strong> types, generic over the underlying types <\/li>\n<li><strong><em>linear-algebra <\/em><\/strong>types, generic over the field types <\/li>\n<\/ul>\n<p>The <em>underlying types <\/em>comprise built-ins like <em>Double, <\/em>and custom types like <em>Rational<\/em>, <em>Complex<\/em>, <em>Quaternion<\/em>, and <em>Symbol<\/em>. Underlying types should implement the basic field operations, but can have many more operations for convenience, like optimized division routines. <font color=\"#ff0000\">Operator overloading is a no-brainer for the underlying types<\/font>. <\/p>\n<p><font color=\"#ff0000\">At the top level of the <em>linear-algebra types<\/em>, operator overloads are again a no-brainer<\/font> for vector + vector, matrix * vector, vector * matrix, matrix * matrix, vector * vector, and so on.<\/p>\n<p>At the middle layer, the <em>field types <\/em>abstract and narrow the operations down to the bare minimum so that the linear-algebra types know what and only what to expect. In this layer, operator overloading is not quite a no-brainer, and there are a couple of different ways to go with a design. <\/p>\n<p>The first paragraph showed the field axioms, and these are what we must design into our <em>field types<\/em>. One way to do that is to impose the field operations by interface:<\/p>\n<pre class=\"code\"><span>Public Interface <\/span>IField(<span>Of <\/span>U) <span>'U is the \"UNDERLYING\" type\n    'Get the underlying value.\n    <\/span><span>Property <\/span>UValue() <span>As <\/span>U\n    <span>'Generic users of IField type shouldn't be able to tell\n    'whether the Underlying type U has copy-reference\n    'semantics or copy-value semantics, so let's insist that\n    'providers of IField implement a Dup operation.\n    <\/span><span>Function <\/span>Dup() <span>As <\/span>IField(<span>Of <\/span>U)\n    <span>'This is what fields do (would be nice to have a contract\n    'for the distributive law). Must use a design like this\n    'since Interfaces cannot host Shared functions in general,\n    'and operator overloads in particular.\n    <\/span><span>Function <\/span>Add(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of <\/span>U)) <span>As <\/span>IField(<span>Of <\/span>U)\n    <span>Function <\/span>Mul(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of <\/span>U)) <span>As <\/span>IField(<span>Of <\/span>U)\n    <span>Function <\/span>AdditiveInverse(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of <\/span>U)) _\n    <span>As <\/span>IField(<span>Of <\/span>U)\n    <span>Function <\/span>MultiplicativeInverse(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of <\/span>U)) _\n    <span>As <\/span>IField(<span>Of <\/span>U)\n    <span>'Every field must have these. Implement them as Shared and\n    'even Const if possible.\n    <\/span><span>ReadOnly Property <\/span>Zero() <span>As <\/span>IField(<span>Of <\/span>U)\n    <span>ReadOnly Property <\/span>Unity() <span>As <\/span>IField(<span>Of <\/span>U)\n    <span>'The following is an auxiliary operation for the Normed\n    'Division Algebras to support Inner Product, or\n    '\"Sesquilinear mappings.\" This computes the complex\n    'conjugate, the quaternion conjugate, and so on. If the\n    'underlying field does not have a natural dual field, then\n    'it's probably self-dual and just implement \"Dual\" as \"Dup.\"\n    <\/span><span>Function <\/span>Dual() <span>As <\/span>IField(<span>Of <\/span>U)\n<span>End Interface<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>An upside of this design is that both Structure types and Class types can implement the interface. Thus, the linear-algebra classes are independent of differences of copy semantics. Programmers may use Structure types for run-time speed at both the underlying-type level and at the field level.<\/p>\n<p>Here&#8217;s an example of a Structure implementing a field of Doubles<\/p>\n<pre class=\"code\"><span>Public Structure <\/span>SFDouble\n    <span>Implements <\/span>IField(<span>Of Double<\/span>)\n...\n    <span>Private <\/span>mValue <span>As Double\n    Public Property <\/span>UValue() <span>As Double Implements <\/span>IField(<span>Of Double<\/span>).UValue\n        <span>Get\n            Return <\/span>mValue\n        <span>End Get\n        Set<\/span>(<span>ByVal <\/span>value <span>As Double<\/span>)\n            mValue = value\n        <span>End Set\n    End Property\n    Public Sub New<\/span>(<span>ByVal <\/span>d <span>As Double<\/span>)\n        mValue = d\n    <span>End Sub\n<\/span><span>...\n    Public Function <\/span>Add(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of Double<\/span>)) <span>As <\/span>IField(<span>Of Double<\/span>) _\n    <span>Implements <\/span>IField(<span>Of Double<\/span>).Add\n        <span>Return New <\/span>SFDouble(<span>Me<\/span>.UValue + that.UValue)\n    <span>End Function\n    Public Function <\/span>Dual() <span>As <\/span>IField(<span>Of Double<\/span>) <span>Implements <\/span>IField(<span>Of Double<\/span>).Dual\n        <span>Return New <\/span>SFDouble(<span>Me<\/span>.UValue)\n    <span>End Function\n    Public Function <\/span>Dup() <span>As <\/span>IField(<span>Of Double<\/span>) <span>Implements <\/span>IField(<span>Of Double<\/span>).Dup\n        <span>Return New <\/span>SFDouble(<span>Me<\/span>.UValue)\n    <span>End Function\n    Public Function <\/span>AdditiveInverse(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of Double<\/span>)) <span>As <\/span>IField(<span>Of Double<\/span>) _\n    <span>Implements <\/span>IField(<span>Of Double<\/span>).AdditiveInverse\n        <span>'Let the underlying math throw exception here if that.UValue == 0\n        <\/span><span>Return New <\/span>FDouble(-<span>Me<\/span>.UValue)\n    <span>End Function\n    Public Function <\/span>MultiplicativeInverse(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of Double<\/span>)) <span>As <\/span>IField(<span>Of Double<\/span>) _\n    <span>Implements <\/span>IField(<span>Of Double<\/span>).MultiplicativeInverse\n        <span>'Let the underlying math throw exception here if that.UValue == 0\n        <\/span><span>Return New <\/span>FDouble(1 \/ <span>Me<\/span>.UValue)\n    <span>End Function\n    Public Function <\/span>Mul(<span>ByVal <\/span>that <span>As <\/span>IField(<span>Of Double<\/span>)) <span>As <\/span>IField(<span>Of Double<\/span>) _\n    <span>Implements <\/span>IField(<span>Of Double<\/span>).Mul\n        <span>Return New <\/span>SFDouble(<span>Me<\/span>.UValue * that.UValue)\n    <span>End Function\n    Private Shared <\/span>sUnity = <span>New <\/span>SFDouble(1.0)\n    <span>Private Shared <\/span>sZero = <span>New <\/span>SFDouble(0.0)\n    <span>Public ReadOnly Property <\/span>Unity() <span>As <\/span>IField(<span>Of Double<\/span>) <span>Implements <\/span>IField(<span>Of Double<\/span>).Unity\n        <span>Get\n            Return <\/span>sUnity\n        <span>End Get\n    End Property\n    Public ReadOnly Property <\/span>Zero() <span>As <\/span>IField(<span>Of Double<\/span>) <span>Implements <\/span>IField(<span>Of Double<\/span>).Zero\n        <span>Get\n            Return <\/span>sZero\n        <span>End Get\n    End Property\n<\/span><span>...\nEnd Structure\n<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>A <em>Big Downside<\/em> though, for the purposes of this exercise, is <font color=\"#ff0000\">no operator overloads at the field level<\/font>, because operator overloads <br \/>are <em>Shared<\/em> by definition (i.e., <em>static<\/em>) and interfaces can&#8217;t support static methods (the reason is that static virtual methods don&#8217;t make sense in .NET, and all methods in an interface are virtual).<\/p>\n<p>But, we want operator overloads at the field level, and we can get them through an alternative base-class design for fields. We lose Structures at the field level, since particular fields must inherit from a base Class, but the underlying types can still be structures.<\/p>\n<pre class=\"code\"><span>Public MustInherit Class <\/span>AField(<span>Of <\/span>U) <span>'U is the \"UNDERLYING\" type\n<\/span><font color=\"#008000\">...<\/font>\n    <span>Private <\/span>mUValue <span>As <\/span>U\n    <span>Public Property <\/span>UValue() <span>As <\/span>U\n        <span>Get\n            Return <\/span>mUValue\n        <span>End Get\n        Set<\/span>(<span>ByVal <\/span>value <span>As <\/span>U)\n            mUValue = value\n        <span>End Set\n    End Property\n    <\/span><span>'Now, our operator overloads just call virtual MustOverride Functions.\n    'Magically, these are NON-COMMUTATIVE in general, just as we want.\n    <\/span><span>Public Shared Operator <\/span>+(<span>ByVal <\/span>e1 <span>As <\/span>AField(<span>Of <\/span>U), _\n                             <span>ByVal <\/span>e2 <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n        <span>Return <\/span>e1.Add(e2)\n    <span>End Operator\n    Public Shared Operator <\/span>-(<span>ByVal <\/span>e1 <span>As <\/span>AField(<span>Of <\/span>U), _\n                             <span>ByVal <\/span>e2 <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n        <span>Return <\/span>e1.Add(e2.AdditiveInverse())\n    <span>End Operator\n    Public Shared Operator <\/span>*(<span>ByVal <\/span>e1 <span>As <\/span>AField(<span>Of <\/span>U), _\n                             <span>ByVal <\/span>e2 <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n        <span>Return <\/span>e1.Mul(e2)\n    <span>End Operator\n    Public Shared Operator <\/span>\/(<span>ByVal <\/span>e1 <span>As <\/span>AField(<span>Of <\/span>U), _\n                             <span>ByVal <\/span>e2 <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n        <span>Return <\/span>e1.Mul(e2.MultiplicativeInverse())\n    <span>End Operator\n    Public Shared Operator <\/span>-(<span>ByVal <\/span>that <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n        <span>Return <\/span>that.AdditiveInverse()\n    <span>End Operator\n    Public Shared Operator Not<\/span>(<span>ByVal <\/span>that <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n        <span>Return <\/span>that.Dual()\n    <span>End Operator\n    <\/span><span>'This is what fields do (would be nice to have a contract for the\n    'distributive law).\n    <\/span><span>MustOverride Function <\/span>Add(<span>ByVal <\/span>that <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n    <span>MustOverride Function <\/span>Mul(<span>ByVal <\/span>that <span>As <\/span>AField(<span>Of <\/span>U)) <span>As <\/span>AField(<span>Of <\/span>U)\n    <span>MustOverride Function <\/span>AdditiveInverse() <span>As <\/span>AField(<span>Of <\/span>U)\n    <span>MustOverride Function <\/span>MultiplicativeInverse() <span>As <\/span>AField(<span>Of <\/span>U)\n    <span>'Every field must have these. Implement them as Shared and even Const if\n    'possible.\n    <\/span><span>MustOverride ReadOnly Property <\/span>Zero() <span>As <\/span>AField(<span>Of <\/span>U)\n    <span>MustOverride ReadOnly Property <\/span>Unity() <span>As <\/span>AField(<span>Of <\/span>U)\n    <span>'Generic users of IField type shouldn't be able to tell\n    'whether the Underlying type U has copy-reference\n    'semantics or copy-value semantics, so insist that\n    'subclasses of AField implement a Dup operation.\n    <\/span><span>MustOverride Function <\/span>Dup() <span>As <\/span>AField(<span>Of <\/span>U)\n    <span>'The following is an auxiliary operation for the Normed\n    'Division Algebras to support Inner Product, or\n    '\"Sesquilinear mappings.\" This computes the complex\n    'conjugate, the quaternion conjugate, and so on. If the\n    'underlying field does not have a natural dual field, then\n    'it's probably self-dual and just implement \"Dual\" as \"Dup.\"\n    <\/span><span>MustOverride Function <\/span>Dual() <span>As <\/span>AField(<span>Of <\/span>U)\n<span>End Class\n<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>Now we have operator overloads at the field level, but they&#8217;re not virtual (they can&#8217;t be). What they do is statically dispatch to <br \/>virtual ADD and MUL methods, which are just like the ones we had in the interface design for the field level. Nice, eh? Here are the implementations for the field of Complexes, which are implemented in an underlying Structure type:<\/p>\n<pre class=\"code\"><span>Public Class <\/span>AComplex\n    <span>Inherits <\/span>AField(<span>Of <\/span>Complex)\n...<\/pre>\n<pre class=\"code\"><span>    Public Overrides Function <\/span>Add(<span>ByVal <\/span>that <span>As <\/span>AField(<span>Of <\/span>Complex)) <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Return New <\/span>AComplex(<span>Me<\/span>.UValue + that.UValue)\n    <span>End Function\n    Public Overrides Function <\/span>AdditiveInverse() <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Return New <\/span>AComplex(-<span>Me<\/span>.UValue.R, -<span>Me<\/span>.UValue.I)\n    <span>End Function\n    Public Overrides Function <\/span>Dual() <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Return New <\/span>AComplex(<span>Not Me<\/span>.UValue)\n    <span>End Function\n    Public Overrides Function <\/span>Dup() <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Return New <\/span>AComplex(<span>Me<\/span>)\n    <span>End Function\n    Public Overrides Function <\/span>MultiplicativeInverse() <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Return New <\/span>AComplex(1.0 \/ <span>Me<\/span>.UValue)\n    <span>End Function\n    Public Overrides Function <\/span>Mul(<span>ByVal <\/span>that <span>As <\/span>AField(<span>Of <\/span>Complex)) <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Return New <\/span>AComplex(<span>Me<\/span>.UValue * that.UValue)\n    <span>End Function\n...<\/span><\/pre>\n<pre class=\"code\"><span><\/span><span>    Public Overrides ReadOnly Property <\/span>Unity() <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Get\n            Return New <\/span>AComplex(1.0, 0.0)\n        <span>End Get\n    End Property\n    Public Overrides ReadOnly Property <\/span>Zero() <span>As <\/span>AField(<span>Of <\/span>Complex)\n        <span>Get\n            Return New <\/span>AComplex(0.0, 0.0)\n        <span>End Get\n    End Property\n    Public Overrides Function <\/span>ToString() <span>As String\n        Return <\/span>UValue.ToString()\n    <span>End Function\nEnd Class\n<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>And here is its underlying type:<\/p>\n<pre class=\"code\"><span>Imports <\/span>System.Text\n<span>Public Structure <\/span>Complex\n    <span>Private <\/span>mR <span>As Double\n    Public Property <\/span>R() <span>As Double\n        Get\n            Return <\/span>mR\n        <span>End Get\n        Set<\/span>(<span>ByVal <\/span>value <span>As Double<\/span>)\n            mR = value\n        <span>End Set\n    End Property\n    Private <\/span>mI <span>As Double\n    Public Property <\/span>I() <span>As Double\n        Get\n            Return <\/span>mI\n        <span>End Get\n        Set<\/span>(<span>ByVal <\/span>value <span>As Double<\/span>)\n            mI = value\n        <span>End Set\n    End Property\n<\/span><span>...\n    Public Shared Operator <\/span>-(<span>ByVal <\/span>that <span>As <\/span>Complex) <span>As <\/span>Complex\n        <span>Return New <\/span>Complex(-that.R, -that.I)\n    <span>End Operator\n    Public Shared Operator <\/span>+(<span>ByVal <\/span>c1 <span>As <\/span>Complex, <span>ByVal <\/span>c2 <span>As <\/span>Complex) <span>As <\/span>Complex\n        <span>Dim <\/span>result = <span>New <\/span>Complex()\n        result.R = c1.R + c2.R\n        result.I = c1.I + c2.I\n        <span>Return <\/span>result\n    <span>End Operator\n    Public Shared Operator <\/span>*(<span>ByVal <\/span>c1 <span>As <\/span>Complex, <span>ByVal <\/span>c2 <span>As <\/span>Complex) <span>As <\/span>Complex\n        <span>Dim <\/span>result = <span>New <\/span>Complex()\n        result.R = (c1.R * c2.R) - (c1.I * c2.I)\n        result.I = (c1.R * c2.I) + (c1.I * c2.R)\n        <span>Return <\/span>result\n    <span>End Operator\n    Public Shared Operator Not<\/span>(<span>ByVal <\/span>c1 <span>As <\/span>Complex) <span>As <\/span>Complex\n        <span>Return New <\/span>Complex(c1.R, -c1.I)\n    <span>End Operator\n...<\/span><\/pre>\n<pre class=\"code\"><span><\/span><span>    Public Shared Operator <\/span>*(<span>ByVal <\/span>c <span>As <\/span>Complex, <span>ByVal <\/span>scalar <span>As Double<\/span>) <span>As <\/span>Complex\n        <span>Return New <\/span>Complex(c.R * scalar, c.I * scalar)\n    <span>End Operator\n    Public Shared Operator <\/span>\/(<span>ByVal <\/span>c <span>As <\/span>Complex, <span>ByVal <\/span>scalar <span>As Double<\/span>) <span>As <\/span>Complex\n        <span>Return New <\/span>Complex(c.R \/ scalar, c.I \/ scalar)\n    <span>End Operator\n    Public Shared Operator <\/span>\/(<span>ByVal <\/span>c1 <span>As <\/span>Complex, <span>ByVal <\/span>c2 <span>As <\/span>Complex) <span>As <\/span>Complex\n        <span>Return <\/span>c1 * <span>Not <\/span>c2 \/ c2.MagnitudeSquared()\n    <span>End Operator\n...<\/span><\/pre>\n<pre class=\"code\"><span><\/span><span>End Structure\n<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>Now, we have an example of a Field generic on an underlying type, How about the Vector space? I wrote one vector space generic <br \/>on the interface-style Field design, and another vector space generic on the base-class Field design. Here is the latter one, it&#8217;s prettier:<\/p>\n<pre class=\"code\"><span>Imports <\/span>System.Text\n<span>'The only reason I must mention the underlying type, U, here, is to pass it to the\n'Generic AField interface. I don't use U anywhere explicitly inside this. If I had\n'\"Monads\" in the Generic type language, then I could thread U through this via a\n'\"bind\" operator, very pretty, but dreamland.\n<\/span><span>Public Class <\/span>ANVector(<span>Of <\/span>U, T <span>As <\/span>{<span>New<\/span>, AField(<span>Of <\/span>U)})\n    <span>Private <\/span>mDimension <span>As Integer\n    Public ReadOnly Property <\/span>Dimension() <span>As Integer\n        Get\n            Return <\/span>mDimension\n        <span>End Get\n    End Property\n    Private <\/span>mComponents() <span>As <\/span>T\n    <span>Default Property <\/span>Component(<span>ByVal <\/span>i <span>As Integer<\/span>) <span>As <\/span>T\n        <span>Get\n            <\/span>Component = mComponents(i)\n        <span>End Get\n        Set<\/span>(<span>ByVal <\/span>Value <span>As <\/span>T)\n            mComponents(i) = Value\n        <span>End Set\n    End Property\n...<\/span><\/pre>\n<pre class=\"code\"><span><\/span><span>    <\/span><span>Public Sub New<\/span>(<span>ByVal <\/span>that <span>As <\/span>ANVector(<span>Of <\/span>U, T))\n        mDimension = that.Dimension\n        <span>ReDim <\/span>mComponents(Dimension)\n        <span>For <\/span>i = 1 <span>To <\/span>Dimension\n            <span>'Cannot call New with parameters on Generic types ... Sorry)\n            ' --&gt; Me.mComponents(i) = New T(that(i))\n            <\/span><span>Me<\/span>.mComponents(i) = that(i).Dup()\n        <span>Next\n    End Sub\n    <\/span><span>'Add two vectors. PROPERLY, vectors should themselves implement IModule, etc. Some day...\n    <\/span><span>Public Shared Operator <\/span>+(<span>ByVal <\/span>V1 <span>As <\/span>ANVector(<span>Of <\/span>U, T), <span>ByVal <\/span>V2 <span>As <\/span>ANVector(<span>Of <\/span>U, T)) _\n    <span>As <\/span>ANVector(<span>Of <\/span>U, T)\n        <span>If <\/span>V1.Dimension &lt;&gt; V2.Dimension <span>Then\n            Throw New <\/span>VectorSpaceException(<span>\"Cannot add vectors of different dimensions\"<\/span>)\n        <span>Else\n            Dim <\/span>result = <span>New <\/span>ANVector(<span>Of <\/span>U, T)(V1) <span>'clone\n            <\/span><span>For <\/span>i = 1 <span>To <\/span>result.Dimension\n                result(i) = result(i) + V2(i)<font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n            <span>Next\n            Return <\/span>result\n        <span>End If\n    End Operator\n    <\/span><span>'Scale a vector\n    <\/span><span>Public Shared Operator <\/span>*(<span>ByVal <\/span>that <span>As <\/span>ANVector(<span>Of <\/span>U, T), <span>ByVal <\/span>scalar <span>As <\/span>T) _\n    <span>As <\/span>ANVector(<span>Of <\/span>U, T)\n        <span>Dim <\/span>result = <span>New <\/span>ANVector(<span>Of <\/span>U, T)(that)\n        <span>For <\/span>i = 1 <span>To <\/span>result.Dimension\n            result(i) = result(i) * scalar<font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n        <span>Next\n        Return <\/span>result\n    <span>End Operator\n    Public Shared Operator <\/span>*(<span>ByVal <\/span>scalar <span>As <\/span>T, <span>ByVal <\/span>that <span>As <\/span>ANVector(<span>Of <\/span>U, T)) _\n    <span>As <\/span>ANVector(<span>Of <\/span>U, T)\n        <span>Return <\/span>that * scalar<font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n    <span>End Operator\n    Public Function <\/span>Dual()\n        <span>Dim <\/span>result = <span>New <\/span>ANVector(<span>Of <\/span>U, T)(<span>Me<\/span>.Dimension)\n        <span>For <\/span>i = 1 <span>To <\/span>result.Dimension\n            result(i) = <span>Not <\/span>result(i)<font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n        <span>Next\n        Return <\/span>result\n    <span>End Function\n    Public Shared Operator Not<\/span>(<span>ByVal <\/span>V <span>As <\/span>ANVector(<span>Of <\/span>U, T)) <span>As <\/span>ANVector(<span>Of <\/span>U, T)\n        <span>Return <\/span>V.Dual()\n    <span>End Operator\n    <\/span><span>'Inner product\n    <\/span><span>Public Shared Operator <\/span>*(<span>ByVal <\/span>Left <span>As <\/span>ANVector(<span>Of <\/span>U, T), <span>ByVal <\/span>Right <span>As <\/span>ANVector(<span>Of <\/span>U, T)) _\n    <span>As <\/span>T\n        <span>If <\/span>Left.Dimension &lt;&gt; Right.Dimension <span>Then\n            Throw New <\/span>VectorSpaceException _\n            (<span>\"Cannot compute inner product of vectors with different dimensions\"<\/span>)\n        <span>Else\n            Dim <\/span>result <span>As New <\/span>T()\n            <span>Dim <\/span>temp <span>As New <\/span>T()\n            <span>For <\/span>i = 1 <span>To <\/span>Left.Dimension\n                result = result + Left(i) * <span>Not <\/span>Right(i)<font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n            <span>Next\n            Return <\/span>result\n        <span>End If\n    End Operator\n<\/span><span>...\nEnd Class\n'================================================================<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<pre class=\"code\"><span>Imports <\/span>System.Text\n<span>Public Class <\/span>AMNMatrix(<span>Of <\/span>U, T <span>As <\/span>{<span>New<\/span>, AField(<span>Of <\/span>U)})\n    <span>Private <\/span>mRowCount <span>As Integer\n    Public ReadOnly Property <\/span>Rows() <span>As Integer\n        Get\n            Return <\/span>mRowCount\n        <span>End Get\n    End Property\n    Private <\/span>mColumnCount <span>As Integer\n    Public ReadOnly Property <\/span>Columns() <span>As Integer\n        Get\n            Return <\/span>mColumnCount\n        <span>End Get\n    End Property\n    Private <\/span>mElements <span>As <\/span>T(,)\n    <span>Default Property <\/span>Element(<span>ByVal <\/span>i <span>As Integer<\/span>, <span>ByVal <\/span>j <span>As Integer<\/span>) <span>As <\/span>T\n        <span>Get\n            Return <\/span>mElements(i, j)\n        <span>End Get\n        Set<\/span>(<span>ByVal <\/span>Value <span>As <\/span>T)\n            mElements(i, j) = Value\n        <span>End Set\n    End Property\n<\/span><span>...\n    <\/span><span>'Scale a matrix\n    <\/span><span>Public Shared Operator <\/span>*(<span>ByVal <\/span>scalar <span>As <\/span>T, <span>ByVal <\/span>that <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)) _\n    <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)\n        <span>Dim <\/span>result = <span>New <\/span>AMNMatrix(<span>Of <\/span>U, T)(that)\n        <span>For <\/span>i = 1 <span>To <\/span>that.Rows\n            <span>For <\/span>j = 1 <span>To <\/span>that.Columns\n                result(i, j) = result(i, j) * scalar <font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n            <span>Next\n        Next\n        Return <\/span>result\n    <span>End Operator\n    <\/span><span>'Scale a matrix\n    <\/span><span>Public Shared Operator <\/span>*(<span>ByVal <\/span>that <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T), <span>ByVal <\/span>scalar <span>As <\/span>T) _\n    <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)\n        <span>Return <\/span>scalar * that<font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n    <span>End Operator\n<\/span><span>\n<span><\/span><span>    'Matrix plus matrix <\/span><br \/>    Public Shared Operator <\/span>+(<span>ByVal <\/span>M1 <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T), <span>ByVal <\/span>M2 <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)) _\n    <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)\n        <span>If <\/span>M1.Rows &lt;&gt; M2.Rows <span>Or <\/span>M1.Columns &lt;&gt; M2.Columns <span>Then\n            Throw New <\/span>VectorSpaceException(<span>\"Cannot add matrices of different dimensions\"<\/span>)\n        <span>Else\n            Dim <\/span>result = <span>New <\/span>AMNMatrix(<span>Of <\/span>U, T)(M1)\n            <span>For <\/span>i = 1 <span>To <\/span>M1.Rows\n                <span>For <\/span>j = 1 <span>To <\/span>M1.Columns\n                    result(i, j) = result(i, j) + M2(i, j) <font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n                <span>Next\n            Next\n            Return <\/span>result\n        <span>End If\n    End Operator\n    <\/span><span>'Matrix times a vector\n    <\/span><span>Public Shared Operator <\/span>*(<span>ByVal <\/span>m <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T), <span>ByVal <\/span>v <span>As <\/span>ANVector(<span>Of <\/span>U, T)) _\n    <span>As <\/span>ANVector(<span>Of <\/span>U, T)\n        <span>If <\/span>m.Columns &lt;&gt; v.Dimension <span>Then\n            Throw New <\/span>VectorSpaceException(<span>\"The number of columns in the matrix must equal \" <\/span>&amp; _\n                                           <span>\"the dimension of the vector\"<\/span>)\n        <span>Else\n            Dim <\/span>result = <span>New <\/span>ANVector(<span>Of <\/span>U, T)(m.Rows)\n            <span>For <\/span>i = 1 <span>To <\/span>m.Rows\n                <span>For <\/span>j = 1 <span>To <\/span>m.Columns\n                    result(i) = result(i) + v(j) * m(i, j) <font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n                <span>Next\n            Next\n            Return <\/span>result\n        <span>End If\n    End Operator\n    <\/span><span>'Vector times a Matrix\n    <\/span><span>Public Shared Operator <\/span>*(<span>ByVal <\/span>v <span>As <\/span>ANVector(<span>Of <\/span>U, T), <span>ByVal <\/span>m <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)) _\n    <span>As <\/span>ANVector(<span>Of <\/span>U, T)\n        <span>If <\/span>m.Rows &lt;&gt; v.Dimension <span>Then\n            Throw New <\/span>VectorSpaceException(<span>\"The dimension of the vector must equal\" <\/span>&amp; _\n                                           <span>\"the number of rows in the matrix\"<\/span>)\n        <span>Else\n            Dim <\/span>result = <span>New <\/span>ANVector(<span>Of <\/span>U, T)(m.Columns)\n            <span>For <\/span>j = 1 <span>To <\/span>m.Columns\n                <span>For <\/span>i = 1 <span>To <\/span>m.Rows\n                    result(j) = result(j) + v(i) * m(i, j) <font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n                <span>Next\n            Next\n            Return <\/span>result\n        <span>End If\n    End Operator\n    <\/span><span>'Matrix times Matrix\n    <\/span><span>Public Shared Operator <\/span>*(<span>ByVal <\/span>left <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T), <span>ByVal <\/span>right <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)) _\n    <span>As <\/span>AMNMatrix(<span>Of <\/span>U, T)\n        <span>If <\/span>left.Columns &lt;&gt; right.Rows <span>Then\n            Throw New <\/span>VectorSpaceException(<span>\"The number of columns in the left matrix must equal\" <\/span>&amp; _\n                                           <span>\"The number of rows in the right matrix\"<\/span>)\n        <span>Else\n            Dim <\/span>result = <span>New <\/span>AMNMatrix(<span>Of <\/span>U, T)(left.Rows, right.Columns)\n            <span>Dim <\/span>inner = left.Columns\n            <span>For <\/span>i = 1 <span>To <\/span>result.Rows\n                <span>For <\/span>j = 1 <span>To <\/span>result.Columns\n                    <span>For <\/span>k = 1 <span>To <\/span>inner <font color=\"#008000\">''' OPERATOR OVERLOADS BEING USED<\/font>\n                        result(i, j) = result(i, j) + left(i, k) * right(k, j)\n                    <span>Next\n                Next\n            Next\n            Return <\/span>result\n        <span>End If\n    End Operator\n<\/span><span>...\nEnd Class\n<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>There we go: operator overloading at three levels! I&#8217;ve uploaded a zipped Visual-Studio 2008 project to my <a href=\"http:\/\/wrofeq.bay.livefilestore.com\/y1pi__YcVhyovwgv0CHgXJmFjt5Suuy1lOhmLkGupZ0OLPm-qg22wRIBXV_nF0ezBXytE8OmoLRBRJZImw6Wi0cbw\/LinearAlgebra.zip?download\">Public folder<\/a> with all this code. <br \/>Play around, let me know what you think.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I did a Channel 9 interview with Beth Massi where I walked through a Visual Basic program that used Generics and Operator overloads to perform some higher mathematics. I thought I&#8217;d follow up with a post explaining the details of exactly what I did. Operator overloads with Generics enable some beautiful designs for data [&hellip;]<\/p>\n","protected":false},"author":259,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[192,195],"tags":[40,164,165,166],"class_list":["post-4913","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-featured","category-visual-basic","tag-beth-massi","tag-vb_express","tag-vb2005","tag-vb2008"],"acf":[],"blog_post_summary":"<p>Recently I did a Channel 9 interview with Beth Massi where I walked through a Visual Basic program that used Generics and Operator overloads to perform some higher mathematics. I thought I&#8217;d follow up with a post explaining the details of exactly what I did. Operator overloads with Generics enable some beautiful designs for data [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4913","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/259"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=4913"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4913\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=4913"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=4913"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=4913"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}