[Bf-blender-cvs] [dee5ee40e01] functions: actually run the inferencer on a node tree

Jacques Lucke noreply at git.blender.org
Wed Mar 13 16:21:51 CET 2019


Commit: dee5ee40e01bd33671e79b8b7f221eefac2db107
Author: Jacques Lucke
Date:   Wed Mar 13 16:21:30 2019 +0100
Branches: functions
https://developer.blender.org/rBdee5ee40e01bd33671e79b8b7f221eefac2db107

actually run the inferencer on a node tree

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

M	release/scripts/startup/function_nodes/base.py
M	release/scripts/startup/function_nodes/inferencer.py
M	release/scripts/startup/function_nodes/nodes/function_input.py
M	release/scripts/startup/function_nodes/nodes/function_output.py
M	release/scripts/startup/function_nodes/socket_decl.py
M	release/scripts/startup/function_nodes/sockets.py
M	release/scripts/startup/function_nodes/test_inferencer.py
A	release/scripts/startup/function_nodes/update_sockets.py

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

diff --git a/release/scripts/startup/function_nodes/base.py b/release/scripts/startup/function_nodes/base.py
index 5113d167851..8af190b9903 100644
--- a/release/scripts/startup/function_nodes/base.py
+++ b/release/scripts/startup/function_nodes/base.py
@@ -46,12 +46,25 @@ class BaseSocketDecl:
 
 class FunctionNode(BaseNode):
     def init(self, context):
+        self.rebuild()
+
+    def rebuild(self):
+        self.inputs.clear()
+        self.outputs.clear()
+
         inputs, outputs = self.get_sockets()
         for socket_decl in inputs:
             socket_decl.build(self, self.inputs)
         for socket_decl in outputs:
             socket_decl.build(self, self.outputs)
 
+    def rebuild_existing_sockets(self):
+        amount_in = len(self.inputs)
+        amount_out = len(self.outputs)
+        self.rebuild()
+        assert amount_in == len(self.inputs)
+        assert amount_out == len(self.outputs)
+
     def get_sockets():
         return [], []
 
diff --git a/release/scripts/startup/function_nodes/inferencer.py b/release/scripts/startup/function_nodes/inferencer.py
index 68bdf9768a0..45131c30f59 100644
--- a/release/scripts/startup/function_nodes/inferencer.py
+++ b/release/scripts/startup/function_nodes/inferencer.py
@@ -3,6 +3,7 @@ class Inferencer:
         self.type_infos = type_infos
         self.finalized_ids = dict()
         self.constraints = set()
+        self.decisions = dict()
 
     def insert_final_type(self, id, data_type):
         self.finalized_ids[id] = data_type
@@ -11,14 +12,15 @@ class Inferencer:
         constraint = EqualityConstraint(ids)
         self.constraints.add(constraint)
 
-    def insert_list_constraint(self, list_ids, base_ids=tuple()):
-        constraint = ListConstraint(list_ids, base_ids, self.type_infos)
+    def insert_list_constraint(self, list_ids, base_ids=tuple(), decision_id=None):
+        constraint = ListConstraint(list_ids, base_ids, decision_id, self.type_infos)
         self.constraints.add(constraint)
 
     def finalize_id(self, id, data_type):
         if id in self.finalized_ids:
             if self.finalized_ids[id] != data_type:
-                raise CannotInferenceError()
+                msg = f"Conflicting type for {id}: {self.finalized_ids[id]} vs. {data_type}"
+                raise ConflictingTypesError(msg)
         else:
             self.finalized_ids[id] = data_type
 
@@ -26,25 +28,41 @@ class Inferencer:
         for id in ids:
             self.finalize_id(id, data_type)
 
+    def make_decision(self, decision_id, value):
+        assert decision_id not in self.decisions
+        self.decisions[decision_id] = value
+
     def inference(self):
+        '''
+        Tries to find a solution for all constraints.
+        Raises InferencingError when it is impossible
+        to find a solutions.
+        Returns True, when every id has been mapped to
+        a data type. Otherwise False.
+        '''
         while len(self.constraints) > 0:
             handled_constraints = set()
 
             for constraint in self.constraints:
-                if constraint.try_finalize(self.finalized_ids, self.finalize_ids):
+                if constraint.try_finalize(self.finalized_ids, self.finalize_ids, self.make_decision):
                     handled_constraints.add(constraint)
 
             if len(handled_constraints) == 0:
-                raise CannotInferenceError()
+                return False
 
             self.constraints -= handled_constraints
 
+        return True
+
     def get_final_type(self, id):
-        return self.finalized_ids[id]
+        return self.finalized_ids.get(id, None)
+
+    def get_decisions(self):
+        return self.decisions
 
 
 class Constraint:
-    def try_finalize(self, finalized_ids, do_finalize):
+    def try_finalize(self, finalized_ids, do_finalize, make_decision):
         raise NotImplementedError()
 
 class EqualityConstraint(Constraint):
@@ -54,7 +72,7 @@ class EqualityConstraint(Constraint):
     def can_be_finalized(self, finalized_ids):
         return any(id in finalized_ids for id in self.ids)
 
-    def try_finalize(self, finalized_ids, finalize_do):
+    def try_finalize(self, finalized_ids, finalize_do, make_decision):
         for id in self.ids:
             if id in finalized_ids:
                 finalize_do(self.ids, finalized_ids[id])
@@ -62,27 +80,45 @@ class EqualityConstraint(Constraint):
         return False
 
 class ListConstraint(Constraint):
-    def __init__(self, list_ids, base_ids, type_infos):
+    def __init__(self, list_ids, base_ids, decision_id, type_infos):
         self.list_ids = set(list_ids)
         self.base_ids = set(base_ids)
+        self.decision_id = decision_id
         self.type_infos = type_infos
 
-    def try_finalize(self, finalized_ids, finalize_do):
+    def try_finalize(self, finalized_ids, finalize_do, make_decision):
         for id in self.list_ids:
             if id in finalized_ids:
                 list_type = finalized_ids[id]
+                if not self.type_infos.is_list(list_type):
+                    raise NoListTypeError()
                 base_type = self.type_infos.to_base(list_type)
                 finalize_do(self.list_ids, list_type)
                 finalize_do(self.base_ids, base_type)
+                if self.decision_id is not None:
+                    make_decision(self.decision_id, base_type)
                 return True
         for id in self.base_ids:
             if id in finalized_ids:
                 base_type = finalized_ids[id]
+                if not self.type_infos.is_base(base_type):
+                    raise NoBaseTypeError()
                 list_type = self.type_infos.to_list(base_type)
                 finalize_do(self.base_ids, base_type)
                 finalize_do(self.list_ids, list_type)
+                if self.decision_id is not None:
+                    make_decision(self.decision_id, base_type)
                 return True
         return False
 
-class CannotInferenceError(Exception):
-    ...
+class InferencingError(Exception):
+    pass
+
+class ConflictingTypesError(InferencingError):
+    pass
+
+class NoListTypeError(InferencingError):
+    pass
+
+class NoBaseTypeError(InferencingError):
+    pass
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/function_input.py b/release/scripts/startup/function_nodes/nodes/function_input.py
index 2d6a4d2e15b..75756eb1b36 100644
--- a/release/scripts/startup/function_nodes/nodes/function_input.py
+++ b/release/scripts/startup/function_nodes/nodes/function_input.py
@@ -1,6 +1,6 @@
 import bpy
 from .. base import BaseNode
-from .. sockets import info
+from .. sockets import type_infos
 
 class FunctionInputNode(BaseNode, bpy.types.Node):
     bl_idname = "fn_FunctionInputNode"
@@ -29,7 +29,7 @@ class FunctionInputNode(BaseNode, bpy.types.Node):
             text="", icon="X", settings=(index, ))
 
     def new_socket(self, data_type):
-        info.build(data_type, self.outputs, "Input")
+        type_infos.build(data_type, self.outputs, "Input")
 
     def remove_socket(self, index):
         self.outputs.remove(self.outputs[index])
diff --git a/release/scripts/startup/function_nodes/nodes/function_output.py b/release/scripts/startup/function_nodes/nodes/function_output.py
index ffd9e012b28..8a4f4767ab7 100644
--- a/release/scripts/startup/function_nodes/nodes/function_output.py
+++ b/release/scripts/startup/function_nodes/nodes/function_output.py
@@ -1,6 +1,6 @@
 import bpy
 from .. base import BaseNode
-from .. sockets import info
+from .. sockets import type_infos
 
 class FunctionOutputNode(BaseNode, bpy.types.Node):
     bl_idname = "fn_FunctionOutputNode"
@@ -29,7 +29,7 @@ class FunctionOutputNode(BaseNode, bpy.types.Node):
             text="", icon="X", settings=(index, ))
 
     def new_socket(self, data_type):
-        info.build(data_type, self.inputs, "Output")
+        type_infos.build(data_type, self.inputs, "Output")
 
     def remove_socket(self, index):
         self.inputs.remove(self.inputs[index])
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/socket_decl.py b/release/scripts/startup/function_nodes/socket_decl.py
index 543495a738a..3a1772e1afe 100644
--- a/release/scripts/startup/function_nodes/socket_decl.py
+++ b/release/scripts/startup/function_nodes/socket_decl.py
@@ -1,6 +1,6 @@
 from bpy.props import *
 from dataclasses import dataclass
-from . sockets import info
+from . sockets import type_infos
 
 class SocketDeclBase:
     def build(self, node, node_sockets):
@@ -12,7 +12,7 @@ class FixedSocketDecl(SocketDeclBase):
         self.data_type = data_type
 
     def build(self, node, node_sockets):
-        return info.build(
+        return type_infos.build(
             self.data_type,
             node_sockets,
             self.display_name)
@@ -24,8 +24,8 @@ class ListSocketDecl(SocketDeclBase):
 
     def build(self, node, node_sockets):
         base_type = getattr(node, self.type_property)
-        list_type = info.to_list(base_type)
-        return info.build(
+        list_type = type_infos.to_list(base_type)
+        return type_infos.build(
             list_type,
             node_sockets,
             self.display_name)
@@ -41,7 +41,7 @@ class BaseSocketDecl(SocketDeclBase):
 
     def build(self, node, node_sockets):
         data_type = getattr(node, self.type_property)
-        return info.build(
+        return type_infos.build(
             data_type,
             node_sockets,
             self.display_name)
diff --git a/release/scripts/startup/function_nodes/sockets.py b/release/scripts/startup/function_nodes/sockets.py
index 3d06d57773a..825beb09dd7 100644
--- a/release/scripts/startup/function_nodes/sockets.py
+++ b/release/scripts/startup/function_nodes/sockets.py
@@ -30,7 +30,7 @@ class IntegerSocket(bpy.types.NodeSocket, DataSocket):
         layout.prop(self, "value", text=text)
 
     def draw_color(self, context, node):
-        return (0, 0.7, 0.5, 1)
+        return (0.3, 0.7, 0.5, 1)
 
 class VectorSocket(bpy.types.NodeSocket, DataSocket):
     bl_idname = "fn_VectorSocket"
@@ -132,13 +132,13 @@ class DataTypesInfo:
         return socket


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list