[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