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

Я пытаюсь включить 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 (или какого-либо другого бесплатного программного обеспечения), он был бы очень признателен.

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


person Steven Gillies    schedule 11.09.2013    source источник


Ответы (2)


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

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

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

person Konstantin Vladimirov    schedule 11.09.2013
comment
есть только одна глобальная функция, остальные вызываются только из глобальной функции. это вообще меняет ваш совет или это все еще способ продолжить? - person Steven Gillies; 11.09.2013
comment
Нет разницы между одной глобальной функцией или их количеством. Это означает только то, что вы должны вызывать одну функцию через P/Invoke, и, таким образом, все упрощается. - person Konstantin Vladimirov; 11.09.2013

Этот ответ несколько ортогонален вопросу, поскольку он полностью избегает 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.

person fuglede    schedule 23.12.2017