简洁表达数学公式的语法建议

发布于 2024-09-03 10:29:01 字数 832 浏览 2 评论 0 原文

我正在 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

简洁表达,其中值位于 <>< /code> 已计算为 4 维数组。

I am developing functional domain specific embedded language within C++ to translate formulas into working code as concisely and accurately as possible.

I posted a prototype in the comments, it is about two hundred lines long.

Right now my language looks something like this (well, actually is going to look like):

// 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)];

I am looking for possible syntax improvements/extensions or just different ideas about expressing mathematical formulas as clearly and precisely as possible (in any language, not just C++).

Can you give me some syntax examples relating to my question which can be accomplished in your language of choice which consider useful. In particular, if you have some ideas about how to translate the above code segments, I would be happy to hear them.

Thank you.

Just to clarify and give an actual formula, my short-term goal is to express the following

alt textalt text

expression concisely where values in <> are already computed as 4-dimensional arrays.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

耶耶耶 2024-09-10 10:29:01

如果您要为从头开始的世界(我从您的 MP2 方程中猜测)编写此内容,您希望使其非常容易且清晰地表达尽可能接近数学定义的事物。

其一,我不会使用复杂的 range 函数。让它定义一个循环,但如果您想要嵌套循环,请同时指定它们:

所以而不是

(range(i) < j < N)[T(i,j) = (T(i,j) - T(j,i))/e(i+j)];

使用

循环(j,0,N)[循环(i,0,j)[T(i,j) = (T(i,j) - T(j,i))/e(i+j)]]

对于和和积之类的东西,使语法“继承”它是一个循环的事实。

因此,不要

sum(range(i) < j < N))[(T(i,j) - T(j,i))/e(i+j)];

使用

sum(j,0,n)[循环(i,0,j)[(T(i,j) - T(j,i))/e(i+j)]]

或如果您需要双和

sum(j,0,n)[sum(i,0,j)[(T(i,j) - T(j,i))/e(i+j)] ]

由于看起来您正在尝试表示量子力学运算符,因此请尝试使您的语言结构尽可能与运算符在 1-1 的基础上匹配。这样就很容易翻译(并且清楚正在翻译的内容)。

编辑添加,

因为您正在研究量子化学,所以它相当简单(至少就语法而言)。您定义的运算符始终处理其右侧的内容,然后您唯一需要的其他东西是括号来对运算符停止的位置进行分组。

爱因斯坦表示法很有趣,您无需指定索引或界限,并且由于约定而隐含它们,但这并不能形成清晰的代码,而且更难以思考。

对于总和,即使隐含了界限,它们也总是很容易根据上下文计算出来,因此您应该始终让人们指定它们。

sum(i,0,n)sum(j,0,i)sum(a,-j,j)sum(b,-i,i)....

由于每个运算符都向右运算,因此其变量是已知的,因此 j 可以了解 i,a 可以了解 i 和 j,b 可以了解 i、j 和 a。

根据我与量子化学家的经验(我也是其中之一!),他们不喜欢与他们编写的内容有很大差异的复杂语法。他们很乐意将双倍和三倍和以及积分分成单数集合,因为无论如何这些都只是简写。

对称性也不会那么难。它只是交换和加法或乘法的集合。我会做一些指定操作,其中包含相同且可以交换的元素列表:

c2v(sigma_x,a,b)a+b

这表示 a 和 b 可以被视为相同的粒子c2v 操作。这意味着任何带有 a 和 b 的方程(例如后面的​​ a+b)都应该转换为 c2v 变换的线性组合。 sigma_x 是您想要应用于函数 (a+b) 的 c2v 中的运算。如果我没记错的话,那就是 1/sqrt(2)((a+b)+(b+a))。但我这里没有对称性书,所以这可能是错误的。

If you're going to be writing this for the ab-initio world (which I'm guessing from your MP2 equation) you want to make it very easy and clear to express things as close to the mathematical definition that you can.

For one, I wouldn't have the complicated range function. Have it define a loop, but if you want nested loops, specify them both:

So instead of

(range(i) < j < N)[T(i,j) = (T(i,j) - T(j,i))/e(i+j)];

use

loop(j,0,N)[loop(i,0,j)[T(i,j) = (T(i,j) - T(j,i))/e(i+j)]]

And for things like sum and product, make the syntax "inherit" from the fact that it's a loop.

So instead of

sum(range(i) < j < N))[(T(i,j) - T(j,i))/e(i+j)];

use

sum(j,0,n)[loop(i,0,j)[(T(i,j) - T(j,i))/e(i+j)]]

or if you need a double sum

sum(j,0,n)[sum(i,0,j)[(T(i,j) - T(j,i))/e(i+j)]]

Since it looks like you're trying to represent quantum mechanical operators, then try to make your language constructs match the operator on a 1-1 basis as closely as possible. That way it's easy to translate (and clear about what's being translated).

EDITED TO ADD

since you're doing quantum chemistry, then it's fairly easy (at least as syntax goes). You define operators that always work on what's to the right of them and then the only other thing you need are parenthesis to group where an operator stops.

Einstein notation is fun where you don't specify the indices or bounds and they're implied because of convention, however that doesn't make clear code and it's harder to think about.

For sums, even if the bounds implied, they're always easy to figure out based on the context, so you should always make people specify them.

sum(i,0,n)sum(j,0,i)sum(a,-j,j)sum(b,-i,i)....

Since each operator works to the right, its variables are known, so j can know about i, a can know about i and j and b can know about i,j, and a.

From my experience with quantum chemists (I am one too!) they don't like complicated syntax that differs much from what they write. They are happy to separate double and triple sums and integrals into a collection of singles because those are just shorthand anyway.

Symmetry isn't going to be that hard either. It's just a collection of swaps and adds or multiplies. I'd do something where you specify the operation which contains a list of the elements that are the same and can be swapped:

c2v(sigma_x,a,b)a+b

This says that a and b are can be considered identical particles under a c2v operation. That means that any equation with a and b (such as the a+b after it) should be transformed into a linear combination of the c2v transformations. the sigma_x is the operation in c2v that you want applied to your function, (a+b). If I remember correctly, that's 1/sqrt(2)((a+b)+(b+a)). But I don't have my symmetry book here, so that could be wrong.

早茶月光 2024-09-10 10:29:01

我希望循环之间有更牢固的分离。例如,我更喜欢第二个示例的替代表示法:

sum(range(j) < N)[sum(range(i) < j)[(T(i,j) - T( j,i))/e(i+j)]]

我也发现范围语法很困难。我认为范围应该是单个组件。我更喜欢这样的东西:

j = range_iter(0,N)

这将为 range x(0,N); 打开j = range.begin(); 或我现在想不出的替代方案。

您甚至可以:

j = range_iter(inc(0) => exc(N)); 对于 j 迭代 [0,N)。

不管怎样,有趣的想法。你的结果函数可以组合吗?您可以请求域名信息吗?

I would prefer a more solid separation between loops. For example, I'd prefer this alternative notation to your second example:

sum(range(j) < N)[sum(range(i) < j)[(T(i,j) - T(j,i))/e(i+j)]]

I also find the range syntax difficult. I think a range should be a single component. I'd prefer something like so:

j = range_iter(0,N)

That would open for range x(0,N); j = range.begin(); or alternatives I can't think up right now.

You could even:

j = range_iter(inc(0) => exc(N)); for j iterates over [0,N).

Anyway, interesting idea. Can your resulting functions be composed? Can you request domain information?

冷夜 2024-09-10 10:29:01

如果您正在寻找简单性,您应该进一步考虑循环的隐式性。 类似的操作

T( i < j , j < N ) = ( T(i,j) - T(j,i) )/e(i+j)

例如,如果您重写赋值运算符 = 以使其正常运行,例如 a(i) = b(i) + c(i) 但行为正常,则 会起作用就像 a(i<5) = b(i) + c(i) 的求和。假设求和从 0 开始,除非指定下限,例如 a(3,检查作为求和索引出现的符号上限/下限,并根据需要进行双倍求和。如果您希望语法强制明确,您可以定义一个单独的求和运算符 s=

T( i < j , j < N ) s= ( T(i,j) - T(j,i) )/e(i+j)

我认为您无法获得比这更清晰的结果,并且仍然具有一些通用的可用性。至于您的短期目标,可以使用在索引首次出现的同时指定求和索引的概念来编写。

E_MP2 s= EV( i < n1 , j < n2 , a < n3 , b < n4 ) *
         2 ( EV(a,b,i,j) - EV(a,b,j,i) ) / ( e(i)+e(j)-e(a)-e(b) )

您明确声明这是一个总和(使用 s=),然后使该运算符从索引出现的第一个实例中获取求和索引和限制值。具体来说,您还可以使用类似的语法(假设现在 a,b 固定,i,j 根据您的示例),

E_MP2 s=(i<j,j<N) EV(i,j,a,b) *
                  2 ( EV(a,b,i,j) - EV(a,b,j,i) ) / ( e(i)+e(j)-e(a)-e(b) )

这在符号上非常清晰。

然后,您可以继续进一步采用这个概念,例如定义一个执行相同操作的集成运算符i=。即,它查找用限制标记的变量实例,然后继续对这些变量的表达式进行积分,类似于

F i=(0<x<Pi) x^-1 * exp(-I x^2)

求和,您可以在 x 第一次出现时指定限制,

F i= x[0,Pi]^-1 * exp(-I x^2)

其中方括号用于区分符号和求和,这样您就不必使用 i=s=
并且可以同时使用求和和积分:

F(i) = G(i,j<10) * x[0,inf]^-1 * H(i,j,x)

If you're looking for simplicity you should take the implicitness of the loops even further. E.g., something like this

T( i < j , j < N ) = ( T(i,j) - T(j,i) )/e(i+j)

will work if you rewrite the assignment operator = to behave normally for something like a(i) = b(i) + c(i) but behave like a summation for a(i<5) = b(i) + c(i). Assume summation starts from 0 unless the lower limit is specified, e.g. a(3<i<5), check for symbolic upper/lower limits that appear as summation indices and make double sums as necessary. If you want the syntax to force explicitness you could define a separate sum operator s=

T( i < j , j < N ) s= ( T(i,j) - T(j,i) )/e(i+j)

I don't think you can get any cleaner than this and still have some general purpose usability. As for your short term goal, using the notion of specifying the summation index at the same time that the index first appears you could write.

E_MP2 s= EV( i < n1 , j < n2 , a < n3 , b < n4 ) *
         2 ( EV(a,b,i,j) - EV(a,b,j,i) ) / ( e(i)+e(j)-e(a)-e(b) )

where you explicitly state that this is a sum (using s=) making that operator then take the summation indices and limiting values from the first instance an index appears. Specifically you could also use a syntax like (assuming now a,b fixed and i,j as per your example)

E_MP2 s=(i<j,j<N) EV(i,j,a,b) *
                  2 ( EV(a,b,i,j) - EV(a,b,j,i) ) / ( e(i)+e(j)-e(a)-e(b) )

which is quite clear notationally.

You could then go on and take this concept even further by, e.g., defining an integration operator i= that does the same thing. I.e. it looks for instances of variables that are marked down with limits and then proceeds to integrate the expression with respect to those variables

F i=(0<x<Pi) x^-1 * exp(-I x^2)

similarly to the summation you could specify the limit when x first occurs

F i= x[0,Pi]^-1 * exp(-I x^2)

where the square brackets serve to differentiate the notation from summation, so that you don't have to use i= or s=
and can use both summation and integration at the same time:

F(i) = G(i,j<10) * x[0,inf]^-1 * H(i,j,x)
左秋 2024-09-10 10:29:01

我对 Phoenix 不熟悉,只能对其功能做出假设。

我一直很喜欢 Haskell 允许我将范围表达为列表理解的方式。它可以很好地从实际的数学符号转换为编程语言结构。

[ i + j | i <- [1..10], j <- [1..10] ]

最终会是这样的:

[ i + j | i = range(1,10), j = range(1,10) ]

不幸的是,我真的不知道凤凰城是否有可能实现这样的事情。

I'm not familiar with Phoenix and can only make assumptions about it's capabilities.

I've always liked the way Haskell allows me to express ranges as a list comprehension. It translates nicely from the actual mathematical notation into the programming language construct.

[ i + j | i <- [1..10], j <- [1..10] ]

would end up as something like:

[ i + j | i = range(1,10), j = range(1,10) ]

Unfortunately I really don't know if something like this is even possible with Phoenix.

黯然 2024-09-10 10:29:01
T = T - T'/e;

或者,如果您没有在所有 T 上进行操作

T(0:i,0:j) = T(0:i,0:j) - T(0:i,0:j)'/e(0:i,0:j)
T = T - T'/e;

or, if you're not operating on all of T

T(0:i,0:j) = T(0:i,0:j) - T(0:i,0:j)'/e(0:i,0:j)
当爱已成负担 2024-09-10 10:29:01

我不喜欢你指定“三角形”二维范围的方式。
我希望看到类似的内容:

(i,j) in range(0..j,0..N)

例如,这可能会导致:

X = sum(f(i,j) for (i,j) in range(0..j,0..N));

AFAIK 这不是现有的语言,但由于您正在创建自己的语法...我对在中使用 j 的能力表示怀疑i 的范围表达式,但你找到了一种方法:-)

I don't like the way you specify that "triangular" 2d range.
I'd like to see something like:

(i,j) in range(0..j,0..N)

for example, which could then lead to:

X = sum(f(i,j) for (i,j) in range(0..j,0..N));

AFAIK This is not an existing language, but since you're creating your own syntax... I'm doubtful about the ability to use j in the range expression for i, but you found a way in yours :-)

怀中猫帐中妖 2024-09-10 10:29:01

我不确定这些公式有多复杂,但如果你的 API 看起来更像数学领域而不是标准 C++(使用运算符重载和模板元编程很容易完成),我猜你应该考虑开发领域特定语言 (DSL)。当您尝试使用一种语言(如您的情况)执行此操作时,它被称为内部 DSL,尽管它有一些优点,但也有很多缺点。您应该最了解您的需求,但是我想建议您查看外部 DSL 的工具,这些工具是专门针对特定领域的小型外部语言。看看Jetbrains MPS和Eclipse Xtext,这是两个开源工具,可用于快速外部DSL开发。

I am not sure how complicated those formulas will be, but if get to the point when your API looks more like that math domain than standard C++ (which is using operator overloading and template metaprogramming done quite easily), I would guess you should consider developing a Domain Specific Language (DSL). When you are trying to do it in a language (like in your case) it is called internal DSL and although it has some advantages, it has many disadvantages. You should know your requirements best, however I want to suggest you looking at tools for external DSLs, which are small external languages specialized for certain domain. Look at Jetbrains MPS and Eclipse Xtext, those are two open source tools, which can be used for rapid external DSL development.

你与清晨阳光 2024-09-10 10:29:01

我会好好阅读 Project Fortress 博客,它有一些鼓舞人心的帖子编程语言的数学简明符号。

I would give a good read to the Project Fortress blog, it has some inspiring posts on mathematical concise notations for a programming language.

久夏青 2024-09-10 10:29:01

我会考虑 表达数学公式,因为它们是在 LaTeX 中完成的。毕竟,LaTeX 在该领域已经有明确的定义和完善的文档。

I would consider expressing math formulas as they are done in LaTeX. After all, LaTeX is already well-defined and well-documented in this area.

一梦等七年七年为一梦 2024-09-10 10:29:01

我的原型(显然仍然需要大量工作和评论)

// #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)];

}

my prototype (still needs lots of work obviously, and comments)

// #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)];

}
羁绊已千年 2024-09-10 10:29:01

您可能想看看 APLish 语言以获取灵感。通过将矩阵/数组作为一个整体来处理,你可以大大降低简洁性。我将在下面使用 Q,除非我误读了您的帖子,否则您的第二个陈述可以写为:

sum raze (T-flip T) div e

要理解 T 减去翻转 T,您需要看一个示例。想象一下,我们将 T 设置为以下矩阵:

0 1 2
3 4 5
6 7 8

翻转 T 交换顶部两个维度,这会导致:

0 3 6
1 4 7
2 5 8

所以 T-flip T 基本上是 T(i,j)-T(j, i) 但打字次数少了很多,因此出错的可能性也少了很多。

raze 将数组缩减为一维,因此 razing this:

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

You may want to look at APLish languages for inspiration. By working with the matrix/array as a whole, you can get the brevity down quite a bit. I'm going to use Q below, and unless I misread your post, your second statement can be written as:

sum raze (T-flip T) div e

To understand T minus flip T, you need to look at an example. Imagine we have T set to the following matrix:

0 1 2
3 4 5
6 7 8

flip T swaps the top two dimensions, which results in:

0 3 6
1 4 7
2 5 8

So T-flip T is basically T(i,j)-T(j,i) but a lot less typing, and thus a lot less error-prone.

The raze reduces an array to a single dimension, so razing this:

0 3 6
1 4 7
2 5 8

turns it into this:

0 3 6 1 4 7 2 5 8

Finally, the sum is sum-over; it basically adds up all of the members of its list, so

sum 0 3 6 1 4 7 2 5 8

means:

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

Implementing this kind of thing in C++ isn't that difficult; you could:

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

with the right level of operator overloading.

By the way, K is even more brief:

+/,/(T-+:T)%e
昔日梦未散 2024-09-10 10:29:01

封装!

我相信您会找到一些平衡简洁和清晰的语法。无论它有多好,通过提供封装都会大大改善它。因此,

qty = sum(range(i) < j < N))[(T(i,j) - T(j,i))/e(i+j)];

您可以使用

Texpr = (T(i,j) - T(j,i))/e(i+j);
RangeExpr = (range(i) < j < N);
qty = sum(RangeExpr)[ Texpr ];

That 来代替,这可能会给您带来更冗长的语法。

PS:这不是Mathematica吗? Mathematica C/C++ 语言界面

Encapsulate!

I'm sure you'll find some syntax that balances concision and clarity. However good it is, it will be vastly improved by providing encapsulation. So instead of

qty = sum(range(i) < j < N))[(T(i,j) - T(j,i))/e(i+j)];

You could have

Texpr = (T(i,j) - T(j,i))/e(i+j);
RangeExpr = (range(i) < j < N);
qty = sum(RangeExpr)[ Texpr ];

That might afford you more verbosity in the syntax.

PS: Isn't this Mathematica? Mathematica C/C++ Language Interface

人间不值得 2024-09-10 10:29:01

您应该查看用于 Haskell 列表理解 的语法。

You should have a look at syntax used for Haskell's list comprehension.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文