Commit 7025d24f authored by Jean-Paul Smets's avatar Jean-Paul Smets

Updated to support grouping even in very complex cases related to production...

Updated to support grouping even in very complex cases related to production or in universal solver cases.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@33979 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 8a10405a
......@@ -82,64 +82,94 @@ class SolverProcess(XMLObject, ActiveProcess):
"""
movement_dict = {}
types_tool = self.portal_types
message_list = []
# First create a mapping between delivery movements and solvers
# in order to know for each movements which solvers are needed
# and which parameters with
#
# movement_dict[movement] = {
# solver : [((c1, v1), (c2, v2 )),
# ((c1, v1), (c2, v2 )),
# ],
for decision in self.contentValues(portal_type="Solver Decision"):
solver = decision.getSolverValue()
# do nothing if solver is not yet set.
if solver is None:
continue
solver_type = solver.getId() # ex. Postpone Production Solver
solver_conviguration_dict = decision.getConfigurationPropertyDict()
solver_conviguration_key = tuple(solver_conviguration_dict.items())
configuration_mapping = solver_conviguration_dict.items()
configuration_mapping.sort() # Make sure the list is sorted in canonical way
configuration_mapping = tuple(configuration_mapping)
for movement in decision.getDeliveryValueList():
# Detect incompatibilities
movement_solver_dict = movement_dict.setdefault(movement.getRelativeUrl(), {})
movement_solver_configuration_list = movement_solver_dict.setdefault(solver_type, [])
if solver_conviguration_key not in movement_solver_configuration_list:
movement_solver_configuration_list.append(solver_conviguration_key)
movement_solver_dict = movement_dict.setdefault(movement, {})
movement_solver_configuration_list = movement_solver_dict.setdefault(solver, [])
if configuration_mapping not in movement_solver_configuration_list:
movement_solver_configuration_list.append(configuration_mapping)
# Second, make sure solvers do not conflict and configuration is valid
# Build a movement and configuration structure per solver type
# Second, create a mapping between solvers and movements
# and their configuration
#
# solver_dict[solver] = {
# movement : [((c1, v1), (c2, v2 )),
# ((c1, v1), (c2, v2 )),
# ],
# }
#
solver_dict = {}
for movement_url, movement_solver_dict in movement_dict.items():
for solver_type, movement_solver_configuration_list in movement_solver_dict.items():
solver_movement_dict = solver_dict.setdefault(solver_type, {})
configuration_list = solver_movement_dict.setdefault(movement_url, [])
configuration_list.extend(movement_solver_configuration_list) # XXX-JPS WRONG
# Then start the grouping procedure
solver_dict = {}
for movement_url, movement_solver_dict in movement_dict.items():
for solver_type, movement_solver_configuration_list in movement_solver_dict.items():
solver = types_tool[solver_type]
for other_solver_type in movement_solver_dict.keys():
if other_solver_type == solver_type:
continue
if solver.conflictsWithSolver(types_tool[other_solver_type]):
# XXX6PJS REDO HERE
raise ValueError, "Solver %s conflicts with solver %s on movement %s" % (solver_type, other_solver_type, movement_url)
# Make sure multiple configuration are possible
try:
# Solver key contains only those properties which differentiate
# solvers (ex. there should be only Production Reduction Solver)
solver_key = solver.getSolverProcessGroupingKey(movement_url, movement_solver_configuration_list, movement_solver_dict)
except: # Raise the exception generated by the solver in case of failure of grouping
raise
solver_key_dict = solver_dict.setdefault(solver_type, {})
solver_movement_dict = solver_key_dict.setdefault(solver_key, {})
solver_movement_dict[movement_url] = movement_solver_configuration_list
# Third, build target solvers
for solver_type, solver_key_dict in solver_dict.items():
for movement, movement_solver_dict in movement_dict.items():
for solver, movement_solver_configuration_list in movement_solver_dict.items():
solver_movement_dict = solver_dict.setdefault(solver, {})
solver_movement_dict[movement] = movement_solver_configuration_list
# Third, group solver configurations and make sure solvers do not conflict
# by creating a mapping between solvers and movement configuration grouped
# by a key which is used to aggregate multiple configurations
#
# grouped_solver_dict[solver] = {
# solver_key: {
# movement : [((c1, v1), (c2, v2 )),
# ((c1, v1), (c2, v2 )),
# ],
# }
# }
grouped_solver_dict = {}
for movement, movement_solver_dict in movement_dict.items():
for solver, movement_solver_configuration_list in movement_solver_dict.items():
for configuration_mapping in movement_solver_configuration_list:
solver_message_list = solver.getSolverConflictMessageList(movement, configuration_mapping, solver_dict)
if solver_message_list:
message_list.extend(solver_message_list)
continue # No need to keep on
# Make sure multiple configuration are possible
try:
# Solver key contains only those properties which differentiate
# solvers (ex. there should be only Production Reduction Solver)
solver_key = solver.getSolverProcessGroupingKey(movement, configuration_mapping, solver_dict)
except: # Raise the exception generated by the solver in case of failure of grouping
raise
solver_key_dict = grouped_solver_dict.setdefault(solver, {})
solver_movement_dict = solver_key_dict.setdefault(solver_key, {})
movement_solver_configuration_list = movement_solver_dict.setdefault(solver, [])
if configuration_mapping not in movement_solver_configuration_list:
movement_solver_configuration_list.append(configuration_mapping)
# Return empty list of conflicts
if message_list: return message_list
# Fourth, build target solvers
for solver, solver_key_dict in grouped_solver_dict.items():
for solver_key, solver_movement_dict in solver_key_dict.items():
solver_instance = self.newContent(portal_type=solver_type)
solver_instance._setDeliveryList(solver_movement_dict.keys())
for movement_url, configuration_list in solver_movement_dict.iteritems():
for configuration_kw in configuration_list:
if len(configuration_kw):
solver_instance.updateConfiguration(**dict(configuration_kw))
solver_instance = self.newContent(portal_type=solver.getId())
solver_instance._setDeliveryValueList(solver_movement_dict.keys())
for movement, configuration_list in solver_movement_dict.iteritems():
for configuration_mapping in configuration_list:
if len(configuration_mapping):
solver_instance.updateConfiguration(**dict(configuration_mapping))
# Return empty list of conflicts
return []
# ISolver implementation
# Solver Process Workflow Interface
......
......@@ -52,31 +52,45 @@ class SolverTypeInformation(ERP5TypeInformation):
, PropertySheet.Configurable
)
def conflictsWithSolver(self, movement, configuration_dict, other_configuration_list):
def getSolverConflictMessageList(self, movement, configuration_mapping, solver_dict, movement_dict):
"""
Returns True if the solver conflicts with other_solver. False else.
Returns the list of conflictings messgaes if the solver and configuration_mapping
conflicts with another solver
movement -- a movement or a movement relative url
movement -- a movement
configuration_mapping -- a mapping of configuration parameters sorted in
canonical way. ((c1, v1), (c2, v2 ))
configuration_dict -- a dictionary of configuration parameters to
solve the current movement with self
other_configuration_list -- a list of solvers and their configuration
for the same movement
solver_dict -- a dictionary of configuration parameters for
each solver
solver_dict[solver] = {
movement : [((c1, v1), (c2, v2 )),
((c1, v1), (c2, v2 )),
],}
movement_dict -- a dictionary of solver and configuration parameters for
each movement
movement_dict[movement] = {
solver : [((c1, v1), (c2, v2 )),
((c1, v1), (c2, v2 )),
],}
"""
method = self._getTypeBasedMethod('conflictsWithSolver')
method = self._getTypeBasedMethod('getSolverConflictMessageList')
if method is not None:
return method(movement, configuration_dict, other_configuration_list)
return method(movement, configuration_mapping, solver_dict, movement_dict)
# Default Implementation (use categories and trivial case)
for solver_type, configuration_dict in other_configuration_list:
if solver.getTestedProperty() == self.getTestedProperty():
return True
# this default implementation should be applicable to most
# solvers so that use of Type Based methods is very rare
for solver, configuration_list in movement_dict[movement].items():
if solver is not self and solver.getTestedProperty() == self.getTestedProperty():
return AppropriateUIMessage(whatever) # XXX-TODO
# Return False by Default
return False
# Return emtpty message list
return ()
def getSolverProcessGroupingKey(self, movement, configuration_dict, other_configuration_list):
def getSolverProcessGroupingKey(self, movement, configuration_mapping, solver_dict, movement_dict):
"""
Returns a key which can be used to group solvers during the
process to build Targer Solver instances from Solver Decisions.
......@@ -98,26 +112,34 @@ class SolverTypeInformation(ERP5TypeInformation):
Adopt, Accept) which tested property is configurable, is the
tested property itself.
movement -- a movement or a movement relative url
configuration_dict -- a dictionary of configuration parameters
movement -- a movement
other_configuration_list -- a list of movements and their configuration
which are solved by the same solve type.
[(m1, c1), (m2, c2), ...]
configuration_mapping -- a mapping of configuration parameters sorted in
canonical way. ((c1, v1), (c2, v2 ))
solver_dict -- a dictionary of configuration parameters for
each solver
solver_dict[solver] = {
movement : [((c1, v1), (c2, v2 )),
((c1, v1), (c2, v2 )),
],}
movement_dict -- a dictionary of solver and configuration parameters for
each movement
movement_dict[movement] = {
solver : [((c1, v1), (c2, v2 )),
((c1, v1), (c2, v2 )),
],}
"""
method = self._getTypeBasedMethod('getSolverProcessGroupingKey')
if method is not None:
return method(movement, configuration_dict, other_configuration_list)
return method(movement, configuration_mapping, solver_dict, movement_dict)
# Default Implementation (read properties and implement XXX)
# Default Implementation (read solver type properties and implement XXX-TODO)
if self.isLineGroupable():
return ()
if isinstance(movement, str):
return movement
else:
return movement.getRelativeUrl()
return movement.getRelativeUrl()
def getDefaultConfigurationPropertyDict(self, configurable):
"""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment