[Bf-blender-cvs] [2e2f289d25b] functions: Vectorization support for Node UI

Jacques Lucke noreply at git.blender.org
Sat Apr 6 12:00:46 CEST 2019


Commit: 2e2f289d25bb89a6693017f1bce1193b1d571b17
Author: Jacques Lucke
Date:   Sat Apr 6 11:05:40 2019 +0200
Branches: functions
https://developer.blender.org/rB2e2f289d25bb89a6693017f1bce1193b1d571b17

Vectorization support for Node UI

===================================================================

M	release/scripts/startup/function_nodes/declaration/__init__.py
A	release/scripts/startup/function_nodes/declaration/vectorized.py
M	release/scripts/startup/function_nodes/graph.py
M	release/scripts/startup/function_nodes/inferencing.py
M	release/scripts/startup/function_nodes/nodes/combine_vector.py
M	release/scripts/startup/function_nodes/nodes/separate_vector.py
M	release/scripts/startup/function_nodes/socket_builder.py

===================================================================

diff --git a/release/scripts/startup/function_nodes/declaration/__init__.py b/release/scripts/startup/function_nodes/declaration/__init__.py
index 1cb3be0a431..bc5c67233b5 100644
--- a/release/scripts/startup/function_nodes/declaration/__init__.py
+++ b/release/scripts/startup/function_nodes/declaration/__init__.py
@@ -2,4 +2,5 @@ from . fixed_type import FixedSocketDecl
 from . dynamic_list import ListSocketDecl
 from . pack_list import PackListDecl
 from . tree_interface import TreeInterfaceDecl
-from . variadic import AnyVariadicDecl
\ No newline at end of file
+from . variadic import AnyVariadicDecl
+from . vectorized import VectorizedInputDecl, VectorizedOutputDecl
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/declaration/vectorized.py b/release/scripts/startup/function_nodes/declaration/vectorized.py
new file mode 100644
index 00000000000..8acd89275fe
--- /dev/null
+++ b/release/scripts/startup/function_nodes/declaration/vectorized.py
@@ -0,0 +1,66 @@
+import bpy
+from bpy.props import *
+from . base import SocketDeclBase
+from .. types import type_infos
+
+class VectorizedDeclBase:
+    def build(self, node_sockets):
+        data_type, name = self.get_type_and_name()
+        return [type_infos.build(
+            data_type,
+            node_sockets,
+            name,
+            self.identifier)]
+
+    def validate(self, sockets):
+        if len(sockets) != 1:
+            return False
+        data_type, name = self.get_type_and_name()
+        return self._data_socket_test(sockets[0],
+            name, data_type, self.identifier)
+
+    def amount(self):
+        return 1
+
+    @staticmethod
+    def Property():
+        return StringProperty(default="BASE")
+
+    def get_type_and_name(self):
+        stored = getattr(self.node, self.prop_name)
+        if stored == "BASE":
+            return self.base_type, self.base_name
+        elif stored == "LIST":
+            return self.list_type, self.list_name
+        else:
+            assert False
+
+
+class VectorizedInputDecl(VectorizedDeclBase, SocketDeclBase):
+    def __init__(self,
+            node, identifier, prop_name,
+            base_name, list_name,
+            base_type):
+        self.node = node
+        self.identifier = identifier
+        self.prop_name = prop_name
+        self.base_name = base_name
+        self.list_name = list_name
+        self.base_type = base_type
+        self.list_type = type_infos.to_list(base_type)
+
+
+class VectorizedOutputDecl(VectorizedDeclBase, SocketDeclBase):
+    def __init__(self,
+            node, identifier, prop_name, input_prop_names,
+            base_name, list_name,
+            base_type):
+        assert prop_name not in input_prop_names
+        self.node = node
+        self.identifier = identifier
+        self.prop_name = prop_name
+        self.input_prop_names = input_prop_names
+        self.base_name = base_name
+        self.list_name = list_name
+        self.base_type = base_type
+        self.list_type = type_infos.to_list(base_type)
diff --git a/release/scripts/startup/function_nodes/graph.py b/release/scripts/startup/function_nodes/graph.py
index dd2762c0d71..a7d5f5ec256 100644
--- a/release/scripts/startup/function_nodes/graph.py
+++ b/release/scripts/startup/function_nodes/graph.py
@@ -1,21 +1,33 @@
 from collections import namedtuple, defaultdict
 
-Edge = namedtuple("Edge", ["from_v", "to_v"])
-
 class DirectedGraph:
     def __init__(self, V, E):
-        assert all(isinstance(e, Edge) for e in E)
+        assert all(isinstance(e, tuple) for e in E)
         assert all(v1 in V and v2 in V for v1, v2 in E)
         self.V = set(V)
         self.E = set(E)
 
         self.outgoing = defaultdict(set)
         self.incoming = defaultdict(set)
+        self.neighbors = defaultdict(set)
         for v1, v2 in E:
             self.outgoing[v1].add(v2)
             self.incoming[v2].add(v1)
+            self.neighbors[v1].add(v2)
+            self.neighbors[v2].add(v1)
 
     def reachable(self, start_verts):
+        return self._reachable(start_verts, self.outgoing)
+
+    def reachable_inversed(self, start_verts):
+        return self._reachable(start_verts, self.incoming)
+
+    def connected(self, start_verts):
+        return self._reachable(start_verts, self.neighbors)
+
+    def _reachable(self, start_verts, next_map):
+        if start_verts in self.V:
+            start_verts = (start_verts, )
         assert all(v in self.V for v in start_verts)
 
         verts_to_check = set(start_verts)
@@ -23,7 +35,7 @@ class DirectedGraph:
         while len(verts_to_check) > 0:
             v = verts_to_check.pop()
             found_verts.add(v)
-            for prev_v in self.outgoing[v]:
+            for prev_v in next_map[v]:
                 if prev_v not in found_verts:
                     verts_to_check.add(prev_v)
         return found_verts
@@ -66,7 +78,7 @@ class DirectedGraphBuilder:
     def add_directed_edge(self, from_v, to_v):
         self.V.add(from_v)
         self.V.add(to_v)
-        self.E.add(Edge(from_v, to_v))
+        self.E.add((from_v, to_v))
 
     def build(self):
         return DirectedGraph(self.V, self.E)
diff --git a/release/scripts/startup/function_nodes/inferencing.py b/release/scripts/startup/function_nodes/inferencing.py
index 8366d9c7dd3..e48faba8b89 100644
--- a/release/scripts/startup/function_nodes/inferencing.py
+++ b/release/scripts/startup/function_nodes/inferencing.py
@@ -1,6 +1,7 @@
 from collections import namedtuple, defaultdict
 from . utils.graph import iter_connected_components
 from . types import type_infos
+from . tree_data import TreeData
 
 from . declaration import (
     FixedSocketDecl,
@@ -8,17 +9,27 @@ from . declaration import (
     PackListDecl,
     AnyVariadicDecl,
     TreeInterfaceDecl,
+    VectorizedInputDecl,
+    VectorizedOutputDecl,
 )
 
 DecisionID = namedtuple("DecisionID", ("node", "group", "prop_name"))
 
-def get_inferencing_decisions(tree_data):
-    decisions = dict()
+def get_inferencing_decisions(tree_data: TreeData):
     list_decisions = make_list_decisions(tree_data)
+    vector_decisions = make_vector_decisions(tree_data, list_decisions)
+    pack_list_decisions = make_pack_list_decisions(tree_data, list_decisions, vector_decisions)
+
+    decisions = dict()
     decisions.update(list_decisions)
-    decisions.update(make_pack_list_decisions(tree_data, list_decisions))
+    decisions.update(vector_decisions)
+    decisions.update(pack_list_decisions)
     return decisions
 
+
+# Inference list type decisions
+#################################################
+
 def make_list_decisions(tree_data):
     decision_users = get_list_decision_ids_with_users(tree_data)
     decision_links = get_list_decision_links(tree_data)
@@ -75,6 +86,10 @@ def iter_possible_list_component_types(component, decision_users, tree_data):
                         yield type_infos.to_base(data_type)
                 elif isinstance(other_decl, PackListDecl):
                     yield other_decl.base_type
+                elif isinstance(other_decl, VectorizedInputDecl):
+                    yield other_decl.base_type
+                elif isinstance(other_decl, VectorizedOutputDecl):
+                    yield other_decl.base_type
         for socket in decision_users[decision_id]["BASE"]:
             for other_node, other_socket in tree_data.iter_connected_sockets_with_nodes(socket):
                 other_decl = other_socket.get_decl(other_node)
@@ -84,8 +99,113 @@ def iter_possible_list_component_types(component, decision_users, tree_data):
                         yield data_type
                 elif isinstance(other_decl, PackListDecl):
                     yield other_decl.base_type
+                elif isinstance(other_decl, VectorizedInputDecl):
+                    yield other_decl.base_type
+                elif isinstance(other_decl, VectorizedOutputDecl):
+                    yield other_decl.base_type
+
+
+# Inference vectorization decisions
+########################################
+
+def make_vector_decisions(tree_data, list_decisions):
+    graph, socket_by_decision_id = get_vector_decisions_graph(tree_data)
 
-def make_pack_list_decisions(tree_data, list_decisions):
+    decisions = dict()
+    decision_ids_with_collision = set()
+
+    for initial_decision_id, decision in iter_obligatory_vector_decisions(graph, socket_by_decision_id, tree_data, list_decisions):
+        for decision_id in graph.reachable(initial_decision_id):
+            if decision_id in decisions:
+                if decisions[decision_id] != decision:
+                    decision_ids_with_collision.add(decision_id)
+            else:
+                decisions[decision_id] = decision
+
+    for decision_id in graph.V:
+        decisions.setdefault(decision_id, "BASE")
+
+    while len(decision_ids_with_collision) > 0:
+        collision_decision_id = decision_ids_with_collision.pop()
+        connected_decision_ids = graph.connected(collision_decision_id)
+        for decision_id in connected_decision_ids:
+            decisions.pop(decision_id, None)
+            decision_ids_with_collision.discard(decision_id)
+
+    return decisions
+
+def get_vector_decisions_graph(tree_data):
+    '''
+    Builds a directed graph.
+    Vertices in that graph are decision IDs.
+    A directed edge (A, B) means: If A is a list, then B has to be a list.
+    '''
+    from . graph import DirectedGraphBuilder
+    builder = DirectedGraphBuilder()
+    socket_by_decision_id = dict()
+
+    for node in tree_data.iter_nodes():
+        for decl, sockets in node.decl_map.iter_decl_with_sockets():
+            if isinstance(decl, VectorizedInputDecl):
+                decision_id = DecisionID(node, node, decl.prop_name)
+                builder.add_vertex(decision_id)
+                socket_by_decision_id[decision_id] = sockets[0]
+            elif isinstance(decl, VectorizedOutputDecl):
+                decision_id = DecisionID(node, node, decl.prop_name)
+                builder.add_vertex(decision_id)
+                socket_by_decision_id[decision_id] = sockets[0]
+                for input_prop_name in decl.input_prop_names:
+   

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list