Continue to Site

Eng-Tips is the largest engineering community on the Internet

Intelligent Work Forums for Engineering Professionals

  • Congratulations cowski on being selected by the Eng-Tips community for having the most helpful posts in the forums last week. Way to Go!

Matrix math -- Application development 3

Status
Not open for further replies.

ePOWEReng

Electrical
Jul 15, 2003
114
Hello,

I am considering taking some calculations that presently performed using MathCAD and creating an application to perform those calculations instead. The calculations involve creating a matrix of complex numbers and performing some matrix math operations to arrive at the solution. The complex matrices will be up to 200x200 in size and matrix inversion will be required. My question is what programming language and development platform would make be the easiest to implement a program like this in? Are there libraries out there for performing complex matrix inversion? I was considering using the microsoft visual platform...

Thanks for your input and suggestions.
 
Replies continue below

Recommended for you

Does anyone have a simple numerical example they can post for testing purposes?

The solution for the example I posted above can be obtained in Matlab as follows

Code:
»  A=[5+2*i, 6+2*i; 3+8*i, 1+2*i]

A =

   5.0000 + 2.0000i   6.0000 + 2.0000i
   3.0000 + 8.0000i   1.0000 + 2.0000i

» inv(A)

ans =

  -0.0482 + 0.0227i   0.0510 - 0.1416i
   0.1921 - 0.0669i  -0.0504 + 0.1178i

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
What I meant to say - the solution is the last thing listed after "ans ="...

I still haven't gotten it to work...

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
After loading the required libraries, I still get the same error that I described 15 May 10 0:13.

It is looking at a matrix A (his A, not mine) and accessing element A(I,J) where I=0 and J=0 at the time of the call. The matrix starts with element 1,1.

Maybe I need to add Option Base 0 in front of his modules?
I am using Excel 2000

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
Thanks Doug. I see now you have suggested my matrix needs to be base zero. I'd vote you a LPS, but I already voted you one in this thread.

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
After heeding Doug's advice, it does in fact give same answer as Matlab.

Here is test code
Code:
Sub test1()
Dim A1(0 To 1, 0 To 1) As Complex
Dim XX As MatInvReport

' Initialize Matrix
A1(0, 0).X = 5
A1(0, 0).Y = 2
A1(0, 1).X = 6
A1(0, 1).Y = 2
A1(1, 0).X = 3
A1(1, 0).Y = 8
A1(1, 1).X = 1
A1(1, 1).Y = 2

Call CMatrixInverse(A1, 2, 0, XX)
Debug.Print "Ainv(0,0)=" & Format(A1(0, 0).X, "#.###") & "+" & Format(A1(0, 0).Y, "#.###") & "i"
Debug.Print "Ainv(0,1)=" & Format(A1(0, 1).X, "#.###") & "+" & Format(A1(0, 1).Y, "#.###") & "i"
Debug.Print "Ainv(1,0)=" & Format(A1(1, 0).X, "#.###") & "+" & Format(A1(1, 0).Y, "#.###") & "i"
Debug.Print "Ainv(1,1)=" & Format(A1(1, 1).X, "#.###") & "+" & Format(A1(1, 1).Y, "#.###") & "i"

End Sub
Here is result
Code:
Ainv(0,0)=-.048+.023i
Ainv(0,1)=.051+-.142i
Ainv(1,0)=.192+-.067i
Ainv(1,1)=-.05+.118i
So it works, but there are two minor inconveniences:
1 - we need to make sure all our matrices are dimensioned as base 0.
2 - the subroutine overwrites the matrix that we passed with it's inverse. Need to be careful how you call it. I guess I'd be inclined to create a function that calls the subroutine and returns the value without overwriting the argument. Unless there is some easier way or something I'm missing?

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
There is a challenge in using this that you have to import so many supporting files. Especially if you'd like to access a broad range of functions. Note there is no clear map for dependencies among files... as seen above it was not easy to figure out trfac.bas was required to support subroutine CMatrixInverse which itself was located in matinv.bas. And perhaps some others required (I loaded all the ones he said in the post on the alglib forum).

So it would be nice to be able to load them all once, and then not have to ever do it again. And it would be very ugly to have them cluttering up the module list (such as if I just try to use the same xls file that I loaded the alglib modules into).

To me it seems like perfect application for an excel add-in.

So after I imported, I saved my file with required modules as xla. As attached.

Then I closed excel, created a new spreadsheet, went to add-ins menu and added my just-created add-in. Then went to vba window... I could see the new add-in had showed up as a Project. But when I tried to run my test code again, it does not recognize the Complex type. Seems like some kind of scoping problem. The add-in has a module with a public declariation of Complex datatype. Why can't it be seen in other Projects?

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
 http://files.engineering.com/getfile.aspx?folder=b4640786-a478-49d9-90a6-fc194ca004b6&file=AlgLibTestBookTrialForAddin.xla
I guess public gets you as far as the project level, but not beyond that. I'll have to study up a little on add-ins and scoping. Seems pretty useless if you can't access public declarations and public from an add-in.

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
Thanks Doug and Electric pete. I imported all the correct modules and it seems to be working.

Good points on use of the function too electric pete. I think as long as I keep that in mind it shouldn't be difficult to work around.

Thanks!
 
I found a way to automatically insert all 101 bas files into modules. The code was adapted from Walkenbach.

1 - Create a new worksheet, insert a module, and put the code below into it.

2 - Put the 101 bas files into a directory and edit the FilePath below FROM "C:\Documents and Settings\peter\My Documents\AlgLib\SourceBas\" TO whatever your directory is.

3 - Run the sub BatchProcess
Code:
Sub BatchProcess()
Dim FS As FileSearch
Dim FilePath As String, FileSpec As String
Dim I As Integer
Dim myfilename As String

' Specify path and file spec
FilePath = "C:\Documents and Settings\peter\My Documents\AlgLib\SourceBas\"
FileSpec = "*.bas"
' Create a FileSearch object
Set FS = Application.FileSearch
With FS
.LookIn = FilePath
.FileName = FileSpec
.Execute
' Exit if no files are found
If .FoundFiles.Count = 0 Then
MsgBox "No files were found"
Exit Sub
End If
End With
' Loop through the files and process them
For I = 1 To FS.FoundFiles.Count
Stop
Application.Modules.Add.InsertFile (FS.FoundFiles(I))
myfilename = "z_" & FileNameOnly(FS.FoundFiles(I))
myfilename = Mid(myfilename, 1, Len(myfilename) - 4)
Modules(Modules.Count).Name = myfilename

Next I
End Sub

Public Function FileNameOnly(pname) As String
' Returns the filename from a path/filename string
Dim I As Integer, length As Integer, Temp As String
length = Len(pname)
Temp = ""
For I = length To 1 Step -1
If Mid(pname, I, 1) = Application.PathSeparator Then
FileNameOnly = Temp
Exit Function
End If
Temp = Mid(pname, I, 1) & Temp
Next I
FileNameOnly = pname
End Function
One small downside, the file is already 5MB, and there is no data in it yet (just code).

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
I forgot to mention one thing - I put a z_ in front of every filename. That way all of the library modules will sort to the end of the list and it won't be so cumbersome to find your own modules within the module list.

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
Last post - here is the indented version of the code. Easier on the eyes.
Code:
Sub BatchProcess()
Dim FS As FileSearch
Dim FilePath As String, FileSpec As String
Dim I As Integer
Dim myfilename As String

    ' Specify path and file spec
    FilePath = "C:\Documents and Settings\peter\My Documents\AlgLib\SourceBas\"
    FileSpec = "*.bas"
    ' Create a FileSearch object
    Set FS = Application.FileSearch
    With FS
        .LookIn = FilePath
        .FileName = FileSpec
        .Execute
        ' Exit if no files are found
        If .FoundFiles.Count = 0 Then
            MsgBox "No files were found"
            Exit Sub
        End If
    End With
    ' Loop through the files and process them
    For I = 1 To FS.FoundFiles.Count
        Stop
        Application.Modules.Add.InsertFile (FS.FoundFiles(I))
        myfilename = "z_" & FileNameOnly(FS.FoundFiles(I))
        myfilename = Mid(myfilename, 1, Len(myfilename) - 4)
        Modules(Modules.Count).Name = myfilename

    Next I
End Sub

Public Function FileNameOnly(pname) As String
' Returns the filename from a path/filename string
Dim I As Integer, length As Integer, Temp As String
    length = Len(pname)
    Temp = ""
    For I = length To 1 Step -1
        If Mid(pname, I, 1) = Application.PathSeparator Then
            FileNameOnly = Temp
            Exit Function
        End If
        Temp = Mid(pname, I, 1) & Temp
    Next I
    FileNameOnly = pname
End Function

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
My question is what programming language and development platform would make be the easiest to implement a program like this in?
I am partial to excel vba for a number of reasons: mostly that it's portable.

BUT, if you're looking for "easy to program" matrix operations, it's clearly not here in vba (nowhere near as easy/compact as Matlab). Since each multiplication is a function call, you will end up with a lot of nesting or have to break down matrix equations into baby steps. As a somewhat frustrating example I have encountered... you can't even use A=B where A is dimensioned as NxN and B is NxN. You have to write a routine to do it on an element by element basis, or else A has to be a new variable not yet dimensioned. So to accomplish A=B*C you end up something like:
Call Mequals(A, Mmultiply(B,C))
where Mequals is your element by element assignment routine that puts the values from the 2nd argument into the 1st on an element by element basis. Mmultiply would be a function. But you can't say A=Mmultiply(B,C) if A is already dimensioned (even though the dimensions are compatible).

There may be some easier workaround, but that's what I came up with.

=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
electricpete - thanks for the code for inserting the code automatically, I was just about to go and do it manually.

I verified the complex inversion routines with your example and got the same answer, so thanks for that as well.

I wrote a UDF to convert the arrays to a suitable form for the AlgLib routines. Here it is:

Code:
Function CMatInv(A As Variant) As Variant
    Dim N As Long, M As Long
    Dim A2() As Complex, I As Long, J As Long, K As Long, Info As Long
    Dim Rep As MatInvReport, Tmp As Complex

    A = A.Value2
    M = UBound(A)
    N = UBound(A, 2)

    ReDim A2(0 To M - 1, 0 To N / 2 - 1)

' Convert value pairs to Complex type and write to base zero array
    K = 0
    For I = 1 To M
        For J = 1 To N - 1 Step 2
            K = (J + 1) / 2 - 1
            Tmp.X = A(I, J)
            Tmp.Y = A(I, J + 1)
            A2(I - 1, K) = Tmp
        Next J
    Next I

    Call CMatrixInverse(A2, M, Info, Rep)

' Convert Complex results back to pairs of doubles
    For I = 1 To M
        For J = 1 To N / 2
            Tmp = A2(I - 1, J - 1)
            A(I, J * 2 - 1) = Tmp.X
            A(I, J * 2) = Tmp.Y
        Next J
    Next I

    CMatInv = A
End Function


I'll comment on your last post later, but I have to go and do some .bas importing right now :)



Doug Jenkins
Interactive Design Services
 
Apparently the filesearch object no longer works in Excel 2007. The code below works in 2007, but I had to save the workbook in the same directory as the .bas files.

Code:
Sub BatchProcess()
    Dim FileName As String, FileList() As String
    Dim FilePath As String, FileSpec As String
    Dim I As Integer
    Dim myfilename As String, FoundFiles As Long

    ' Specify path and file spec
    FileSpec = "d:\Users\Doug\Documents\SPREAD\AlgLib\vb6\src\" & "*.bas"
    FileName = dir(FileSpec)

    ' Exit if no files are found
    If FileName <> "" Then
        FoundFiles = 1
        ReDim Preserve FileList(1 To FoundFiles)
        FileList(FoundFiles) = FileName
    Else
        Exit Sub
    End If
    Do
        FileName = dir
        If FileName = "" Then Exit Do
        FoundFiles = FoundFiles + 1
        ReDim Preserve FileList(1 To FoundFiles)
        FileList(FoundFiles) = FileName
    Loop

    ' Loop through the files and process them
    For I = 1 To FoundFiles
        Stop
        Application.Modules.Add.InsertFile (FileList(I))
        myfilename = "z_" & FileNameOnly(FileList(I))
        myfilename = Mid(myfilename, 1, Len(myfilename) - 4)
        Modules(Modules.Count).Name = myfilename

    Next I

End Sub

If you are using XL2007 it's worth saving as an xlsb file. The file size is reduced to 2.2 MB and it saves very much more quickly than an xls file.

Thanks again to electricpete for posting the original version.

Doug Jenkins
Interactive Design Services
 
I like your idea of a front-end function for CMatrixInverse to accomplish two things:
1 - Provide a function call rather than a sub which stuffs Ainverse into A.
2 - Make sure the indexing starts as zero.

I think I'd be inclined to store my vba complex variables as user-defined type "complex" (defined in module ap) or arrays of NxN complex variables (like the example I posted), rather than a Nx2N array of scalars that gets decoded to/from complex in the function call. A conversion does has to be made from vba format to format compatible with outside world (for example spreadsheet), my preference would be to do that conversion as part of input/output routines. Just a personal preference.

Note Alglib provides a few functions for manipluating udt complex variables directly. They roughly correspond to the same routines provided in the excel analysis tookpak. Except one that is missing is something to generate the angle of a complex number (like imargument). But it would be easy to create that missing function... the hardest part (most important part) would be keeping organized in storing/tracking these extra functions like the angle funciton or the front-end for Cmatrix or the input/output functions.

Regarding loading those 101 modules, you can see here that the 101 are divided into "packages" with no more than 20 or so modules in a package.:
I am pretty sure that in order to access a function or subroutine from a package, it would be sufficient to load just the modules from that package, along with the special module "ap". That would cut down on size of the file. I'm going to split the source files into separate directories on my harddrive (one directory per package) for the purpose of making it easier to import only modules needed by a package.


=====================================
Eng-tips forums: The best place on the web for engineering discussions.
 
I mentioned earlier that I had to switch off Option Explicit to get the matrix inversion sub to run. For some reason it is now working, even if Option Explicit is set, but if I run Debug-Compile VBA Project I get a load of errors.

It seems that it is only AP.bas that has the problem, so I have gone through and added dim statements for all the undeclared variables. I'll post the updated file when I've tested it more thoroughly.

Doug Jenkins
Interactive Design Services
 
I have summarised the procedures for installing the AlgLib code, and posted some sample functions (matrix inversion and eigen values) here:


which might be useful for anyone looking at the code and wondering where to start.

I will also be posting some examples of linking to c++ dlls from VBA in the near future.


Doug Jenkins
Interactive Design Services
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor