[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