Решение задачи оптимизации в рамках ООП

318
10 февраля 2017, 04:19

Не могу правильно подобрать структуру классов и методов для решения задачи оптимизации именно в стиле ООП.
Дано: функция с ограничениями (равенства и неравенства) для примера возьмем простую нелинейную функцию с ограничением равенством

x^2 + y^2 -> min
x + y = 1

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

Как я решал:

  1. Оптимизировал простые целевые функции без ограничений градиентным методом, имел два класса - Задачу (Problem) с функциями выдающими значение функции и ее градиента и класс градиентный спуск (GradientDescent) со всеми свойственными ему методами. В main создавал объекты двух классов и массив double *point с начальными значениями точки, объект problem и gradient_descent. После чего, problem и point передавал в инициализатор gradient_descent и запускал метод optimize.
  2. Оптимизировал функции с ограничениями методом штрафных функций, соответственно методы getF и getG изменились добавился "коэффициент резкого возрастания функции" gamma, а оптимизация попала в цикл с изменяющимся параметром gamma.
  3. На основе вышеописанного хотелось бы писать код в рамках ООП. На сколько я понял лучше и удобнее - пользоваться наследованием. А именно - создать абстрактный класс Problem со всеми свойственными ему атрибутами и методами и парой переопределяемых методов, например virtual bool solve() и от него унаследовать класс например GradientDescent:Problem дабы просто использовать методы и атрибуты класса родителя и не передавать какието объекты и параметры. Однако я не могу никак придумать "связку" наследования Задача -> Метод штрафных функций -> Любой метод безусловной оптимизации. Может ли кто нибудь "на пальцах" объяснить возможна ли такая связка? Пока что в голову приходит только что в методе класса PenaltyM будет крутиться цикл с GradientDescent:Problem.

UPD По хорошему это ведь может касаться не только моей конкретной задачи. А задач на подобии:

        |----------------> Method_1
        |------>Method_0-----^
Problem |----------------> Method_2
        |----------------> Method_3
        |------>Method_4-----^

Т.е. по идее должен быть какой-то обобщенный класс метод, который может наследоваться от проблемы напрямую или иметь промежуточный метод. К сожалению я мыслю в формате процедурном, может быть кто нибудь сталкивался с подобным и сможет направить? Методы 1,2 и 3 должны как-то узнать, что их функцию оптимизации запускают либо просто так либо еще и через методы 0 или 4.

UPD 2 Я нашел один из подходов который решает мою задачу, но он не универсален. Как сделать так чтобы PenaltyMethod стал универсальным - я пока что не могу адекватно представить и реализовать. Ну а по делу, код выглядит так:

class Problem{
public:
    Problem(){}
    Problem (int size,
             double *point,
             double *constr_non_eq,
             bool **constr_eq):size_(size),
                              point_(point),
                              constrains_non_eq_(constr_non_eq),
                              constrains_eq_(constr_eq){}
    virtual ~Problem(){}
    virtual double *getResult() = 0;
    virtual bool solve() = 0;
protected:
    virtual double getFunctionVal(){}
    long size_;
    double *point_;
    double *constrains_non_eq_;
    bool **constrains_eq_;
};
class GradDesc : Problem{
public:
    GradDesc():Problem(){}
    GradDesc(int size,
             double *point,
             double *constr_non_eq,
             bool **constr_eq,
             double min_step_lenght,
             double min_eps,
             double min_iter): min_step_lenght_(min_step_lenght),
                               min_eps_(min_eps),
                               min_iter_(min_iter),
                               Problem(size, point, constr_non_eq, constr_eq){}
    virtual bool getGradientVal(){}
    bool solve() override {
        optimize();
    }
    double *getResult() override{}
    bool optimize() {
        // optimization, will use private methods
        // getNewPoint and getGradientNorm
    }
protected:
    bool getNewPoint(){}
    double getGradientNorm(){}

    double *grad_;
    double min_step_lenght_;
    double min_eps_;
    int min_iter_;
};
class PenaltyMethod : GradDesc{
public:
    PenaltyMethod():GradDesc(){}
    PenaltyMethod(int size,
                  double *point,
                  double *constr_non_eq,
                  bool **constr_eq,
                  double min_step_lenght,
                  double min_eps,
                  double min_iter,
                  int gamma_start,
                  double mult,
                  double accuracy):gamma_(gamma_start),
                                   mult_(mult),
                                   accuracy_(accuracy),
                                   GradDesc(size, point, constr_non_eq, constr_eq,min_step_lenght,min_eps,min_iter){}
    bool solve() override {
        for (int i = 0; i < 5 ; ++i) {
            optimize();
        }
    }
    double *getResult() override{}
protected:
    double getFunctionVal() override{}
    bool getGradientVal() override{}
private:
    int gamma_;
    double mult_;
    double accuracy_;
};

int main() {
    int size = 3;
    double *point = new double[size];
    double *constr_non_eq = new double[15];
    bool ** constr_eq = new bool*[size];
    for (int i = 0; i < size ; ++i) {
        constr_eq[i] = new bool[9];
    }
    PenaltyMethod *pm = new PenaltyMethod(size,point,constr_non_eq, constr_eq,1e-5,1e-5,50,1,10,1e-10);
    pm->solve();
    pm->getResult();
    return 0;
}

Напрягает нагромождение инициализации конструкторов и то что если у меня вдруг поменяется промежуточный метод оптимизации. То придется еще и от него наследовать метод Штрафных функций. В голове крутятся мысли по обобщению методов, но учитывая отсутствие опыта в С++ и незнакомство с шаблонами пока что приходится пользоваться такими вот костылями.

READ ALSO
Стиль/тема заголовка QDockWidget

Стиль/тема заголовка QDockWidget

Разбираюсь с QDockWidgetСтолкнулся с непонятной для меня вещью - под MS Windows заголовок окошка в доке отображается всегда одинаково, вне зависимости...

352
Сортировка строк и буква ё с++

Сортировка строк и буква ё с++

Нужно отсортировать слова, например: ёжик, Азбука, аромат, ЁжПроблема в том, что буква ё не сортируется

424