2014 dxdy logo

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

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




Начать новую тему Ответить на тему
 
 Как сделать каррирование функции от вектора в С++
Сообщение08.07.2019, 17:05 
Аватара пользователя


22/06/07
146
Здравствуйте. Пишу метод покоординатного спуска на 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 
Заслуженный участник


27/04/09
28128
Проблема именно в описании типов или нет? Во втором случае вам просто нужно написать функцию, берущую вашу f, вектор постоянных аргументов и индекс и выдающую функцию одного аргумента, которая вставляет его в нужном месте в копию вектора постоянных и вызывает f с результатом вставки.

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

 Профиль  
                  
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение09.07.2019, 04:46 


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

 Профиль  
                  
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение09.07.2019, 14:43 
Аватара пользователя


22/06/07
146
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 


11/12/14
893
Евгеша в сообщении #1404133 писал(а):
Немножко "подсахарил" для себя.


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

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


22/06/07
146
aa_dav в сообщении #1404172 писал(а):

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


Тогда уж:

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

 Профиль  
                  
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение11.07.2019, 07:39 


11/12/14
893
Евгеша в сообщении #1404177 писал(а):
Тогда уж:


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

 Профиль  
                  
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение11.07.2019, 12:47 
Заслуженный участник


27/04/09
28128
А что, такой typedef вообще скомпилируется? :o Если так, то ого.

 Профиль  
                  
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение11.07.2019, 14:35 


11/12/14
893
arseniiv в сообщении #1404504 писал(а):
А что, такой typedef вообще скомпилируется?


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

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


07/02/12
1403
Питер
Перепишите с
Код:
<template typename ...>

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

 Профиль  
                  
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение25.01.2020, 19:39 
Заслуженный участник


02/08/11
6892
arseniiv, присмотритесь к коду внимательнее: там нет магии, которую, как мне кажется, вы нашли. Rn - это просто Rn, а не волшебная конкатенация идентификатора с числом.

 Профиль  
                  
 
 Re: Как сделать каррирование функции от вектора в С++
Сообщение25.01.2020, 20:52 
Заслуженный участник


27/04/09
28128
Да меня тогда удивило, что туда const входит. Точно не помню, что думал, так-то типы с const я видел давно.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 12 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group