F# и ILNumerics

Я только что скачал последнюю версию ILNumerics для использования в моем проекте F#. Можно ли использовать эту библиотеку в F#? Я пробовал простые вычисления, и они кажутся очень громоздкими (на F#).

Я хотел бы задать задачу оптимизации с ограничениями (или даже без ограничений). Подойдет обычная функция Розенброка, а затем я воспользуюсь своей собственной функцией. У меня тяжелые времена, когда определяется даже массив. Единственный тип массива, который я мог определить, был RetArray, например, с помощью этого кода

let vector = ILMath.vector<float>(1.0, 2.0)

Компилятор сигнализирует, что вектор представляет собой RetArray; Я думаю, это связано с тем, что он возвращается из функции (например, ILMath.vector). Если я определяю другой подобный вектор, я могу, например, суммировать векторы, просто написав, например

let a = ILMath.vector<float>(1.0, 2.0)
let b = ILMath.vector<float>(3.2,2.2)
let c = a  + b 

и я получаю

RetArray<float> = seq [4.2; 4.2]

но если я попытаюсь получить значение c, опять же, написав, например, в FSI,

c;;

я получил

Ошибка: ссылка на объект не указывает на экземпляр объекта.

Каков предлагаемый способ использования ILNumerics в F#? Можно ли использовать библиотеку изначально в F#, или я вынужден вызывать свой код F# из библиотеки C#, чтобы использовать всю библиотеку ILNumerics? Помимо упомянутой проблемы, у меня есть проблемы с пониманием самой базовой логики ILNumerics при переносе на F #.

Например, что было бы F# эквивалентом C# с использованием области действия, как в примере кода, например:

using (ILScope.Enter(inData)) { ...

}

person pacta_sunt_servanda    schedule 09.03.2021    source источник
comment
но если я попытаюсь получить значение c, можете ли вы уточнить это? В вашем вопросе нет кода для доступа к c.   -  person Jim Foye    schedule 10.03.2021
comment
@JimFoye Я соответственно изменил сообщение. Спасибо, что попросили разъяснения.   -  person pacta_sunt_servanda    schedule 10.03.2021
comment
О using вот ссылка на язык на управление ресурсами. Таким образом, код будет выглядеть как using (ILScope.Enter inData) (fun () -> some computations)   -  person JL0PD    schedule 10.03.2021


Ответы (2)


Причина того, что второй доступ к c не удается, заключается в том, что ILNumerics выполняет очень необычное управление памятью, которое автоматически освобождает память вектора, когда вы этого не ожидаете. В C# для этого используется неявное преобразование vector в Array:

// C#
var A = vector<int>(1, 2, 3);          // bad!
Array<int> A = vector<int>(1, 2, 3);   // good

В F# нет неявных преобразований типов, но вы можете вызвать член op_Implicit вручную, например так:

open ILNumerics
open type ILMath   // open static class - new feature in F# 5

let inline (!) (x : RetArray<'t>) =
    Array<'t>.op_Implicit(x)

[<EntryPoint>]
let main argv =
    let a = !vector<float>(1.0, 2.0)
    let b = !vector<float>(3.2,2.2)
    let c = !(a  + b)
    printfn "%A" c
    printfn "%A" c
    0

Обратите внимание, что я создал встроенную вспомогательную функцию под названием !, чтобы упростить эту задачу. Каждый раз, когда вы создаете вектор ILNumerics в F#, вы должны вызывать эту функцию, чтобы преобразовать его в массив. (Это некрасиво, я знаю, но я не вижу более простой альтернативы.)

Чтобы ответить на ваш последний вопрос, эквивалентный код F #:

use _scope = Scope.Enter(inData)
...
person brianberns    schedule 10.03.2021
comment
большое спасибо. Я попробую использовать ваш подход и, возможно, отчитаюсь. Это имеет гораздо больше смысла. - person pacta_sunt_servanda; 10.03.2021

Просто чтобы немного уточнить ответ Брайанберна, есть несколько вещей, которые вы могли бы сделать, чтобы облегчить себе задачу.

Лично я бы не пошел по пути определения пользовательского оператора, особенно такого, который переопределяет существующий. Вместо этого, возможно, вам следует рассмотреть возможность использования выражения для вычислений для работы с типами ILMath. Это позволит вам скрыть многие уродства, возникающие при работе с библиотеками, использующими стандарты, отличные от F# (например, неявные преобразования типов).

У меня нет доступа к ILMath, поэтому я просто реализовал эти фиктивные альтернативы, чтобы мой код скомпилировался. Я подозреваю, что вы должны иметь возможность просто не копировать это, и остальная часть кода будет работать как задумано.

module ILMath =
    type RetArray<'t> = { Values: 't seq }

    and Array<'t> = { OtherValues: 't seq } with
        static member op_Implicit(x: RetArray<_>) = { OtherValues = x.Values }
        static member inline (+) (x1, x2) = { Values = (x1.OtherValues, x2.OtherValues) ||> Seq.map2 (+) }

type ILMath =
    static member vector<'t>([<ParamArray>] vs : 't []) = { ILMath.Values = vs }

Если вы никогда раньше не видели и не реализовывали вычислительное выражение, вам следует проверить документацию, на которую я ссылался. По сути, он добавляет немного приятного синтаксического сахара поверх некоторой уродливости, так, как вы сами решаете. В моем примере реализации добавлены только ключевые слова let! (отказатели сахара к Bind) и return (отказатели сахара к Return).

type ILMathBuilder() =
    member __.Bind(x: ILMath.RetArray<'t>, f) =
        f(ILMath.Array<'t>.op_Implicit(x))
    member __.Return(x: ILMath.RetArray<'t>) =
        ILMath.Array<'t>.op_Implicit(x)

let ilmath = ILMathBuilder()

Это должно быть определено и реализовано (переменная ilmath) на верхнем уровне. Это позволяет вам писать

let c = ilmath {
    let! a = vector(1.0, 2.0)
    let! b = vector(3.2, 2.2)
    return a + b
}

Конечно, эта реализация добавляет поддержку очень немногих вещей и требует, например, чтобы всегда возвращалось значение типа RetArray<'t>. Отсюда следует расширение типа ILMathBuilder в соответствии с документацией.

person torbonde    schedule 10.03.2021
comment
FWIW, я тоже думал о построителе вычислений, но это значительно больше работы для тех, кто просто хочет использовать библиотеку. (Компоновщик действительно должен быть предоставлен самой ILNumerics.) Кроме того, обратите внимание, что ваш последний фрагмент кода очень похож на то, что я написал — основное отличие заключается в расположении !. - person brianberns; 10.03.2021
comment
Torbonde, Большое спасибо. Это отличный ответ. @brianberns: ты определенно прав. Мне понравился ответ, и он очень поучителен, но, возможно, я сначала попробую использовать более простой подход, просто чтобы использовать библиотеку. Большое спасибо вам обоим. - person pacta_sunt_servanda; 10.03.2021