.Net ( c# ) 与 Fortran 混合编程实例(一):求线性方程组的解

几点说明:

1.线性方程组的输入采用矩阵形式,以 “," 分割,写入 txt 文本中;

2. .Net 读取文本,以 ”,“ 拆分存入二维数组中,再将数组传递给 Fortran DLL 进行求逆、求解;

3.求解( A x = b )方法采用系数矩阵 A 求逆与 b 列阵相乘取得解列阵 x 。

4.开发平台: VS2008 + CVF6

5. Debug 文件夹清单:

—— Debug

———— EXAMPLES (文件夹——存放算例)

———— FORTRANCAL (文件夹——存放 Fortran Dll 文件)

—————— LinearEquation.dll (动态链接库——求解线性方程组的类)

—————— PlaceUsingTxt.dll (动态链接库——文本文件操作,用以取得系数矩阵、常数列阵)

—————— Main.exe (Windows 控制台程序——执行文件)


开始:

1.新建类库,LinearEquation ,新建类 ClassY ,添加引用之前准备的 PlaceUsingTxt.dll (参考文章 .Net 中操作文本文件),贴入以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;
using PlaceUsingTxt;

namespace LinearEquation
{
    public class ClassY
    {
        //二维数组存放系数矩阵
        private Single[,] d;

        //系数矩阵的行数、列数
        private int rows, cols;

        public ClassY(string FileName)
        {
            ClassReadTxt cr = new ClassReadTxt(Environment.CurrentDirectory + "/EXAMPLES/" + FileName + ".txt");
            string[,] str = cr.OutStr2D();
            cr.close();

            rows = str.GetLength(0);
            cols = str.GetLength(1);

            //将读取的字符串数组转为数值型
            d = new Single[rows, cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    d[i, j] = Convert.ToSingle(str[i, j]);
                }
            }
        }

        [DllImport("FORTRANCAL/MatrixCal.dll")]
        public static extern void MatrixNi(ref Single A, ref int n);

        //得到逆矩阵
        public Single[,] GetA_()
        {
            //取得需要求逆的方阵
            Single[,] A = new Single[rows, rows];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < rows; j++)
                {
                    A[i, j] = d[i, j];
                }
            }

            //返回逆矩阵
            MatrixNi(ref A[0, 0], ref rows);
            return A;
        }

        //取得列阵
        public Single[] Getb()
        {
            Single[] b = new Single[rows];

            for (int i = 0; i < rows; i++)
            {
                b[i] = d[i, cols - 1];
            }
            return b;
        }

        [DllImport("FORTRANCAL/MatrixCal.dll")]
        public static extern void MatrixJie(ref Single A_, ref int n, ref Single b, ref Single x);

        //取得解
        public Single[] Getx()
        {
            Single[] x = new Single[rows];

            MatrixJie(ref this.GetA_()[0, 0], ref rows, ref this.Getb()[0], ref x[0]);
            return x;
        }

        //测试用,返回从文本读取的矩阵
        public Single[,] GetM()
        {
            return d;
        }
    }
}


编译生成 LinearEquation.dll 。


2. (Fortran 方面)新建项目,Fortran 动态链接库,命名为 MatrixCal ,新建 2 个源文件,关于 .Net 与 Fortran 混合编程基础参考文章(.Net(c#) 通过 Fortran 动态链接库,实现混合编程),贴入以下代码:


(1)系数矩阵求逆

subroutine MatrixNi(a,num)
	implicit none

	!dec$ attributes dllexport::MatrixNi
	!dec$ attributes alias:"MatrixNi"::MatrixNi
	!dec$ attributes reference::a,num

	integer::num
	real(4)::a(num,num)
	integer::i,j,k
	integer::n
	
	n = num
	
	do k=1,N
        a(k,k) = 1.d0/a(k,k)
        do j=1,N
            if(j/=k) a(j,k) = a(k,k)*a(j,k)
        end do
		
		do i=1,N
            do j=1,N
                if(i/=k.and.j/=k) a(j,i) = a(j,i) - a(k,i)*a(j,k)
            end do
            if(i/=k) a(k,i) = -a(k,i)*a(k,k)
        end do
	end do

end subroutine


其中, a 为系数矩阵, num 为方阵的维数。将 .Net 传递的数组首地址后 n × n 个地址中数字取出,当成数组来使用,将 a 求逆,然后存回原地址中。


(2)系数逆矩阵与列阵 b 相乘取得 解列阵 x

subroutine MatrixJie(a,num,b,x)
	implicit none

	!dec$ attributes dllexport::MatrixJie
	!dec$ attributes alias:"MatrixJie"::MatrixJie
	!dec$ attributes reference::a,num,b,x

	integer::num
	real(4)::a(num,num)
	real(4)::b(num)
	real(4)::x(num)

	integer::n,i,j

	n = num

	do i = 1,N
		do j = 1,N
			x(i) = x(i) + a(j,i) * b(j)
		end do
	end do
	
end subroutine	 

其中,a 为刚才求得的逆矩阵,num 为方阵维数,b 为(A x = b)中右侧列阵,x 为所求的解列阵。

编译后将 MatrixCal.dll 放入 Degug/FORTRANCAL 中。


3.(主程序)新建 windows 控制台程序,命名为 Main,添加对 LinearEquation.dll 的引用,贴入代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using LinearEquation;

namespace Main
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please press down the filename.");
            string s = Console.ReadLine();

            ClassY c = new ClassY(s.Trim());
            //取得逆矩阵
            Single[,] A_ = c.GetA_();
            //取得解列阵
            Single[] x = c.Getx();

            for (int i = 0; i < A_.GetLength(0); i++)
            {
                for (int j = 0; j < A_.GetLength(1); j++)
                {
                    Console.Write(A_[i, j].ToString() + ",");
                }
                Console.WriteLine("");
            }

            Console.WriteLine();

            for (int i = 0; i < x.GetLength(0); i++)
            {
                Console.WriteLine(x[i].ToString());
            }

            Console.ReadLine();
        }


    }
}

4.进行测试,在 Debug 文件夹中新建文件夹 EXAMPLES ,新建文本 test.txt ,写入:

1,1,1,1
1,2,1,1
1,1,3,1


这个矩阵原型为:

x + y + z = 1

x + 2y + z = 1

x + y + 3z = 1


保存,运行程序,键入 test ,返回



注:

若要将此程序在未装 cvf 的电脑中运行,在 cvf 中编译 MatrixCal.dll 时,对 cvf 进行如下设置:

Project - Settings - Fortran ,在 Category 中选择 Libraries ,选择 Multi-threaded ,确定。



posted on 2011-10-04 16:48  silyvin  阅读(529)  评论(0编辑  收藏  举报