22

我想实现一个节点接口,基本上是一个DAG,其中每个节点对其输入连接执行操作,并输出一些东西(你可以连接到另一个节点)

一些示例应用程序:


作为第一个目标,我想要一个只有 2 个节点的图形应用程序。一个“数字”,它简单地输出一个固定的数字,一个“加”节点,它接受两个输入并输出两者的总和。

正如人们到目前为止所回答的那样,我对如何在代码中表示数据有一个粗略的想法,例如在 Python 的伪代码中:

class Number:
    def __init__(self, value):
        self.value = value

    def eval(self):
        return self.value

class Add:
    def __init__(self, input1, input2):
        self.input1 = input1
        self.input2 = input2

    def eval(self):
        return self.input1.eval() + self.input2.eval()


a = Number(20)
b = Number(72)

adder = Add(a, b)
print adder.eval()

我将如何围绕此包装自定义 GUI?像下面这样的东西,但手绘略少!

节点 UI 模型

我从哪里开始?我目前计划用 Objective-C/Cocoa 编写它,尽管我非常愿意接受其他语言的建议。

4

7 回答 7

3

我将从建模一些基本接口开始(在 OOP 意义上,而不是 GUI 意义上)。在我看来,您将拥有一个接受输入集合和单个输出的节点。您没有说明数据类型有多广泛,但您需要一些合适的方法来表示您的输入/输出。对于您的第一个目标,这可能是一个整数。

在一些通用的 C 风格 OOP 语言中(希望它有意义):

class Node<T> {
    Node<T>[] inputs;
    T eval();
}

class AdderNode extends Node<int> {
    int eval() {
        int accum = 0;
        for (inputs : i)
            accum += i.eval();
        return i;
    }
}

class ConstNode<int I> extends Node<int> {
    int eval() { return I; }
}

AdderNode a;
a.inputs.add(ConstNode<2>());
a.inputs.add(ConstNode<3>());
a.eval();

您可以通过将 int 替换为一些抽象类、泛型或接口来对此进行扩展。当然,实际实现会因实际语言而异。

于 2009-03-14T05:38:55.460 回答
2

我将从对有趣的操作进行建模开始。最终,您会将它们连接到 UI,但那是方向盘和油门踏板,而不是引擎。

您尝试构建的内容与编程语言有很多共同点:变量、值、类型、表达式、评估等。许多隐喻都是适用的,可能会提供一些指导。

如果您使用的是 .NET 3.5,则可以选择Expression Trees,它允许您在运行时表示和编译代码表达式。

例如,为您的第一个目标建模:

using System.Linq.Expressions;

ConstantExpression theNumber2 = Expression.Constant(2);
ConstantExpression theNumber3 = Expression.Constant(3);

BinaryExpression add2And3 = Expression.Add(theNumber2, theNumber3);

要调用表达式,我们需要add2And3用一个方法包装。这是通过 lambda 表达式完成的:

Expression<Func<int>> add2And3Lambda = Expression.Lambda<Func<int>>(add2And3);

Func<int>表示一个不带参数并返回一个int. 在 C# 中,由 表示的代码add2And3Lambda将是:

() => 2 + 3

所以我们有一个表达式树,它的根是一个方法。因为方法是可调用的,我们可以将树编译成底层委托类型的实例:

Func<int> add2And3Func = add2And3Lambda.Compile();

现在我们可以调用我们构建的代码:

int theNumber5 = add2And3Func();

支持 .NET 语言可用的每个表达式。

想象一下图中的每个节点都有一个Expression关联。这可能会让您了解表达式树的强大功能以及它们如何帮助您完成这项任务。

于 2009-03-14T06:32:34.660 回答
1

我发现了一些关于在 Cocoa 中实现这样一个接口的有用信息:

于 2009-05-23T18:37:02.720 回答
1

所有这些节点系统的共同点是它们描述了一种函数式编程语言。一个函数接受多个参数并返回一个结果,无论它的设计目的是什么。一些例子:

  • 图形:模糊(图像、内核、半径)-> 图像

  • 数学:加(数字,数字)-> 数字

  • 关系:过滤器(表,谓词)-> 表

基本上,这归结为Func<object[], object>(C#)之类的函数签名。

您将面临如何使您的节点系统持久化的问题。你想让一个节点的结果只被另一个节点(树)或多个节点(图)用作参数吗?

一棵树的例子,直接有一个子节点的参数:

Add(
  Multiply(
    Constant(5),
    Constant(4)
  ),
  Multiply(
    Constant(5),
    Constant(3)
  )
)

图示例,将所有节点存储在列表中并且仅使用引用:

A := Constant(5)
B := Constant(4)
C := Constant(3)

D := Func(Multiply, A, B)
E := Func(Multiply, A, C)

F := Func(Add, D, E)
于 2009-03-14T09:45:37.753 回答
1

我在研究类似的解决方案时偶然发现了这个线程。最近我在 github https://github.com/nodebox/nodebox上发现了一个不错的项目, 这似乎正是您正在寻找的。至少可以从项目中提取和采用编辑器组件。

问候,斯蒂芬

于 2017-10-29T12:52:51.587 回答
0

也许bwise有什么有趣的事情?

本页下半部分显示了使用 bwise 创建一个以两个数字作为输入的乘法块的示例。

于 2009-05-13T21:15:43.947 回答
0

我实现了一个执行图,就像你在这个项目中描述的那样: GRSFramework

源代码可以在这里找到。

目前,我正致力于在项目ExecutionGraph中发布该系统的更好、更干净的版本。
你可能也会感兴趣。

然后还有来自 Google 的 TensorFlow 库,它有一个类似的系统实现了TensorFlow

于 2017-03-12T21:14:56.507 回答