Results 1 to 20 of 20

Thread: Should I use a Class or a Structure, (Matrix Tool)

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Should I use a Class or a Structure, (Matrix Tool)

    I made a Class for matrix operations, [MatrixObject]. I am mainly concerned with the inverse; I need to calculate many large matrix inverse's for this application.( size:~[R100xC100])

    Right now the performance for computing the inverse is:

    size:50x50 ---- time:~200ms
    size:100x100 - time:~2.3s
    size:200x200 - time:~29s
    That sounds slow but its not, try beating that without purchasing libraries, its hard...

    I can probably squeeze out a tiny bit more speed by cleaning the loops... But I'm wondering if turning this into a Structure would have major performance gains and makes sense ('would a smarter better looking programmer do this?').

    The matrix code has the following charactistics:
    • Large dynamic array member (for matrix values)
    • Does not include any class members.
    • will be used/declared within a method, copy's made will be minimal.
    • speed of operation is important for the application




    The speed of this inverse calculation is essential to the application but it contains a large dynamic array. The internet says large arrays are a no go for Structs... But are there circumstances where you would use a Struct anyway? Also, what happens if the Struct w/ methods is wrapped in Class?

    My knowledge of stack and heap is to the extent of stuff said in youtube videos. I don't have a deep enough understanding to answer this question.

    I would like to get some more info on exactly what can happen if a structure is too large. Does the complexity of the methods also affect stack usage? Do structures get compiled differently than classes do? (different assembly generated)

    Here as example of the Code

    As a Class (current version)

    Code:
    ' Every thing inside a Class ----------------
    Public Class MatrixObject1
    
        Private Structure Matrix4F_Array
            Dim A() As Matrix4x4
        End Structure
    
        Private m_ROW_Arrays() As Matrix4F_Array    '<-- array of [Matrix4x4] arrays 
        '
        '   m_ROW_Arrays(0)     .A(0)   .A(1)   .A(3)    ...
        '                       M11     M12     M13   
        '   m_ROW_Arrays(1)     .A(0)   .A(1)   .A(3)    ...
        '                       M21     M22     M23 
        '   m_ROW_Arrays(2)     .A(0)   .A(1)   .A(3)    ...
        '         :             M31     M32     M33 
        '         :
    
        Public Sub New()
            '...
        End Sub
    
        Public Shared Function Multiply(ByRef Mat1 As MatrixObject1, ByRef Mat2 As MatrixObject1) As MatrixObject1
            ' ....
        End Function
    
        Public Shared Function Inverse(ByRef i_Mat As MatrixObject1, ByRef success As Boolean) As MatrixObject1
            ' ....
        End Function
    
        ' * also includes propertys for size and shared operators: *,+,-
        '   and misc. functions.
    
    End Class
    As a Structure w/methods, and wrapper Class (for non essiential/slow methods); what i'm considering doing.

    Code:
    ' Structure with only essential, tight functions
    Public Structure MatrixStruct
    
        Private Structure Matrix4F_Array
            Dim A() As Matrix4x4
        End Structure
    
        Private m_ROW_Arrays() As Matrix4F_Array    '<-- array of [Matrix4x4] arrays 
    
        Public Shared Function Multiply(ByRef Mat1 As MatrixStruct, ByRef Mat2 As MatrixStruct) As MatrixStruct
            ' ....
        End Function
    
        Public Shared Function Inverse(ByRef i_Mat As MatrixStruct, ByRef success As Boolean) As MatrixStruct
            ' ....
        End Function
    
    End Structure
    
    
    ' 
    ' Matrix Class that inlcudes [MatrixStruct] member
    '   -Class Methods have error checks and other misc. stuff
    Public Class MatrixObject2
    
        Private m_Struct As MatrixStruct
    
        Public Sub New()
            '...
        End Sub
    
        Public Shared Function Multiply(ByRef Mat1 As MatrixObject2, ByRef Mat2 As MatrixObject2) As MatrixObject2
            ' ....
            Dim ret As New MatrixObject2
            ret.m_Struct = MatrixStruct.Multiply(Mat1.m_Struct, Mat2.m_Struct)
            Return ret
        End Function
    
        '   :
        '   :
        '   :
        ' * also includes propertys for size and shared operators: *,+,-
        '   and misc. functions.
    End Class

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,704

    Re: Should I use a Class or a Structure, (Matrix Tool)

    I don't think turning it into a structure would help any at all, and might end up costing too much. If you make it a structure, it is a value item, which means that if you were to pass it as an argument to a method, you'd be copying in the whole thing. For the larger matrices you are talking about, that could mean a significant chunk of memory being passed around. If you will NEVER pass it as an argument to anything, then you might see some trivial gain, but that's all.
    My usual boring signature: Nothing

  3. #3

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Ok,
    What if the Structure w/ methods is private within a wrapper Class... So that it is controlled and never unnecessarily copied.

    Is that any different then just using a Class?

    All the matrix operations (+,-,*) require scanning through a dynamic array(s), getting and setting values. I'm trying to prevent those arrays from being fragmented.

    Also, saw a video that implied Structures methods generate different, more efficient assembly than Class methods, is that correct?

  4. #4
    Frenzied Member PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Newport, UK
    Posts
    1,927

    Re: Should I use a Class or a Structure, (Matrix Tool)

    I suppose the easiest way would be to try both approaches and time them.

    https://benchmarkdotnet.org/ is a great tool for benchmarking dotnet code.
    Last edited by PlausiblyDamp; Sep 13th, 2022 at 06:32 PM.

  5. #5
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,704

    Re: Should I use a Class or a Structure, (Matrix Tool)

    There are differences between classes and structures, but largely at a level that won't matter much, as far as I am aware. For example, if you have a simple loop in a method, that loop will look the same whether in a class or a structure. How you get to the loop might be different, but the loop won't be, and the cost of the loop will out weigh the differences.

    You ought to test it out, though. Create a simplified version (or not simplified) of both a class and a structure, then call the method over and over in a loop while timing it using a Stopwatch object. I have a test project that I use for that purpose. It has Test1 and Test2, which I call in the order Test1, Test2, Test2, Test1, then show the timing of each. By running those tests a few times, it is possible to see the cost and the variation within the runs. Inside the TextX methods, most timing requires a loop, because any one call can be too fast to time.
    My usual boring signature: Nothing

  6. #6

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    working on it...

  7. #7

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Initial results indicate the Structure w/methods wrapped in a Class is many many times faster.
    I need to verify this with more testing. I'll post the code and performance time when finished.

  8. #8
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    109,066

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Quote Originally Posted by Shaggy Hiker View Post
    For the larger matrices you are talking about, that could mean a significant chunk of memory being passed around.
    Structures are value types but arrays are classes and therefore reference types. Copying a structure that contains an array will not copy the array; only the reference to the array. If you then modify an element in that array in the copy, it will affect the original. If you assign a new array in the copy, that would not affect the original.

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,704

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Quote Originally Posted by jmcilhinney View Post
    Structures are value types but arrays are classes and therefore reference types. Copying a structure that contains an array will not copy the array; only the reference to the array. If you then modify an element in that array in the copy, it will affect the original. If you assign a new array in the copy, that would not affect the original.
    Right. I didn't read the code much at all. For some reason, I was thinking back to a time when a simple matrix (it could ONLY be simple) was built without using arrays. That would be totally unworkable for a matrix of the size described.
    My usual boring signature: Nothing

  10. #10
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,704

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Quote Originally Posted by tonyd5 View Post
    Initial results indicate the Structure w/methods wrapped in a Class is many many times faster.
    I need to verify this with more testing. I'll post the code and performance time when finished.
    That sounds suspicious. Fractionally different would be understandable. Something like this being many times faster sounds like you aren't comparing apples to apples.
    My usual boring signature: Nothing

  11. #11

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Quote Originally Posted by jmcilhinney View Post
    Structures are value types but arrays are classes and therefore reference types. Copying a structure that contains an array will not copy the array; only the reference to the array. If you then modify an element in that array in the copy, it will affect the original. If you assign a new array in the copy, that would not affect the original.
    Yep, figured that out. Had to make copy methods... annoying.
    I made structures with arrays members in another program I'm working on; Did NOT have this problem, arrays members were copied just fine...


    My suspicion is because the array member is nested (array of array's), it copies byref... Because the value of each array item is a pointer to another array, the pointer value gets copied but still points to the same thing.


    Code:
    Public Structure MatrixStruct
    
        Private Structure Matrix4F_Array
            Dim A() As Matrix4x4
        End Structure
    
        Private m_ROW_Arrays() As Matrix4F_Array    '<-- array of [Matrix4x4] arrays 
        '
        '   m_ROW_Arrays(0)	     .A(0)	 .A(1)	    .A(3)    ...
        '                       (4x4)11	(4x4)12	   (4x4)13   
        '   m_ROW_Arrays(1)      .A(0)       .A(1)      .A(3)    ...
        '                       (4x4)21	(4x4)22	   (4x4)23 
        '   m_ROW_Arrays(2)      .A(0)       .A(1)      .A(3)    ...
        '         :             (4x4)31	(4x4)32	   (4x4)33 
        '         :
    
    
        '	:
        '	:
        '	:
    
    End Structure

  12. #12
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,704

    Re: Should I use a Class or a Structure, (Matrix Tool)

    There is no method that can copy classes that is generic enough to use on everything and efficient enough that it is justified, so having people write copy methods, while annoying, is probably a good design decision. Some languages will take other routes, though, if they are willing to make a few sacrifices.
    My usual boring signature: Nothing

  13. #13

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Quote Originally Posted by Shaggy Hiker View Post
    There is no method that can copy classes that is generic enough to use on everything and efficient enough that it is justified, so having people write copy methods, while annoying, is probably a good design decision. Some languages will take other routes, though, if they are willing to make a few sacrifices.
    ... I have made a universial clone function for anything. makes deep sea copys of all members(any type including objects) and can handle arrays of arrays of arrays....

    Its monster, very slow. I only use it as a band aid when I don't want to think.

    Code:
    Public Module UtilitiesXXX
    
    
    
    
        '--- Clone object to get new instance with identical member values ------
        '
        '   returns a new instance of the object
        '
        Public Function clone(Of K)(copyObj As K) As K
    
            Dim newObj As K
    
    
            '--- for cloning arrays -----------------------------
            If copyObj.GetType.IsArray Then
                Dim arrObj As Object = copyObj
    
                Dim tArr As Array = Array.CreateInstance(arrObj(0).GetType, UBound(arrObj) + 1)
    
                '-- for all objects in array clone values -----
                For i As Integer = 0 To UBound(arrObj)
    
                    tArr(i) = clone(arrObj(i))
                Next
                '----------------------------------------------
    
                newObj = CTypeDynamic(tArr, copyObj.GetType)
    
                Return newObj
    
            End If
    
    
            '--- for cloning non-arrays ------------------------
            newObj = get_new_instance_ofObject(newObj, copyObj)
    
            clone_members(newObj, copyObj)
    
            Return newObj
    
        End Function
    
    
    
        '--- returns new instance of Class or Value Type passed in
        Private Function get_new_instance_ofObject(Of K)(ByRef newVal As Object, ByVal of_obj As K) As K
    
            Dim ty As Type = of_obj.GetType
    
    
            If ty.IsArray Then _
                Throw New Exception("attmepting to create of a non array instance of an array object")
    
    
            If ty.IsClass Then _
                Return ty.GetConstructor(New System.Type() {}).Invoke(New K() {})
    
    
            If ty.IsValueType Then _
                Return CTypeDynamic(newVal, ty)
    
    
            Return Nothing
        End Function
    
    
        '--- sets field info value for Classes, Structs, and System types
        '---
        Private Sub SmartSetValue(Of K, T)(finfo As System.Reflection.FieldInfo,
                                           ByRef newObj As K,
                                           copyVal As T)
    
            Dim ty As Type = newObj.GetType
    
            '---- see if type is a standard system type ----
            Dim str As String = "System"
            Dim is_system_type As Boolean =
                    ty.IsPrimitive Or
                    Strings.Left(ty.Namespace, Len(str)) = str Or
                    ty.IsEnum
    
    
            If is_system_type Then
                finfo.SetValue(newObj, copyVal)
                Exit Sub
            End If
    
            '----------------------------------------
    
            If ty.IsClass Then
                finfo.SetValue(newObj, copyVal)
                Exit Sub
            End If
    
            '----------------------------------------
    
            If ty.IsValueType Then
                Dim x As ValueType = CTypeDynamic(newObj, newObj.GetType)
                finfo.SetValue(x, copyVal)
                newObj = CTypeDynamic(x, newObj.GetType)
                Exit Sub
            End If
    
    
    
        End Sub
    
    
    
    
        '--- Clone object (1 member deep) to get new instance with identical member values ------
        '
        '   updates 'newObj' by ref
    
        '   returns True if @ no more seeded members
        '
        Private Sub clone_members(ByRef newObj_ As Object, ByVal baseObj As Object)
    
    
            Dim myObj As New Object            '<-- memeber feild as object
            Dim newObj As Object = newObj_
    
            Dim objType As Type                         '<-- type name for feild             
            Dim fInfo As System.Reflection.FieldInfo    '<-- feild info object
    
    
            Dim fInfo_arr() As System.Reflection.FieldInfo    '<-- feild info object
            Dim newfInfo_arr() As System.Reflection.FieldInfo
    
    
    
            objType = baseObj.GetType()
            fInfo_arr = objType.GetFields()
    
    
    
            For Each fInfo In fInfo_arr
    
    
                myObj = fInfo.GetValue(baseObj)                 '<-- get field object of "baseObj"
    
    
    
                '-- set null values case -----------------
                If IsNothing(myObj) Then
                    SmartSetValue(fInfo, newObj_, myObj)
                    Continue For
                End If
                '-----------------------------------------
    
    
                '-- get reference to 'newObj_' feild  -----
                '-- and Type of 'myObj'
                objType = myObj.GetType
                '-------------------------------------------
    
    
                '--- for standard system types case -------------------
                '------------------------------------------------------
                Dim str As String = "System"
                Dim is_system_type As Boolean =
                    objType.IsPrimitive Or
                    Strings.Left(objType.Namespace, Len(str)) = str Or
                    objType.IsEnum
    
                If is_system_type Then
                    SmartSetValue(fInfo, newObj_, myObj)
                    Continue For
                End If
                '------------------------------------------------------
                '------------------------------------------------------
    
    
                '-- see if member feild is an array -------------------
                '-- if so recall 'clone_members' for all
                '-- objects in array
                If myObj.GetType.IsArray Then
    
                    '-- make sure array is declared ----
                    Try
                        Dim i = UBound(myObj)
                    Catch ex As Exception
                        myObj = Nothing
                        SmartSetValue(fInfo, newObj_, myObj)
                        Continue For
                    End Try
                    '-----------------------------------
    
                    '-- create an array instance for new values --
                    objType = myObj(0).GetType
                    Dim tArr As Array = Array.CreateInstance(objType, UBound(myObj) + 1)
    
    
                    '-- for all objects in array clone values -----
                    For i As Integer = 0 To UBound(myObj)
    
                        tArr(i) = clone(myObj(i))
                    Next
                    '----------------------------------------------
                    SmartSetValue(fInfo, newObj_, tArr)
                    Continue For
    
                End If
                '------------------------------------------------------
                '------------------------------------------------------
    
    
    
    
                '-- see if member feild has seeded values -----
                '-- if so recall 'clone_members' for object 
                newfInfo_arr = objType.GetFields()
                If newfInfo_arr.Length > 0 And Not (IsNothing(newfInfo_arr)) Then
    
                    Dim currObj As New Object
                    currObj = clone(myObj)
    
                    SmartSetValue(fInfo, newObj_, currObj)
                End If
                '-----------------------------------------------
    
    
            Next
    
        End Sub
    
    
    
    End Module

    Current time performance
    50x50: 5ms
    100x100: 50ms
    125x125: 90ms
    150x150: 134ms
    200x200: 290ms (but the result is incorrect, weird)

    ~100x faster.
    Don't know for certain if this is 100% due to the Struct yet.

    I'm still working on this. Adding print functions so I can actually see the Matrix while debugging and write to a CSV... I want it to be nice before posting it.

  14. #14
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,704

    Re: Should I use a Class or a Structure, (Matrix Tool)

    That universal clone won't work for EVERYTHING, it will work for certain things. For example, what happens if the array is an array of Object, where the actual items in the array are a variety of things, such as the first being an integer, the second being a string, and so forth. What type will arrObj(0).GetType return for such an array?

    Another, more contrived, variation would be: What happens if the array is an array of classes that maintain a DB connection? What should the state of those connections be in the cloned array?
    My usual boring signature: Nothing

  15. #15
    Frenzied Member PlausiblyDamp's Avatar
    Join Date
    Dec 2016
    Location
    Newport, UK
    Posts
    1,927

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Quote Originally Posted by tonyd5 View Post
    Don't know for certain if this is 100% due to the Struct yet.

    I'm still working on this. Adding print functions so I can actually see the Matrix while debugging and write to a CSV... I want it to be nice before posting it.
    Looking at this and your original post, I am not convinced that switching between a struct and a class would yield much of a performance difference. If there are speedups to be had they are probably more likely to be found in the implementation of the various methods that manipulate the matricies (Inverse etc.) or in the choice of data structure / access. Arrays and nested arrays can have performance issues depending on how they are accessed , there might be cleaner approaches compared to arrays of arrays perhaps.

  16. #16

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Your suspiscions are correct, The Structure was NOT the cause of the major performance gain... The changing the Structure to a Class was only few % points slower...



    What was change:

    In the old version, in all the matrix operations (+,-,*) the size of the matrix's was checked. Like, before multipling these matrices check that the size's are vaild first... Real quick If statments in every operation method.

    In the new version, A Structure w/ (+,-,*,..) methods was made. These methods did NOT have any if statements... Just assumed the matrices were of correct size and went right into scanning arrays and doing math.
    The Structure was also conertrained to only do operations on (4x4) blocks (Matrix4x4)


    So for the inverse method, which is hundreds of multiplications and adding & subtracting, hundreds of reduntant If statements were no longer executed...

    I don't think the If checks were soaking up time but rather messing up the LUT or whatever... preventing next predictable memory location being ready to go in RAM.

    The structure of arrays was NOT changed.

    The matrix operations (+,-,*) were not changed significantly, other than removing reduntant If statements.

    The biggest change was converting the seocond matrix into Column Major form when multipling, Which may or may not save time.

    The inverse operation was not changed...

    -----------------------

    Whatever, below is the code and Demo. The only problem I encounted is that for matrices >150x150 the inverse because less accurate to invently invalid. Probably because a single does not have precission.
    For example the array is 256x256... =2^16... A float (24b + 8exp), will only have 24b-16b=8b of precision for each value in matrix.


    Demo of [MatrixObject] Class

    Code:
    Module MatrixObject_DEMO_MODULE
    
        Public Sub MatrixObject_demo()
    
    
            '~~~~~~~~   Properties: copy() , matrix_item(,) , row() , col()  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            '~~~~~
            '~~
            Dim x1 As New MatrixObject
            Dim Rsize As Integer
            Dim Csize As Integer
            Dim Rarr() As Single
            Dim Carr() As Single
            Dim valS As Single
    
            x1.matrix_item(row:=1, col:=1) = 11.0!
            x1.matrix_item(row:=1, col:=2) = 12.0!
            x1.matrix_item(row:=1, col:=3) = 13.0!
    
            Rsize = x1.RowSize
            Csize = x1.ColSize
            Rarr = x1.row(1)
            Carr = x1.col(3)
    
            x1.matrix_item(row:=2, col:=3) = 23.0!
            x1.matrix_item(row:=2, col:=4) = 24.0!
            x1.Print2Console()       '<-- prints to debug output when in debug mode
    
    
            For i As Integer = 1 To x1.RowSize
                Rarr = x1.row(i)
            Next
    
            For i As Integer = 1 To x1.ColSize
                Carr = x1.col(i)
            Next
    
            x1.row(1) = New Single() {11, 12, 13, 14, 15, 16}
            x1.row(2) = New Single() {21, 22, 23, 24, 25, 26}
            x1.row(3) = New Single() {31, 32, 33, 34, 35, 36}
            x1.row(4) = New Single() {41, 42, 43, 44, 45, 46}
            x1.col(7) = New Single() _
                {17,
                27,
                37,
                47}
    
            x1.Print2Console()
    
            Dim xCopy As MatrixObject = x1.copy
            xCopy *= 100
            xCopy.RowSize = 3
            '
            For i As Integer = 1 To xCopy.RowSize
                For j As Integer = 1 To xCopy.ColSize
                    valS = xCopy.matrix_item(i, j)
                Next
            Next
    
            Console.WriteLine("xCopy")
            xCopy.Print2Console()
            '
            Console.WriteLine("x1")
            x1.Print2Console()
    
    
            '~~~~~~~~   Operators: + , - , *    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            '~~~~~
            '~~
    
            ' add, subtract, scaler multiple --------------------------
            Dim x2 As New MatrixObject
            Dim x3 As New MatrixObject
            Dim x4 As New MatrixObject
            Dim x5 As New MatrixObject
            Dim x6 As New MatrixObject
            Dim x7 As New MatrixObject
            '
            x2.row(1) = New Single() {10, 10, 10, 10, 10, 10}
            x2.row(2) = New Single() {20, 20, 20, 20, 20, 20}
            x2.row(3) = New Single() {30, 30, 30, 30, 30, 30}
            x2.row(4) = New Single() {40, 40, 40, 40, 40, 40}
            '
            x3.row(1) = New Single() {1, 2, 3, 4, 5, 6}
            x3.row(2) = New Single() {1, 2, 3, 4, 5, 6}
            x3.row(3) = New Single() {1, 2, 3, 4, 5, 6}
            x3.row(4) = New Single() {1, 2, 3, 4, 5, 6}
    
            x4 = x2 + x3
            Console.WriteLine("x4")
            x4.Print2Console()
    
            ' x5=x4 * 4
            x5 = x4.copy
            x5 = x5 + x4
            x5 += x4
            x5 = MatrixObject.Add(x5, x4)
            Console.WriteLine("x5")
            x5.Print2Console()
    
            ' x6=x4 * 4
            x6 = x4 * 1.0!
            x6 *= 2.0!
            x6 = MatrixObject.Multiply(x6, 2.0!)
            Console.WriteLine("x6")
            x6.Print2Console()
    
            x7 = x6 - x5
            x7 = MatrixObject.Subtract(x7, x5)
            x7 -= (x5 * (-1.0!))
            Console.WriteLine("x7")
            x7.Print2Console()
    
    
    
            ' matrix multiply ---------------------------------------
            x2 = New MatrixObject
            x3 = New MatrixObject
            '
            x2.row(1) = New Single() {1, 2, 3}
            x3.col(1) = New Single() {1, 2, 3}
            x4 = x2 * x3
            Console.WriteLine("x4")
            x4.Print2Console()
    
            '----
    
            x2 = New MatrixObject
            x3 = New MatrixObject
            '
            x2.row(1) = New Single() {2, 2, 2, 2}
            x2.row(2) = New Single() {3, 3, 3, 3}
            '
            x3.col(1) = New Single() {1, 2, 3, 4}
            x3.col(2) = New Single() {1, 2, 3, 4}
    
            x4 = x2 * x3
            Console.WriteLine("x4")
            x4.Print2Console()
    
            '~~~~~~~~   Methods: Transpose(), Invert(), CSV_view()   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            '~~~~~
            '~~
    
            ' Transpose() --------------------------------------
    
            x1 = New MatrixObject
            x2 = New MatrixObject
    
            x1.row(1) = New Single() {11, 12, 13, 14, 15, 16}
            x1.row(2) = New Single() {21, 22, 23, 24, 25, 26}
            x1.row(3) = New Single() {31, 32, 33, 34, 35, 36}
            x1.row(4) = New Single() {41, 42, 43, 44, 45, 46}
    
            x2 = x1.Transpose
            Console.WriteLine("x1")
            x1.Print2Console()
            '
            Console.WriteLine("transpose")
            x2.Print2Console()
    
            ' Invert() -----------------------------------------
    
            Dim startSize As Integer = 40
            Dim endSize As Integer = 160
            Dim stepSize As Integer = 20
    
            Dim durrMS() As Single : ReDim durrMS(0)
            Dim matCNT() As Single : ReDim matCNT(0)
            Dim k As Integer = 0
    
            Dim Xmat As New MatrixObject
            Dim Ymat As New MatrixObject
            Dim Zmat As New MatrixObject
    
            For currSize As Integer = startSize To endSize Step stepSize
    
                'MatrixObject.m_dummy = 0
    
                Xmat.Size = currSize
    
                For i As Integer = 1 To currSize
                    For j As Integer = 1 To currSize
                        Xmat.matrix_item(i, j) = CInt((Rnd()) * endSize)
                    Next
                Next
    
                Dim timer As New System.Diagnostics.Stopwatch
    
                Dim success As Boolean
    
                timer.Start()
                Ymat = Xmat.Invert(success)
                timer.Stop()
    
                If success = False Then
                    MsgBox("unable to find inverse")
                End If
    
                'Zmat = Ymat * Xmat
                'Console.WriteLine("XMAT")
                'Xmat.Print2Console("G2")
                'Console.WriteLine("YMAT")
                'Ymat.Print2Console("G2")
                'Console.WriteLine("ZMAT")
                'Zmat.Print2Console("G2")
    
                ReDim Preserve durrMS(k)
                ReDim Preserve matCNT(k)
                durrMS(k) = timer.ElapsedMilliseconds
                matCNT(k) = currSize
                k += 1
    
            Next
    
            Zmat = Ymat * Xmat
            Console.WriteLine("XMAT")
            Xmat.Print2Console("G2")
            Console.WriteLine("YMAT")
            Ymat.Print2Console("G2")
            Console.WriteLine("ZMAT")
            Zmat.Print2Console("G2")
    
            ' create CSV of Inverse*MAT, should equal Identity matrix
            Zmat.ToCSV(filename:="newCSV")
    
            ' create CSV of performance results
            Dim prfrmnceMAT As New MatrixObject
            prfrmnceMAT.col(1) = matCNT
            prfrmnceMAT.col(2) = durrMS
            prfrmnceMAT.ToCSV(filename:="MatrixDemo_InvertPerformance")
    
        End Sub
    
    End Module

  17. #17

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Could not fit everything in 1 post....

    Code for Structure & Class

    Code:
    Imports System.Numerics
    
    
    Imports System.Runtime.InteropServices
    
    
    ' Structure with only essential, tight functions
    Public Structure MatrixStruct
    
        Public Structure Matrix4F_Array
            Dim A() As Matrix4x4
        End Structure
    
        Private m_ROW_Arrays() As Matrix4F_Array    '<-- array of [Matrix4x4] arrays 
    
        Private p_BR_size As Integer
        Private p_BC_size As Integer
    
    
        Public Sub setSize(RowBlck_sz As Integer, ColBlck_sz As Integer)
    
            If Me.p_BR_size < 1 Then
                ReDim Me.m_ROW_Arrays(0)
                ReDim Me.m_ROW_Arrays(0).A(0)
            End If
    
            Dim chg_row As Boolean = False
            Dim chg_col As Boolean = False
    
            If Me.p_BR_size <> RowBlck_sz Then
                chg_row = True
                If Me.p_BR_size < RowBlck_sz Then
                    chg_col = True
                End If
            End If
            '
            If Me.p_BC_size <> ColBlck_sz Then
                chg_col = True
            End If
    
    
            If chg_row Then
                Me.p_BR_size = RowBlck_sz
                ReDim Preserve Me.m_ROW_Arrays(Me.p_BR_size - 1)
            End If
    
            If chg_col Then
                Me.p_BC_size = ColBlck_sz
                For i As Integer = 0 To Me.p_BR_size - 1
                    ReDim Preserve Me.m_ROW_Arrays(i).A(Me.p_BC_size - 1)
                Next
            End If
    
        End Sub
    
    
        Public Function RowBlockSize() As Integer
            Return Me.p_BR_size
        End Function
    
        Public Function ColBlockSize() As Integer
            Return Me.p_BC_size
        End Function
    
    
        Public Property MatBlock(rowb As Integer, colb As Integer) As Matrix4x4
            Get
                Return Me.m_ROW_Arrays(rowb - 1).A(colb - 1)
            End Get
            Set(value As Matrix4x4)
                Me.m_ROW_Arrays(rowb - 1).A(colb - 1) = value
            End Set
        End Property
    
    
        Public Function copy() As MatrixStruct
            Dim o_res = New MatrixStruct
            o_res.setSize(Me.p_BR_size, Me.p_BC_size)
    
            For i As Integer = 0 To Me.p_BR_size - 1
                o_res.m_ROW_Arrays(i).A = Me.m_ROW_Arrays(i).A.Clone
            Next
            Return o_res
        End Function
    
    
        Private Property row_BLOCKS(i As Integer) As Matrix4x4()
            Get
                Return Me.m_ROW_Arrays(i - 1).A
            End Get
            Set(value As Matrix4x4())
                Me.m_ROW_Arrays(i - 1).A = value
            End Set
        End Property
    
    
    
        Private Property col_BLOCKS(i As Integer) As Matrix4x4()
            Get
                Dim ret() As Matrix4x4 : ReDim ret(p_BR_size - 1)
                For j As Integer = 0 To (p_BR_size - 1)
                    ret(j) = Me.m_ROW_Arrays(j).A(i - 1)
                Next
                Return ret
            End Get
            Set(value As Matrix4x4())
                For j As Integer = 0 To (p_BR_size - 1)
                    Me.m_ROW_Arrays(j).A(i - 1) = value(j)
                Next
            End Set
        End Property
    
        ' Public Operator Methods ===========================================
    
        Public Shared Function Multiply(ByRef Mat1 As MatrixStruct, ByRef Mat2 As MatrixStruct) As MatrixStruct
    
            Dim row_len As Integer = Mat1.p_BR_size - 1
            Dim col_len As Integer = Mat2.p_BC_size - 1
            Dim len2 As Integer = Mat1.p_BC_size
    
            Dim o_RES As New MatrixStruct
            ReDim o_RES.m_ROW_Arrays(row_len)
            For i As Integer = 0 To row_len
                ReDim o_RES.m_ROW_Arrays(i).A(col_len)
            Next
            '
            o_RES.p_BR_size = row_len + 1
            o_RES.p_BC_size = col_len + 1
    
            Dim col_MAJOR As New MatrixStruct
            ReDim col_MAJOR.m_ROW_Arrays(col_len)
            For i As Integer = 1 To (col_len + 1)
                col_MAJOR.row_BLOCKS(i) = Mat2.col_BLOCKS(i)
            Next
    
    
            Dim r As Integer = 0
            For Each row_ARRAY As Matrix4F_Array In Mat1.m_ROW_Arrays
                Dim c As Integer = 0
                For Each col_ARRAY As Matrix4F_Array In col_MAJOR.m_ROW_Arrays
    
                    o_RES.m_ROW_Arrays(r).A(c) = MatrixStruct.DOTproduct(row_ARRAY.A, col_ARRAY.A, len2)
                    c += 1
                Next
                r += 1
            Next
            Return o_RES
        End Function
    
    
        Public Shared Function MultiplyScaler(ByRef Mat1 As MatrixStruct, ByRef S As Single) As MatrixStruct
    
            Dim o_RES As MatrixStruct = Mat1.copy
    
            Dim r As Integer = 0
            For Each row_ARRAY As Matrix4F_Array In o_RES.m_ROW_Arrays
                Dim c As Integer = 0
                For Each col_MAT As Matrix4x4 In row_ARRAY.A
                    o_RES.m_ROW_Arrays(r).A(c) = Matrix4x4.Multiply(col_MAT, S)
                    c += 1
                Next
                r += 1
            Next
            Return o_RES
        End Function
    
    
        Public Shared Function Add(ByRef Mat1 As MatrixStruct, ByRef Mat2 As MatrixStruct) As MatrixStruct
            Dim o_RES As MatrixStruct = Mat1.copy
            For i As Integer = 0 To o_RES.p_BR_size - 1
                o_RES.m_ROW_Arrays(i).A = MatrixStruct.ADDvector(Mat1.m_ROW_Arrays(i).A, Mat2.m_ROW_Arrays(i).A, o_RES.p_BC_size)
            Next
            Return o_RES
        End Function
    
        Public Shared Function Subtract(ByRef Mat1 As MatrixStruct, ByRef Mat2 As MatrixStruct) As MatrixStruct
            Dim o_RES As MatrixStruct = Mat1.copy
            For i As Integer = 0 To o_RES.p_BR_size - 1
                o_RES.m_ROW_Arrays(i).A = MatrixStruct.SUBTRACTvector(Mat1.m_ROW_Arrays(i).A, Mat2.m_ROW_Arrays(i).A, o_RES.p_BC_size)
            Next
            Return o_RES
        End Function
    
    
    
        Public Shared Sub Inverse(ByRef i_Mat As MatrixStruct, ByRef invA As MatrixStruct, ByRef success As Boolean)
    
            Dim N_blocks As Integer = i_Mat.p_BR_size
            Dim B As MatrixStruct
            Dim C As MatrixStruct
            Dim D As MatrixStruct
    
            Dim x1 As MatrixStruct
            Dim x2 As MatrixStruct
            Dim x3 As MatrixStruct
            Dim x4 As MatrixStruct
    
            ReDim invA.m_ROW_Arrays(0)
            ReDim invA.m_ROW_Arrays(0).A(0)
            invA.p_BR_size = 1
            invA.p_BC_size = 1
    
            success = Matrix4x4.Invert(i_Mat.m_ROW_Arrays(0).A(0), invA.m_ROW_Arrays(0).A(0))
            If success = False Then Exit Sub
    
    
            For i As Integer = 2 To N_blocks
    
                B = MatrixStruct.get_sub_BLOCKS(i_Mat, 1, i, i - 1, i)
                C = MatrixStruct.get_sub_BLOCKS(i_Mat, i, 1, i, i - 1)
                D = MatrixStruct.get_sub_BLOCKS(i_Mat, i, i, i, i)
    
                x4 = MatrixStruct.Multiply(invA, B)
                x4 = MatrixStruct.Multiply(C, x4)
                x4 = MatrixStruct.Subtract(D, x4)
                success = Matrix4x4.Invert(x4.m_ROW_Arrays(0).A(0), x4.m_ROW_Arrays(0).A(0))
                If success = False Then Exit Sub
    
                '----------------------------------------
    
                x1 = MatrixStruct.Multiply(x4, C)
                x1 = MatrixStruct.Multiply(x1, invA)
                x1 = MatrixStruct.Multiply(B, x1)
                x1 = MatrixStruct.Multiply(invA, x1)
                x1 = MatrixStruct.Add(invA, x1)
    
                '----------------------------------------
    
                x2 = MatrixStruct.Multiply(B, x4)
                x2 = MatrixStruct.Multiply(invA, x2)
                x2 = MatrixStruct.MultiplyScaler(x2, -1.0!)
    
                '----------------------------------------
    
                x3 = MatrixStruct.MultiplyScaler(x4, -1.0!)
                x3 = MatrixStruct.Multiply(x3, C)
                x3 = MatrixStruct.Multiply(x3, invA)
    
                '----------------------------------------
    
                invA = x1
                invA.p_BR_size = x1.p_BR_size + 1
                invA.p_BC_size = x1.p_BC_size + 1
    
                ReDim Preserve invA.m_ROW_Arrays(invA.p_BR_size - 1)
                invA.m_ROW_Arrays(invA.p_BR_size - 1) = x3.m_ROW_Arrays(0)
    
                For j As Integer = 0 To (invA.p_BR_size - 2)
                    ReDim Preserve invA.m_ROW_Arrays(j).A(invA.p_BC_size - 1)
                    invA.m_ROW_Arrays(j).A(invA.p_BC_size - 1) = x2.m_ROW_Arrays(j).A(0)
                Next
    
                ReDim Preserve invA.m_ROW_Arrays(invA.p_BR_size - 1).A(invA.p_BC_size - 1)
                invA.m_ROW_Arrays(invA.p_BR_size - 1).A(invA.p_BC_size - 1) = x4.m_ROW_Arrays(0).A(0)
    
                '    _     _   __
                '   |       | |  |
                '   |   X1  | |x2|
                '   |_     _| |__|
                '    _     _   __
                '   |_  x3 _| |x4|
                '
            Next
    
        End Sub
    
        '=== private methods used by operators ================================
    
        Private Shared Function DOTproduct(ByRef x1() As Matrix4x4, ByRef x2() As Matrix4x4, ByRef len As Integer) As Matrix4x4
            Dim res As New Matrix4x4
            For i As Integer = 0 To len - 1
                res = Matrix4x4.Add(res, Matrix4x4.Multiply(x1(i), x2(i)))
            Next
            Return res
        End Function
    
    
        Private Shared Function ADDvector(ByRef x1() As Matrix4x4, ByRef x2() As Matrix4x4, ByRef len As Integer) As Matrix4x4()
            Dim res() As Matrix4x4 : ReDim res(len - 1)
            For i As Integer = 0 To len - 1
                res(i) = Matrix4x4.Add(x1(i), x2(i))
            Next
            Return res
        End Function
    
        Private Shared Function SUBTRACTvector(ByRef x1() As Matrix4x4, ByRef x2() As Matrix4x4, ByRef len As Integer) As Matrix4x4()
            Dim res() As Matrix4x4 : ReDim res(len - 1)
            For i As Integer = 0 To len - 1
                res(i) = Matrix4x4.Subtract(x1(i), x2(i))
            Next
            Return res
        End Function
    
    
    
        Private Shared Function get_sub_BLOCKS(ByRef i_MAT As MatrixStruct,
                                               ByRef i_row_block1 As Integer, ByRef i_col_block1 As Integer,
                                               ByRef i_row_block2 As Integer, ByRef i_col_block2 As Integer) As MatrixStruct
    
            Dim row_len As Integer = i_row_block2 - i_row_block1
            Dim col_len As Integer = i_col_block2 - i_col_block1
    
            Dim o_RES As New MatrixStruct
            ReDim o_RES.m_ROW_Arrays(row_len)
            For i As Integer = 0 To row_len
                ReDim o_RES.m_ROW_Arrays(i).A(col_len)
            Next
            o_RES.p_BR_size = row_len + 1
            o_RES.p_BC_size = col_len + 1
    
            Dim r As Integer = 0
            For i As Integer = (i_row_block1 - 1) To (i_row_block2 - 1)
    
                Dim c As Integer = 0
                For j As Integer = (i_col_block1 - 1) To (i_col_block2 - 1)
    
                    o_RES.m_ROW_Arrays(r).A(c) = i_MAT.m_ROW_Arrays(i).A(j)
                    c += 1
                Next
                r += 1
            Next
    
            Return o_RES
        End Function
    
    
    End Structure

  18. #18

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Wrapper Class..

    Code:
    ' Matrix wrapper Class, uses MatrixStruct
    ' has methods and properties that allow matrix to be easily edited and viewed by user
    Public Class MatrixObject
    
        Private m_Struct As MatrixStruct
    
        Private p_R_size As Integer
        Private p_C_size As Integer
    
        Public Sub New()
            Me.m_Struct = New MatrixStruct
            Me.m_Struct.setSize(0, 0)
            '
            Me.p_R_size = 0
            Me.p_C_size = 0
        End Sub
    
    
        Public Function copy() As MatrixObject
            Dim ret As New MatrixObject
    
            ret.m_Struct = Me.m_Struct.copy
            '
            ret.p_R_size = Me.p_R_size
            ret.p_C_size = Me.p_C_size
            Return ret
        End Function
    
    
    
        Public Property RowSize() As Integer
            Get
                Return Me.p_R_size
            End Get
            Set(value As Integer)
    
                Me.p_R_size = value
                Dim a As Integer
                Dim v As Integer
                MatrixObject.index2_block(value, a, v)
                Me.m_Struct.setSize(a, Me.m_Struct.ColBlockSize)
    
                For j As Integer = 1 To (Me.m_Struct.ColBlockSize)
                    MatrixObject.keep_rows(v, Me.m_Struct.MatBlock(a, j))
                Next
    
            End Set
        End Property
    
    
        Public Property ColSize() As Integer
            Get
                Return Me.p_C_size
            End Get
            Set(value As Integer)
    
                Me.p_C_size = value
    
                Dim a As Integer
                Dim v As Integer
                MatrixObject.index2_block(value, a, v)
                Me.m_Struct.setSize(Me.m_Struct.RowBlockSize, a)
    
                For j As Integer = 1 To (Me.m_Struct.RowBlockSize)
                    MatrixObject.keep_cols(v, Me.m_Struct.MatBlock(j, a))
                Next
    
            End Set
        End Property
    
    
        Public Property Size() As Integer
            Get
                If Me.RowSize <> Me.ColSize Then
                    Return -1
                Else
                    Return Me.RowSize
                End If
            End Get
            Set(value As Integer)
                Me.RowSize = value
                Me.ColSize = value
            End Set
        End Property
    
    
    
        Private Property prv_matrix_item(row As Integer, col As Integer) As Single
            Get
                Dim rowB As Integer
                Dim colB As Integer
                Dim rowV As Integer
                Dim colV As Integer
    
                MatrixObject.index2_block(row, rowB, rowV)
                MatrixObject.index2_block(col, colB, colV)
    
                Dim ret As Single
                MatrixObject.Matrix4x4_value_IO(MAT4x4_IO.GET_, rowV, colV, Me.m_Struct.MatBlock(rowB, colB), ret)
                Return ret
    
            End Get
            Set(value As Single)
    
                Dim rowB As Integer
                Dim colB As Integer
                Dim rowV As Integer
                Dim colV As Integer
    
                MatrixObject.index2_block(row, rowB, rowV)
                MatrixObject.index2_block(col, colB, colV)
    
                MatrixObject.Matrix4x4_value_IO(MAT4x4_IO.SET_, rowV, colV, Me.m_Struct.MatBlock(rowB, colB), value)
            End Set
        End Property
    
    
    
        Public Property matrix_item(row As Integer, col As Integer) As Single
            Get
    
                If row > Me.RowSize Then Return 0
                If col > Me.ColSize Then Return 0
    
                Return Me.prv_matrix_item(row, col)
            End Get
            Set(value As Single)
    
                If Me.RowSize < row Then Me.RowSize = row
                If Me.ColSize < col Then Me.ColSize = col
    
                Me.prv_matrix_item(row, col) = value
            End Set
        End Property
    
    
    
    
        Public Property row(i As Integer) As Single()
            Get
                Dim array As Single()
                If i < 1 Then Return array
                If Me.RowSize < i Then Return array
                If Me.ColSize < 1 Then Return array
    
                ReDim array(Me.ColSize - 1)
                For j As Integer = 1 To Me.ColSize
                    array(j - 1) = Me.prv_matrix_item(i, j)
                Next
                Return array
            End Get
            Set(value As Single())
    
                If i < 1 Then Exit Property
                If Me.RowSize < i Then Me.RowSize = i
                If Me.ColSize < value.Length Then Me.ColSize = value.Length
    
                For j As Integer = 1 To value.Length
                    Me.prv_matrix_item(i, j) = value(j - 1)
                Next
            End Set
        End Property
    
    
        Public Property col(i As Integer) As Single()
            Get
                Dim array As Single()
                If i < 1 Then Return array
                If Me.ColSize < i Then Return array
                If Me.RowSize < 1 Then Return array
    
                ReDim array(Me.RowSize - 1)
                For j As Integer = 1 To Me.RowSize
                    array(j - 1) = Me.prv_matrix_item(j, i)
                Next
                Return array
            End Get
            Set(value As Single())
    
                If i < 1 Then Exit Property
                If Me.ColSize < i Then Me.ColSize = i
                If Me.RowSize < value.Length Then Me.RowSize = value.Length
    
                For j As Integer = 1 To value.Length
                    Me.prv_matrix_item(j, i) = value(j - 1)
                Next
    
            End Set
        End Property
    
    
    
        Public Shared Function Multiply(ByRef i_MatObj1 As MatrixObject, ByRef i_MatObj2 As MatrixObject) As MatrixObject
    
            If i_MatObj1.RowSize < 1 Then Return New MatrixObject
            If i_MatObj2.RowSize < 1 Then Return New MatrixObject
            If i_MatObj1.ColSize < 1 Then Return New MatrixObject
            If i_MatObj2.ColSize < 1 Then Return New MatrixObject
            If i_MatObj1.ColSize <> i_MatObj2.RowSize Then Return New MatrixObject
    
            Dim o_res As New MatrixObject
            o_res.m_Struct = MatrixStruct.Multiply(i_MatObj1.m_Struct, i_MatObj2.m_Struct)
    
            o_res.RowSize = i_MatObj1.RowSize
            o_res.ColSize = i_MatObj2.ColSize
            Return o_res
        End Function
    
    
    
        Public Shared Function Multiply(ByRef i_MatObj As MatrixObject, ByRef C As Single) As MatrixObject
    
            If i_MatObj.RowSize < 1 Then Return New MatrixObject
            If i_MatObj.ColSize < 1 Then Return New MatrixObject
    
            Dim o_res As New MatrixObject
            o_res.m_Struct = MatrixStruct.MultiplyScaler(i_MatObj.m_Struct, C)
    
            o_res.RowSize = i_MatObj.RowSize
            o_res.ColSize = i_MatObj.ColSize
            Return o_res
        End Function
    
    
        Public Shared Function Add(ByRef i_MatObj1 As MatrixObject, ByRef i_MatObj2 As MatrixObject) As MatrixObject
    
            If i_MatObj1.RowSize < 1 Then Return New MatrixObject
            If i_MatObj1.ColSize < 1 Then Return New MatrixObject
            If i_MatObj1.RowSize <> i_MatObj2.RowSize Then Return New MatrixObject
            If i_MatObj1.ColSize <> i_MatObj2.ColSize Then Return New MatrixObject
    
            Dim o_res As New MatrixObject
            o_res.m_Struct = MatrixStruct.Add(i_MatObj1.m_Struct, i_MatObj2.m_Struct)
    
            o_res.RowSize = i_MatObj1.RowSize
            o_res.ColSize = i_MatObj1.ColSize
            Return o_res
        End Function
    
    
        Public Shared Function Subtract(ByRef i_MatObj1 As MatrixObject, ByRef i_MatObj2 As MatrixObject) As MatrixObject
    
            If i_MatObj1.RowSize < 1 Then Return New MatrixObject
            If i_MatObj1.ColSize < 1 Then Return New MatrixObject
            If i_MatObj1.RowSize <> i_MatObj2.RowSize Then Return New MatrixObject
            If i_MatObj1.ColSize <> i_MatObj2.ColSize Then Return New MatrixObject
    
            Dim o_res As New MatrixObject
            o_res.m_Struct = MatrixStruct.Subtract(i_MatObj1.m_Struct, i_MatObj2.m_Struct)
    
            o_res.RowSize = i_MatObj1.RowSize
            o_res.ColSize = i_MatObj1.ColSize
            Return o_res
        End Function
    
    
        Public Shared Operator *(A1 As MatrixObject, A2 As MatrixObject) As MatrixObject
            Return MatrixObject.Multiply(A1, A2)
        End Operator
    
    
        Public Shared Operator *(A1 As MatrixObject, x As Single) As MatrixObject
            Return MatrixObject.Multiply(A1, x)
        End Operator
    
    
        Public Shared Operator +(A1 As MatrixObject, A2 As MatrixObject) As MatrixObject
            Return MatrixObject.Add(A1, A2)
        End Operator
    
    
    
        Public Shared Operator -(A1 As MatrixObject, A2 As MatrixObject) As MatrixObject
            Return MatrixObject.Subtract(A1, A2)
        End Operator
    
    
    
        Public Shared Function Invert(ByRef i_MAT As MatrixObject, ByRef o_res As MatrixObject) As Boolean
    
            If i_MAT.RowSize < 1 Then o_res = New MatrixObject : Return False
            If i_MAT.RowSize <> i_MAT.ColSize Then o_res = New MatrixObject : Return False
    
            Dim org_size As Integer = i_MAT.Size
    
            i_MAT.Size = i_MAT.m_Struct.RowBlockSize * 4%
    
            ' make extra row/cols identity
            For j As Integer = (org_size + 1) To i_MAT.Size
                i_MAT.matrix_item(j, j) = 1
            Next
    
            o_res = New MatrixObject
            Dim success As Boolean
    
            MatrixStruct.Inverse(i_MAT.m_Struct, o_res.m_Struct, success)
    
            i_MAT.Size = org_size
            If success Then o_res.Size = org_size
    
            Return success
        End Function
    
    
        Public Function Invert(ByRef success As Boolean) As MatrixObject
            Dim o_res As MatrixObject
            success = MatrixObject.Invert(Me, o_res)
            Return o_res
        End Function
    
    
        '' --https://www.youtube.com/watch?v=vGowBXcur1k
        ''
        Public Function Transpose() As MatrixObject
    
            Dim newObj As New MatrixObject
    
            newObj.m_Struct.setSize(Me.m_Struct.ColBlockSize, Me.m_Struct.RowBlockSize)
    
            For i As Integer = 1 To Me.m_Struct.RowBlockSize
                For j As Integer = 1 To Me.m_Struct.ColBlockSize
                    newObj.m_Struct.MatBlock(j, i) = Matrix4x4.Transpose(Me.m_Struct.MatBlock(i, j))
                Next
            Next
    
            newObj.RowSize = Me.ColSize
            newObj.ColSize = Me.RowSize
            Return newObj
    
        End Function
    
    
    
    
        Private Shared Sub index2_block(ByRef i_index As Integer, ByRef o_array4x4 As Integer, ByRef o_vector4x4 As Integer)
    
            If i_index < 1 Then o_array4x4 = 0 : o_vector4x4 = 0 : Exit Sub
    
            Dim n As Integer = (i_index - 1) \ 4%
            o_array4x4 = n + 1
            o_vector4x4 = i_index - (n) * 4%
    
        End Sub
    
    
        Private Shared Sub keep_rows(ByRef i_row As Integer, ByRef io_MAT As Matrix4x4)
            If i_row = 4 Then Exit Sub
            If i_row = 0 Then io_MAT = New Matrix4x4
            io_MAT = Matrix4x4.Multiply(c_Identity(i_row), io_MAT)
        End Sub
    
        Private Shared Sub keep_cols(ByRef i_col As Integer, ByRef io_MAT As Matrix4x4)
            If i_col = 4 Then Exit Sub
            If i_col = 0 Then io_MAT = New Matrix4x4
            io_MAT = Matrix4x4.Multiply(io_MAT, c_Identity(i_col))
        End Sub
    
    
        Private Shared ReadOnly c_Identity() As Matrix4x4 = New Matrix4x4() {
            New Matrix4x4 With {.M11 = 1, .M22 = 1, .M33 = 1, .M44 = 1},
            New Matrix4x4 With {.M11 = 1, .M22 = 0, .M33 = 0, .M44 = 0},
            New Matrix4x4 With {.M11 = 1, .M22 = 1, .M33 = 0, .M44 = 0},
            New Matrix4x4 With {.M11 = 1, .M22 = 1, .M33 = 1, .M44 = 0},
            New Matrix4x4 With {.M11 = 1, .M22 = 1, .M33 = 1, .M44 = 1}}
    
    
    
    
        Private Shared Sub Matrix4x4_value_IO(ByRef i_GetSet As MAT4x4_IO,
                                              ByRef i_row As Integer, ByRef i_col As Integer,
                                              ByRef io_MAT As Matrix4x4, ByRef io_val As Single)
    
            Select Case i_row
    
                '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                Case 1
                    Select Case i_col
                        Case 1
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M11 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M11 : Exit Sub
                            End Select
                        Case 2
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M12 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M12 : Exit Sub
                            End Select
                        Case 3
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M13 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M13 : Exit Sub
                            End Select
                        Case 4
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M14 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M14 : Exit Sub
                            End Select
                    End Select
                    '------------------------------------
    
                '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                Case 2
                    Select Case i_col
                        Case 1
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M21 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M21 : Exit Sub
                            End Select
                        Case 2
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M22 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M22 : Exit Sub
                            End Select
                        Case 3
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M23 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M23 : Exit Sub
                            End Select
                        Case 4
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M24 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M24 : Exit Sub
                            End Select
                    End Select
                    '------------------------------------
    
                    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                Case 3
                    Select Case i_col
                        Case 1
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M31 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M31 : Exit Sub
                            End Select
                        Case 2
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M32 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M32 : Exit Sub
                            End Select
                        Case 3
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M33 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M33 : Exit Sub
                            End Select
                        Case 4
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M34 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M34 : Exit Sub
                            End Select
                    End Select
                    '------------------------------------
    
                '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                Case 4
                    Select Case i_col
                        Case 1
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M41 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M41 : Exit Sub
                            End Select
                        Case 2
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M42 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M42 : Exit Sub
                            End Select
                        Case 3
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M43 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M43 : Exit Sub
                            End Select
                        Case 4
                            Select Case i_GetSet
                                Case MAT4x4_IO.SET_ : io_MAT.M44 = io_val : Exit Sub
                                Case MAT4x4_IO.GET_ : io_val = io_MAT.M44 : Exit Sub
                            End Select
                    End Select
                    '------------------------------------
    
            End Select
    
        End Sub
    
        Private Enum MAT4x4_IO
            NA = 0
            SET_ = 1
            GET_ = 2
        End Enum
    
    
        ' Matrix View/String Convert methods ==================================================
    
        Public Shared Narrowing Operator CType(ByVal MatObj As MatrixObject) As String
            Return MatObj.ToString("G3")
        End Operator
    
    
        Public Sub Print2Console(Optional format As String = "G")
            Static k As Integer = 0
            If k = 0 Then
                k = 1
                Win32.AllocConsole()
            End If
            Console.WriteLine(Me.ToString(format))
        End Sub
    
    
    
        Public Overloads Function ToString(Optional format As String = "") As String
    
            Dim maxlen As Integer = Me.MaxStringLength(format)
    
            Dim val As Single
            Dim str As String
            Dim len As Integer
    
            Dim ret_str As String = ""
            For i As Integer = 1 To Me.RowSize
                For j As Integer = 1 To Me.ColSize
    
                    val = Me.matrix_item(i, j)
                    str = val.ToString(format)
    
                    len = str.Length
                    Do While len < maxlen
                        str &= " "
                        len += 1
                    Loop
    
                    ret_str &= str & vbTab
                Next
                ret_str &= vbCrLf
            Next
            Return ret_str
        End Function
    
    
        Public Sub ToCSV(Optional filename As String = "", Optional fullpath As String = "", Optional format As String = "")
    
            If fullpath = "" Then
                If filename = "" Then filename = "matrix_view"
                fullpath = AppDomain.CurrentDomain.BaseDirectory & filename & ".csv"
            End If
    
    
            Dim str As String = Me.ToString(format)
            str = Strings.Replace(str, vbTab, " ")
    
            Do While InStr(str, "  ") <> 0
                str = Strings.Replace(str, "  ", " ")
            Loop
            str = Strings.Replace(str, " " & vbCrLf, vbCrLf)
            str = Strings.Replace(str, " ", ",")
    
            Dim str_rows() As String = Strings.Split(str, vbCrLf)
    
            Dim csv_str As String
    
            csv_str = ""
            csv_str &= ",,col" & vbCrLf
            csv_str &= ",row"
    
            For i As Integer = 1 To Me.ColSize
                csv_str &= "," & CStr(i)
            Next
            csv_str &= vbCrLf
    
            For i As Integer = 1 To Me.RowSize
                csv_str &= "," & CStr(i) & "," & str_rows(i - 1) & vbCrLf
            Next
    
    
    
            Dim sw As System.IO.StreamWriter
    
            fullpath = Strings.Replace(fullpath, ".csv", "")
            Dim fullpath2 As String = fullpath
            Dim j As Integer = 0
            Do
                Try
                    sw = New System.IO.StreamWriter(fullpath2 & ".csv")
                    Exit Do
                Catch ex As Exception
                    j += 1
                    fullpath2 &= fullpath & CStr(j)
                End Try
            Loop While (1)
            fullpath2 &= ".csv"
    
            sw.WriteLine(csv_str)
            sw.Close()
            Process.Start(fullpath2)
    
        End Sub
    
    
    
        Private Function MaxStringLength(format As String) As Integer
    
            Dim val As Single
            Dim str As String
            Dim len As Integer
            Dim N_len As Integer
    
            N_len = 0
            For i As Integer = 1 To Me.RowSize
                For j As Integer = 1 To Me.ColSize
    
                    val = Me.matrix_item(i, j)
                    str = val.ToString(format)
    
                    len = str.Length
                    If N_len < len Then N_len = len
                Next
            Next
    
            Return N_len
        End Function
    
    End Class
    
    Public Class Win32
        <DllImport("kernel32.dll")> Public Shared Function AllocConsole() As Boolean
        End Function
    
        <DllImport("kernel32.dll")> Public Shared Function FreeConsole() As Boolean
        End Function
    End Class

  19. #19

    Thread Starter
    Junior Member
    Join Date
    Oct 2021
    Posts
    23

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Quote Originally Posted by Shaggy Hiker View Post
    That universal clone won't work for EVERYTHING, it will work for certain things. For example, what happens if the array is an array of Object, where the actual items in the array are a variety of things, such as the first being an integer, the second being a string, and so forth. What type will arrObj(0).GetType return for such an array?

    Another, more contrived, variation would be: What happens if the array is an array of classes that maintain a DB connection? What should the state of those connections be in the cloned array?
    It'll work for the first 2 examples. Every item in the array calls 'Clone' again... its recursive.
    Every member in a object calls Clone again... keeps going and going until it gets to the valuetype.

  20. #20
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    37,704

    Re: Should I use a Class or a Structure, (Matrix Tool)

    Right, and it WILL clone most everything, but not absolutely everything. I think there's a faster method to accomplish the same thing, but whether or not it is simpler is certainly debatable. I haven't tried it, just seen it, and I may not be remembering it right, but I think the idea was to binary serialize to a memory stream, then restore to a new location. I think that's slightly wrong, as the binary serialization sounds a bit off, but it was something like that.
    My usual boring signature: Nothing

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width