Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Minpack fortran .dll для использования в С#

Автор вопроса: Steven GilliesОтветов: 2

Я пытаюсь включить minpack, который написан на FORTRAN и используется для решения методом наименьших квадратов недоопределенных математических задач, в мое решение формы окна С#.

Я читал, что можно скомпилировать подпрограммы minpack fortran, которых 7 (все в отдельных файлах), в .dll, которую я затем могу добавить в качестве ссылки на мою программу на С# в Visual Studio 2012.

Я пытался сделать это сейчас в течение 2 дней без особой удачи. Я скачал GCC GNU для компиляции файлов фортрана. Мои шаги до сих пор:

1) скомпилируйте файлы fortran в файлы общего формата объектных файлов (COFF *.o), используя синтаксис "gcc -c filename1.f" в командной строке mingw64env для всех 7 файлов.

2) Затем я скомпилировал эти файлы вместе в общий исполняемый файл, используя синтаксис "gcc -shared -o mindpack.dll имя_файла1.o имя_файла2.o имя_файла3.o..."

это выводит файл .dll без сообщений об ошибках.

3) Но когда я пытаюсь добавить его в качестве ссылки на мой проект форм Windows (С#), я получаю сообщение об ошибке "Не удалось добавить ссылку на" * .dll ". Пожалуйста, убедитесь, что файл доступен и что это допустимая сборка или COM-компонент".

4) одним из предложений исправить это было найти файл C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\TlbImp.exe и выполнить его с синтаксисом "TlbImp.exe minpack.dll ", но это дает ошибку "TlbImp: ошибка T10000: входной файл" C:\mingw64\minpack.dll'не является допустимой библиотекой типов.

Может ли кто-нибудь указать мне правильное направление, поскольку я только начал изучать С#, и некоторые из онлайн-решений мне не по плечу с такими вещами, как файлы заголовков и файлы DEF, я не уверен, что они вообще актуальны.

Если бы кто-то мог выложить решение для преобразования набора подпрограмм fortran в один файл .dll, который можно вызывать из С#, желательно с использованием GCC GNU (или какого-либо другого бесплатного программного обеспечения), он был бы очень признателен.

Заранее спасибо.

gccfortrandllgnu

Ответы

Ответ 1 · рейтинг 1 · Konstantin Vladimirov

Неуправляемую dll нельзя добавить в качестве ссылки на приложение C#. GCC не может легко связать COM-объект для вас.

Если dll экспортирует ряд глобальных функций, вы должны иметь возможность использовать Platfrom Invoke (атрибут DllImport) для их вызова из C#.

Посмотрите на это статью или любую другую из поиска Google.

Ответ 2 · рейтинг 1 · fuglede

Этот ответ несколько ортогонален вопросу, поскольку он полностью избегает Fortran, но, учитывая распространенность вопроса в результатах поиска на C# и MINPACK, стоит упомянуть, что доступен порт MINPACK на C/C++ с открытым исходным кодом, что может упростить процесс создания чего-то вызываемого из .NET.

Чтобы использовать эту конкретную библиотеку,

  1. загрузите релизную версию исходного кода, последней на момент написания статьи была версия 1.6. 3.
  2. Откройте решение Visual C++ cminpack.sln, содержащееся внутри, и соберите его, чтобы получить библиотеку cminpack_dll.dll.
  3. Добавьте cminpack_dll.dll в свое решение .NET и убедитесь, что он скопирован в выходной каталог при сборке.
  4. На этом этапе библиотеку можно вызвать с помощью P/Invoke.

В приведенном ниже примере показано, как подогнать квадратичную функцию к заданному набору точек данных:

class Program
{
    static void Main()
    {
        // Define some test data by 5i + 3i^2. The plan is to let cminpack figure out
        // the values 5 and 3.
        var data = Enumerable.Range(0, 20)
            .Select(i => 5 * i + 3 * Math.Pow(i, 2))
            .ToList();

        CminpackFuncMn residuals = (p, m, n, x, fvec, iflag) =>
        {
            unsafe
            {
                // Update fvec with the values of the residuals x[0]*i + x[1]*i^2 - data[i].
                var fvecPtr = (double*)fvec;
                var xPtr = (double*)x;
                for (var i = 0; i < m; i++)
                    *(fvecPtr + i) = *xPtr * i + *(xPtr + 1) * Math.Pow(i, 2) - data[i];
            }
            return 0;
        };

        // Define an initial (bad) guess for the value of the parameters x.
        double[] parameters = { 2d, 2d };
        var numParameters = parameters.Length;
        var numResiduals = data.Count;
        var lwa = numResiduals * numParameters + 5 * numParameters + numResiduals;

        // Call cminpack
        var info = lmdif1(
            fcn: residuals,
            p: IntPtr.Zero,
            m: numResiduals,
            n: numParameters,
            x: parameters,
            fvec: new double[numResiduals],
            tol: 0.00001,
            iwa: new int[numParameters],
            wa: new double[lwa],
            lwa: lwa);

        // parameters now contains { 5, 3 }.
        Console.WriteLine($"Return value: {info}, x: {string.Join(", ", parameters)}");
    }

    [DllImport("cminpack_dll.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int lmdif1(CminpackFuncMn fcn, IntPtr p, int m, int n, double[] x,
        double[] fvec, double tol, int[] iwa, double[] wa, int lwa);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int CminpackFuncMn(IntPtr p, int m, int n, IntPtr x, IntPtr fvec, int iflag);
}

Здесь подписи lmdif1 и CminpackFuncMn можно определить, проверив соответствующий заголовочный файл. в cminpack.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы