2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 Как сделать каррирование функции от вектора в С++
Сообщение08.07.2019, 17:05 
Аватара пользователя
Здравствуйте. Пишу метод покоординатного спуска на C$++$ для функции с большим числом аргументов. Возник такой вопрос.

На каждом шаге нужно фиксировать значения всех переменных кроме $x_i$, получая одномерную функцию $f(x_i)$, по которой проводить одномерную оптимизацию.

Я планировал написать отдельно функцию одномерной оптимизации, в которую в качестве аргумента каждый раз передавать каррированную по нужной координате функцию.

Будь функция двух-трех переменных, то можно было бы сделать как-то так:

Код:
#include <iostream>
#include <functional>

using namespace std;

typedef double R;

auto f(R x, R y, R z) -> R {
    return x + 2 * y + 3 * z;
}

auto main() -> int {
    auto fx = [=](R x) {
        return f(x, 0, 0);
    };

    auto fy = [=](R y) {
        return f(0, y, 0);
    };

    auto fz = [=](R z) {
        return f(0, 0, z);
    };

    cout << fx(5) << endl; // 5
    cout << fy(5) << endl; // 10
    cout << fz(5) << endl; // 15

    return 0;
}



Но если функция от большого числа параметров, то расписывать так для каждого аргумента выйдет слишком громоздко. В качестве аргумента удобно брать вектор или массив, например:

Код:
typedef array<R, n> Rn;

auto F(Rn x) -> R;


В гугле, к сожалению, подходящей информации не нашел.
Можно ли как-то реализовать каррирование для аргумента-вектора?

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение08.07.2019, 17:24 
Проблема именно в описании типов или нет? Во втором случае вам просто нужно написать функцию, берущую вашу f, вектор постоянных аргументов и индекс и выдающую функцию одного аргумента, которая вставляет его в нужном месте в копию вектора постоянных и вызывает f с результатом вставки.

Это довольно неудобный вариант, потому что будет как минимум постоянное копирование большого вектора. Проще было бы предложить сначала в вектор постоянных вставить на нужное место ну например ноль, а функцию оптимизации написать так, чтобы она знала, какой элемент этого вектора менять. Она будет просто присваивать ему всё новые значения и отдавать f, и никаких копирований.

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение09.07.2019, 04:46 
Как пример: https://ideone.com/4cfjdZ
Тут следует помнить, что лямбды в C++ есть лишь удобные иногда обёртки над классами-функторами, поэтому если предполагается многократное переиспользование такого класса (как тут - с разными idx), то проще как раз написать полноценный функтор. С++ всё-таки не ФЯ, не надо сильно на этом в нём заморачиваться.

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение09.07.2019, 14:43 
Аватара пользователя
arseniiv
Проблема была из функции на векторе получить функцию одной переменной. Что-то я, конечно, пытался реализовать, но до рабочего прототипа не дошло.

aa_dav
Благодарю. Немножко "подсахарил" для себя.
Код:
#include <iostream>
#include <functional>
#include <array>

using namespace std;

const int n = 3;

typedef double R;
typedef array<R, n> Rn;
typedef function<R(Rn)> CRn;

auto F(Rn x) -> R {
    return x[0] + 2 * x[1] + 3 * x[2];
}

class Currying {
    CRn func;
    int index;
    Rn currentX;
public:
    Currying(CRn _func, int _index, Rn _currentX)
        : func(_func), index(_index), currentX(_currentX) {}

    R operator()(R x) {
        currentX[index] = x;
        return func(currentX);
    }
};

auto main() -> int {
    Rn x = {1, 2, 3};

    Currying Fx{F, 0, x};
    Currying Fy{F, 1, x};
    Currying Fz{F, 2, x};

    cout << Fx(5) << endl;
    cout << Fy(5) << endl;
    cout << Fz(5) << endl;

    return 0;
}

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение09.07.2019, 18:45 
Евгеша в сообщении #1404133 писал(а):
Немножко "подсахарил" для себя.


Rn тут везде лучше передавать в качестве параметра как const Rn & чтобы избежать лишних копирований.

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение09.07.2019, 19:15 
Аватара пользователя
aa_dav в сообщении #1404172 писал(а):

Rn тут везде лучше передавать в качестве параметра как const Rn & чтобы избежать лишних копирований.


Тогда уж:

Код:
typedef const array<R, n>& Rn;

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение11.07.2019, 07:39 
Евгеша в сообщении #1404177 писал(а):
Тогда уж:


Не стоит - во первых оно как раз не нужно в полях классов или просто переменных, а кроме того не следует прятать по значению или по ссылке передаётся параметр и const он или нет - это может запутать человека привыкшего к общим практикам в C++. Ну или хотя бы выделить constRefRn как отдельный тип, но это особо не нужно.

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение11.07.2019, 12:47 
А что, такой typedef вообще скомпилируется? :o Если так, то ого.

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение11.07.2019, 14:35 
arseniiv в сообщении #1404504 писал(а):
А что, такой typedef вообще скомпилируется?


Да, без проблем.

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение25.01.2020, 14:48 
Аватара пользователя
Перепишите с
Код:
<template typename ...>

Руками. Получите удовольствие :D

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение25.01.2020, 19:39 
arseniiv, присмотритесь к коду внимательнее: там нет магии, которую, как мне кажется, вы нашли. Rn - это просто Rn, а не волшебная конкатенация идентификатора с числом.

 
 
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение25.01.2020, 20:52 
Да меня тогда удивило, что туда const входит. Точно не помню, что думал, так-то типы с const я видел давно.

 
 
 [ Сообщений: 12 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group