Предложения по синтаксису для краткого выражения математической формулы - PullRequest
30 голосов
/ 24 мая 2010

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

Я разместил прототип в комментариях, его длина составляет около двухсот строк.

Прямо сейчас мой язык выглядит примерно так (ну, на самом деле будет выглядеть так):

// implies two nested loops j=0:N, i=0,j
(range(i) < j < N)[T(i,j) = (T(i,j) - T(j,i))/e(i+j)];

// implies summation over above expression
sum(range(i) < j < N))[(T(i,j) - T(j,i))/e(i+j)];

Я ищу возможные улучшения / расширения синтаксиса или просто разные идеи о выражении математических формул в видеясно и точно, насколько это возможно (на любом языке, не только C ++).

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

Спасибо.

Просто, чтобы уточнить и дать фактическую формулу, моя краткосрочная цель состоит в том, чтобы выразить следующее

alt textalt text

выражение кратко, где значения в <> уже вычислены как 4-мерные массивы.

Ответы [ 13 ]

0 голосов
/ 04 июня 2010

Возможно, вы захотите взглянуть на языки APLish для вдохновения.Работая с матрицей / массивом в целом, вы можете немного сократить краткость.Я собираюсь использовать Q ниже, и если я не прочитал ваш пост, ваше второе утверждение может быть записано как:

sum raze (T-flip T) div e

Чтобы понять T минус флип T, вам нужно взглянуть на пример.Представьте, что мы установили T для следующей матрицы:

0 1 2
3 4 5
6 7 8

flip T меняет два верхних измерения, что приводит к:

0 3 6
1 4 7
2 5 8

Так что T-flip T в основном T(i,j)-T(j,i), нонамного меньше печатает, и, следовательно, намного меньше подвержен ошибкам.

raze уменьшает массив до одного измерения, так что это выглядит так:

0 3 6
1 4 7
2 5 8

превращает его в это:

0 3 6 1 4 7 2 5 8

Наконец, sum суммируется;он в основном складывает всех членов своего списка, поэтому

sum 0 3 6 1 4 7 2 5 8

означает:

0+3+6+1+4+7+2+5+8

Реализация такого рода вещей в C ++ не так уж и сложна;Вы могли бы:

sum(raze((T-flip(T))/e))

с правильным уровнем перегрузки оператора.

Кстати, K еще более кратко:

+/,/(T-+:T)%e
0 голосов
/ 30 мая 2010

мой прототип (все еще нужно много работы и комментариев)

// #include "tensor/tensor.hpp"
// #include "typename.hpp"

#include <boost/spirit/home/phoenix/core/argument.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#define BOOST_FUSION_INVOKE_FUNCTION_OBJECT_MAX_ARITY PHOENIX_ARG_LIMIT
#include <boost/fusion/functional/invocation/limits.hpp>
#include <boost/fusion/functional.hpp>

#include <boost/fusion/include/intrinsic.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/vector_tie.hpp>
#include <boost/fusion/include/make_vector.hpp>

#include <boost/typeof/typeof.hpp>

namespace range_ {
    namespace detail {

        namespace phoenix = boost::phoenix;
        namespace fusion = boost::fusion;

        /// undefined or implicit object
        struct undefined {};

        template<int N>
        struct index {
            // index(boost::phoenix::argument<N>) {}
            typedef phoenix::actor<phoenix::argument<N> > argument;
            argument arg() const { return argument(); }
        };

        template<typename T, typename U = void>
        struct functional {
            typedef phoenix::actor<phoenix::value<T> > type;
            static type form(const T& t) { return type(t); }
        };

        template<typename T, typename U>
        struct functional<phoenix::actor<T>, U> {
            typedef phoenix::actor<T> type;
            static type form(const T& t) { return type(t); }
        };

        template<typename T>
        struct functional<undefined,T> {
            typedef typename functional<T>::type type;
            static type form(const undefined&) { return type(T()); }
        };

        template<int N, class L, class U, class T = undefined>
        struct expression;

        template<int N, class L, class U, class C>
        struct expression {
            typedef functional<L,U> lower_function;
            typedef functional<U,L> upper_function;

            expression(const L &lower, const U& upper, const C &cdr)
                : lower_(lower), upper_(upper), cdr_(cdr) {}

            template<class E>
            expression<N, L, U, E> operator()(const E &c) const {
                return expression<N, L, U, E>(lower_,  upper_, c);
            }

            template<class F>
            void operator[](const F &f) const {
#define TEXT(z, n, text) text
#define UNDEFINED_ARGUMENTS BOOST_PP_ENUM(PHOENIX_ARG_LIMIT, TEXT, undefined())
                evaluate<int>(f, fusion::make_vector(UNDEFINED_ARGUMENTS));
#undef TEXT
#undef UNDEFINED_ARGUMENTS
            }

            L lower_;
            U upper_;
            C cdr_;

            const L& left() const { return lower_; }

            const C& cdr() const {return cdr_; }

            template<typename T>
            typename functional<L,T>::type begin() const {
                return functional<L,T>::form(lower_);
            }

            template<typename T>
            typename functional<U,T>::type end() const {
                return functional<U,T>::form(upper_);
            }

            template<typename T, class F, class A>
            void evaluate(const F &f, const A &arguments) const {
                T i = this->begin<T>()(arguments);
#define AS_VECTOR(var, expr) BOOST_AUTO(var, fusion::as_vector(expr))
#define ADVANCE_C(seq) fusion::advance_c<N>(fusion::begin(seq))
                AS_VECTOR(b, fusion::erase(arguments, ADVANCE_C(arguments)));
                AS_VECTOR(a, fusion::insert_range(b, ADVANCE_C(b),
                                                  fusion::vector_tie(i)));
#undef ADVANCE_C
#undef AS_VECTOR
                while (fusion::invoke_function_object(this->end<T>(), a)) {
                    this->apply<T>(cdr_, f, a);
                    ++i;
                }
            }

            template<typename T, class E, class F, class V>
            void apply(const E &e, const F &f, const V &variables) const {
                e.template evaluate<T>(f, variables);
            }

            template<typename T, class F, class V>
            void apply(const undefined&, const F &f, const V &variables) const {
                fusion::invoke_function_object(f, fusion::as_vector(variables));
            }

        };

        template<int N, class  L, class U>
        expression<N, L, U>
        make_expression(const L &lower, const U& upper) {
            return expression<N, L, U>(lower, upper, undefined());
        }

        template<int N, class  L, class U>
        expression<N, L, U>
        make_expression(const expression<N, L, undefined> &expr, const U& right) {
            return expression<N, L, U>(expr.left(), right, undefined());
        }

        template<int N1, class L1, class U1, class T1,
                 int N2, class L2, class U2>
        expression<N2, L2, U2, expression<N1, L1, U1, T1> >
        operator,(const expression<N1, L1, U1, T1> &e1,
                  const expression<N2, L2, U2> &e2)  {
            return e2(e1);
        }

#define ARGUMENT(N) phoenix::actor<phoenix::argument<N> >
#define ACTOR_COMPOSITE(O,L,R)                                          \
        phoenix::actor<typename phoenix::as_composite<O, L, R>::type>


#define LOWER_BOUND_OPERATOR(op, eval, param)                           \
        template <typename T, int N>                                    \
        expression<N, param, undefined>                                 \
        operator op (const param& left, const index<N> &i) {            \
            return make_expression<N>(left, undefined());               \
        }


#define UPPER_BOUND_OPERATOR_INDEX(op, eval, param)             \
        template <typename T, int N>                            \
        expression<N, undefined,                                \
                   ACTOR_COMPOSITE(eval, ARGUMENT(N), param)>   \
        operator op (const index<N> &i, const param& e) {       \
            return make_expression<N>(undefined(),              \
                                      (ARGUMENT(N)() op e));    \
        }

#define UPPER_BOUND_OPERATOR_EXPRESSION(op, eval)                       \
        template <typename T, int N, class E>                           \
        expression<N, E, ACTOR_COMPOSITE(eval, ARGUMENT(N), T)>         \
        operator op (const expression<N, E, undefined> &left,           \
                     const T& right) {                                  \
            return make_expression(left, (ARGUMENT(N)() op right));     \
        }

#define UPPER_BOUND_OPERATOR(op, eval)                                  \
        UPPER_BOUND_OPERATOR_INDEX(op, eval, T)                         \
        UPPER_BOUND_OPERATOR_INDEX(op, eval, phoenix::actor<T>)         \
        UPPER_BOUND_OPERATOR_EXPRESSION(op, eval)

        LOWER_BOUND_OPERATOR( < , phoenix::less_eval, T)
        LOWER_BOUND_OPERATOR( < , phoenix::less_eval, phoenix::actor<T>)
        LOWER_BOUND_OPERATOR( <= , phoenix::less_equal_eval, T)
        LOWER_BOUND_OPERATOR( <= , phoenix::less_equal_eval, phoenix::actor<T>)

        UPPER_BOUND_OPERATOR( < , phoenix::less_eval)
        UPPER_BOUND_OPERATOR( <= , phoenix::less_equal_eval)

    }

}


namespace index {
    using namespace boost::phoenix;
    boost::phoenix::actor<boost::phoenix::argument<0> > const i;
    boost::phoenix::actor<boost::phoenix::argument<1> > const j;
    boost::phoenix::actor<boost::phoenix::argument<2> > const k;
    boost::phoenix::actor<boost::phoenix::argument<3> > const l;

    template<int N>
    range_::detail::index<N> range(const boost::phoenix::actor<
                                   boost::phoenix::argument<N> >&) {
        return range_::detail::index<N>();
    }
    template<int N, class F>
    range_::detail::index<N> range(const boost::phoenix::actor<
                                   boost::phoenix::argument<N> >&,
                                   const F &f) {
        // return range_::detail::index<N>();
        throw std::exception("not implemented");
    }



}

int main(){

    using namespace index;

    // formula domain language rough prototype
    // stuff in brackets can be any valid phoenix lambda expression

    // physicist notation, lower bound may be implicit
    (range(i) <= j, 3 <= range(j) < 4)[std::cout << i << " " << j << std::endl];

    // implicit physicist notation, not done yet
    //(range(i) < range(j) < 4)[...]

    // programmer notation, same as above , but order is reversed
    (3 <= range(j) < 4)(range(i) <= j)[std::cout << i << " " << j << std::endl];

    // ignore, some early prototype for lambda tensor
    // size_t N = 4;
    // tensor::tensor<4> T(N,N,N,N);

     // tensor::function<tensor::tensor<4> > T_(T);
    // (range(j) < 4)(range(i) <= j)[std::cout << T_(i,j,0,0)];

    // (range(i) < j, range(j) < N)[T_(i,j,0,0) = T_(j,i,0,0)];
    // sum(j < val(N))[T_(i,j,0,0)];

}
0 голосов
/ 24 мая 2010

Я бы посчитал выражающими математические формулы, как они сделаны в LaTeX .В конце концов, LaTeX уже хорошо определен и задокументирован в этой области.

...