/// <inheritdoc/> public override IFact CalculateFact <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) { var fact = base.CalculateFact(node, context); WriteLog(() => $"FactFactory | FactRule\n{node.Info.Rule}\nInput facts: {string.Join(", ", GetRequireFacts(node.Info.Rule, context))}\nResult: {fact}"); return(fact); }
/// <summary> /// Delete current node. /// </summary> /// <typeparam name="TFactRule">FatcRule type.</typeparam> /// <typeparam name="TWantAction">WantAction type.</typeparam> /// <typeparam name="TFactContainer">FactContainer type.</typeparam> /// <param name="node">Node to be removed.</param> /// <param name="treeByFactRule">Rule tree.</param> /// <param name="level">Level in tree.</param> /// <returns>True - remove root node.</returns> /// <remarks> /// Recursively delete parent nodes /// if they do not have other nodes calculating the fact from the child node. /// </remarks> private bool TryRemoveRootNode <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, TreeByFactRule <TFactRule, TWantAction, TFactContainer> treeByFactRule, int level) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { treeByFactRule.Levels[level].Remove(node); if (level == 0) { return(true); } NodeByFactRule <TFactRule> parent = node.Parent; parent.Childs.Remove(node); // If the node has a child node that can calculate this fact if (parent.Childs.Any(n => n.Info.Rule.OutputFactType.EqualsFactType(node.Info.Rule.OutputFactType))) { return(false); } else { return(TryRemoveRootNode(parent, treeByFactRule, level - 1)); } }
/// <summary> /// Calculates the fact and adds the priority fact to the parameters. /// </summary> /// <typeparam name="TFactRule">Type rule.</typeparam> /// <typeparam name="TWantAction">Type wantAction.</typeparam> /// <typeparam name="TFactContainer">Type fact container.</typeparam> /// <param name="node">Node containing information about the calculation rule.</param> /// <param name="context">Context</param> /// <returns>Fact.</returns> public override IFact CalculateFact <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) { IPriorityFact priority = node.Info.Rule.GetPriorityFact(context); return(base .CalculateFact(node, context) .AddPriorityParameter(priority)); }
internal static NodeByFactRule <TFactRule> Copy <TFactRule>(this NodeByFactRule <TFactRule> node, NodeByFactRule <TFactRule> newParent) where TFactRule : IFactRule { return(new NodeByFactRule <TFactRule> { Childs = node.Childs, Info = node.Info, Parent = newParent, }); }
private static void FillUniqueRulesFromTree <TFactRule>(NodeByFactRule <TFactRule> node, HashSet <TFactRule> eniqueRules) where TFactRule : IFactRule { foreach (var child in node.Childs) { FillUniqueRulesFromTree(child, eniqueRules); } if (!eniqueRules.Contains(node.Info.Rule)) { eniqueRules.Add(node.Info.Rule); } }
/// <summary> /// Synchronize the tree level with years ready for calculation. /// </summary> /// <typeparam name="TFactRule"></typeparam> /// <typeparam name="TWantAction"></typeparam> /// <typeparam name="TFactContainer"></typeparam> /// <param name="treeLevel">Tree level.</param> /// <param name="finishedNodes">Nodes by which the rule can already be calculated. Key - node info, value - node</param> /// <param name="context">Context.</param> private void SyncTreeLevelAndFinishedNodes <TFactRule, TWantAction, TFactContainer>(List <NodeByFactRule <TFactRule> > treeLevel, Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> > finishedNodes, IWantActionContext <TWantAction, TFactContainer> context) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { foreach (var finishedNode in finishedNodes) { List <NodeByFactRule <TFactRule> > parentNodes = treeLevel .Where(node => node.Info.Rule.EqualsWork(finishedNode.Key.Rule, context.WantAction, context.Container)) .Select(node => node.Parent) .Distinct() .ToList(); foreach (NodeByFactRule <TFactRule> parentNode in parentNodes) { if (parentNode == null) { continue; } for (int i = parentNode.Childs.Count - 1; i >= 0; i--) { NodeByFactRule <TFactRule> childNode = parentNode.Childs[i]; if (!childNode.Info.Rule.OutputFactType.EqualsFactType(finishedNode.Key.Rule.OutputFactType)) { continue; } parentNode.Childs.Remove(childNode); int indexNodeInTreeLevel = treeLevel.IndexOf(childNode); if (indexNodeInTreeLevel != -1) { treeLevel.RemoveAt(indexNodeInTreeLevel); } } if (parentNode == finishedNode.Value.Parent) { parentNode.Childs.Add(finishedNode.Value); } else { parentNode.Childs.Add(finishedNode.Value.Copy(parentNode)); } } } }
/// <inheritdoc/> public virtual IFact CalculateFact <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { (var rule, var buildSuccessConditions, var runtimeConditions) = (node.Info.Rule, node.Info.BuildSuccessConditions, node.Info.RuntimeConditions); foreach (IRuntimeConditionFact condition in runtimeConditions) { (bool calculated, IFact result) = TryCalculateFactByRuntimeCondition(rule, condition, context); if (calculated) { return(result); } } using (var writer = context.Container.GetWriter()) { buildSuccessConditions.ForEach(writer.Add); runtimeConditions.ForEach(writer.Add); } var requiredFacts = GetRequireFacts(rule, context); if (!CanInvokeWork(requiredFacts, rule, context.Cache)) { throw CommonHelper.CreateDeriveException(ErrorCode.InvalidOperation, $"Can't calculate the '{rule}' rule.", context.WantAction, context.Container); } var fact = Factory.CreateObject( facts => rule.Calculate(facts), requiredFacts); fact.SetCalculateByRule(); context.WantAction.AddUsedRule(rule); using (var writer = context.Container.GetWriter()) { buildSuccessConditions.ForEach(writer.Remove); runtimeConditions.ForEach(writer.Remove); } return(fact); }
/// <summary> /// Whether the <paramref name="rule"/> is contained in a branch with <paramref name="nodeFromBranch"/>. /// </summary> /// <typeparam name="TFactRule"></typeparam> /// <param name="rule"></param> /// <param name="nodeFromBranch"></param> /// <returns></returns> internal static bool RuleContainBranch <TFactRule>(this TFactRule rule, NodeByFactRule <TFactRule> nodeFromBranch) where TFactRule : IFactRule { if (rule == null && nodeFromBranch.Info.Rule == null) { return(true); } else if (rule == null || nodeFromBranch.Info.Rule == null) { return(false); } else if (rule.Equals(nodeFromBranch.Info.Rule)) { return(true); } else if (nodeFromBranch.Parent != null) { return(rule.RuleContainBranch(nodeFromBranch.Parent)); } return(false); }
public void Initialize() { Rule = GetFactRule((Priority1 p, Fact1 f) => new FactResult(f.Value + p)); NodeInfo = new NodeByFactRuleInfo <FactRule> { BuildFailedConditions = new List <IBuildConditionFact>(), Rule = Rule, BuildSuccessConditions = new List <IBuildConditionFact>(), RuntimeConditions = new List <IRuntimeConditionFact>(), }; Node = new NodeByFactRule <FactRule> { Childs = new List <NodeByFactRule <FactRule> >(), Info = NodeInfo, Parent = null, }; Context = GetWantActionContext( GetWantAction((FactResult result) => { }), new FactContainer { new Priority1(), new Priority2(), }); }
/// <inheritdoc/> public virtual bool NeedCalculateFact <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { return(node.Parent != null ? !CanExtractFact(node.Info.Rule.OutputFactType, node.Parent.Info.Rule, context) : !CanExtractFact(node.Info.Rule.OutputFactType, context.WantAction, context)); }
/// <summary> /// Determines you can no longer consider the <paramref name="factType"/> necessary. /// </summary> /// <typeparam name="TFactRule">FactRole type.</typeparam> /// <typeparam name="TWantAction">WantAction type.</typeparam> /// <typeparam name="TFactContainer">FactContainer type.</typeparam> /// <param name="factType">Fact type info.</param> /// <param name="node"></param> /// <param name="context"></param> /// <param name="copatibleAllFinishedNodes"></param> /// <returns>True - may not be considered necessary</returns> private bool CanRemoveFromNeedFactTypes <TFactRule, TWantAction, TFactContainer>(IFactType factType, NodeByFactRule <TFactRule> node, IFactRulesContext <TFactRule, TWantAction, TFactContainer> context, Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> > copatibleAllFinishedNodes) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { // Exclude condition special facts if (factType.IsFactType <IBuildConditionFact>()) { var nodeInfo = node.Info; if (nodeInfo.BuildSuccessConditions.Exists(fact => context.Cache.GetFactType(fact).EqualsFactType(factType))) { return(true); } else if (nodeInfo.BuildFailedConditions.Exists(fact => context.Cache.GetFactType(fact).EqualsFactType(factType))) { return(false); } var condition = Factory.CreateObject( type => type.CreateBuildConditionFact <IBuildConditionFact>(), factType ); if (condition.Condition(nodeInfo.Rule, context, _ => nodeInfo.CompatibleRules)) { nodeInfo.BuildSuccessConditions.Add(condition); return(true); } else { nodeInfo.BuildFailedConditions.Add(condition); return(false); } } else if (factType.IsFactType <IRuntimeConditionFact>()) { var nodeInfo = node.Info; if (nodeInfo.RuntimeConditions.Exists(fact => context.Cache.GetFactType(fact).EqualsFactType(factType))) { return(true); } var condition = Factory.CreateObject( type => type.CreateRuntimeConditionFact <IRuntimeConditionFact>(), factType ); condition.SetGetRelatedRulesFunc <TFactRule, TWantAction, TFactContainer>(GetRelatedRules, node.Info.Rule, context.FactRules); nodeInfo.RuntimeConditions.Add(condition); return(true); } else { // Exclude facts for which a solution has already been found. List <KeyValuePair <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> > > finishedNodesForCurrentFact = copatibleAllFinishedNodes .Where(finishedNode => finishedNode.Key.Rule.OutputFactType.EqualsFactType(factType)) .ToList(); if (finishedNodesForCurrentFact.Count != 0) { node.Childs.Insert(0, finishedNodesForCurrentFact[0].Value); return(true); } } return(false); }
/// <inheritdoc/> public virtual bool TryBuildTreeForFactInfo <TFactRule, TWantAction, TFactContainer>(BuildTreeForFactInfoRequest <TFactRule, TWantAction, TFactContainer> request, out TreeByFactRule <TFactRule, TWantAction, TFactContainer> treeResult, out List <DeriveFactErrorDetail> deriveFactErrorDetails) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { var context = request.Context; treeResult = null; deriveFactErrorDetails = null; // find the rules that can calculate the fact List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > treesByWantFactType = request.GetTreesByRequest(); var treeReady = treesByWantFactType.FirstOrDefault(tree => tree.Status == TreeStatus.Built); if (treeReady != null) { treeResult = treeReady; return(true); } List <List <IFactType> > notFoundFactSet = treesByWantFactType.ConvertAll(item => new List <IFactType>()); var allFinichedNodes = new Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> >(); while (true) { for (int i = treesByWantFactType.Count - 1; i >= 0; i--) { var treeByWantFactType = treesByWantFactType[i]; if (treeByWantFactType.Status != TreeStatus.BeingBuilt) { continue; } int lastlevelNumber = treeByWantFactType.Levels.Count - 1; // If after synchronization we can calculate the tree. if (TrySyncTreeLevelsAndFinishedNodes(treeByWantFactType, lastlevelNumber, allFinichedNodes)) { treeByWantFactType.Built(); continue; } List <NodeByFactRule <TFactRule> > lastTreeLevel = treeByWantFactType.Levels[lastlevelNumber]; // If in the last level there are no nodes for calculation, then the tree can be calculated. if (lastTreeLevel.Count == 0) { treeByWantFactType.Built(); continue; } // Next level nodes. var nextTreeLevel = new List <NodeByFactRule <TFactRule> >(); var currentLevelFinishedNodes = new Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> >(); bool cannotDerived = false; for (int j = 0; j < lastTreeLevel.Count; j++) { NodeByFactRule <TFactRule> node = lastTreeLevel[j]; NodeByFactRuleInfo <TFactRule> nodeInfo = node.Info; Dictionary <NodeByFactRuleInfo <TFactRule>, NodeByFactRule <TFactRule> > copatibleAllFinishedNodes = nodeInfo.GetCompatibleFinishedNodes(allFinichedNodes, context); List <IFactType> needFacts = nodeInfo .RequiredFactTypes .FindAll(needFactType => !CanRemoveFromNeedFactTypes(needFactType, node, context, copatibleAllFinishedNodes)); // If the rule can be calculated from the parameters in the container, then add the node to the list of complete. if (needFacts.IsNullOrEmpty()) { allFinichedNodes.Add(node.Info, node); currentLevelFinishedNodes.Add(node.Info, node); continue; } bool canTryRemoveNode = false; foreach (var needFact in needFacts) { if (needFact.IsFactType <ISpecialFact>()) { if (!canTryRemoveNode) { canTryRemoveNode = true; } notFoundFactSet[i].Add(needFact); continue; } var needRules = nodeInfo .CompatibleRules .FindAll(rule => rule.OutputFactType.EqualsFactType(needFact) && !rule.RuleContainBranch(node)); if (needRules.Count > 0) { List <NodeByFactRule <TFactRule> > nodes = needRules.GetNodesByRules(node, treeByWantFactType); nextTreeLevel.AddRange(nodes); node.Childs.AddRange(nodes); } else { if (!canTryRemoveNode) { canTryRemoveNode = true; } notFoundFactSet[i].Add(needFact); } } if (canTryRemoveNode) { // Is there a neighboring node capable of deriving this fact. cannotDerived = TryRemoveRootNode(node, treeByWantFactType, lastlevelNumber); j--; } } if (cannotDerived) { treeByWantFactType.Cencel(); } else if (currentLevelFinishedNodes.Count > 0) { if (TrySyncTreeLevelsAndFinishedNodes(treeByWantFactType, lastlevelNumber, currentLevelFinishedNodes)) { treeByWantFactType.Built(); } else if (nextTreeLevel.Count > 0) { SyncTreeLevelAndFinishedNodes(nextTreeLevel, currentLevelFinishedNodes, context); treeByWantFactType.Levels.Add(nextTreeLevel); } } else if (nextTreeLevel.Count > 0) { treeByWantFactType.Levels.Add(nextTreeLevel); } else { treeByWantFactType.Built(); } } List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > builtTrees = treesByWantFactType .FindAll(tree => tree.Status == TreeStatus.Built); if (builtTrees.Count != 0) { var countRuleByBuiltTrees = builtTrees.ToDictionary(tree => tree, tree => tree.GetUniqueRulesFromTree().Count); int minRuleCount = countRuleByBuiltTrees.Min(item => item.Value); var suitableTree = countRuleByBuiltTrees.First(item => item.Value == minRuleCount).Key; foreach (var tree in treesByWantFactType) { if (tree != suitableTree && tree.Status != TreeStatus.Cencel && tree.GetUniqueRulesFromTree().Count >= minRuleCount) { tree.Cencel(); } } if (treesByWantFactType.All(tree => tree.Status != TreeStatus.BeingBuilt)) { treeResult = suitableTree; return(true); } } if (treesByWantFactType.All(tree => tree.Status == TreeStatus.Cencel)) { break; } } deriveFactErrorDetails = new List <DeriveFactErrorDetail>(); foreach (var factSet in notFoundFactSet) { if (factSet.Count != 0) { deriveFactErrorDetails.Add(new DeriveFactErrorDetail(request.WantFactType, factSet.AsReadOnly())); } } return(false); }
/// <summary> /// Calculates the fact asynchronously and adds the priority fact to the parameters. /// </summary> /// <typeparam name="TFactRule">Type rule.</typeparam> /// <typeparam name="TWantAction">Type wantAction.</typeparam> /// <typeparam name="TFactContainer">Type fact container.</typeparam> /// <param name="node">Node containing information about the calculation rule.</param> /// <param name="context">Context</param> /// <returns>Fact.</returns> public override async ValueTask <IFact> CalculateFactAsync <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) { IPriorityFact priority = node.Info.Rule.GetPriorityFact(context); return((await base.CalculateFactAsync(node, context).ConfigureAwait(false)).AddPriorityParameter(priority)); }
/// <inheritdoc/> /// <remarks>Adds a versioned fact to the parameters of the calculated fact.</remarks> public override IFact CalculateFact <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) { var version = node.Info.Rule.InputFactTypes.GetVersionFact(context); return(base.CalculateFact(node, context).AddVerionParameter(version)); }
/// <summary> /// Get <see cref="TreeByFactRule{TFactRule, TWantAction, TFactContainer}"/> by <paramref name="request"/>. /// </summary> /// <typeparam name="TFactRule"></typeparam> /// <typeparam name="TWantAction"></typeparam> /// <typeparam name="TFactContainer"></typeparam> /// <param name="request"></param> /// <returns></returns> internal static List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > GetTreesByRequest <TFactRule, TWantAction, TFactContainer>(this BuildTreeForFactInfoRequest <TFactRule, TWantAction, TFactContainer> request) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { var context = request.Context; var factRules = request.Context.FactRules; if (factRules.IsNullOrEmpty()) { throw CommonHelper.CreateDeriveException(ErrorCode.EmptyRuleCollection, "Rules cannot be null."); } var needRules = factRules .Where(rule => rule.OutputFactType.EqualsFactType(request.WantFactType)) .ToList(); if (needRules.IsNullOrEmpty()) { throw CommonHelper.CreateDeriveException(ErrorCode.RuleNotFound, $"No rules found able to calculate fact {request.WantFactType.FactName}."); } var nodeInfos = needRules.ConvertAll(rule => new NodeByFactRuleInfo <TFactRule> { BuildSuccessConditions = new List <IBuildConditionFact>(rule.InputFactTypes.Count(type => type.IsFactType <IBuildConditionFact>())), BuildFailedConditions = new List <IBuildConditionFact>(), RuntimeConditions = new List <IRuntimeConditionFact>(rule.InputFactTypes.Count(type => type.IsFactType <IRuntimeConditionFact>())), Rule = rule, RequiredFactTypes = context.SingleEntity.GetRequiredTypesOfFacts(rule, context).ToList(), CompatibleRules = rule.GetCompatibleRulesEx(context.FactRules, context), }); return(nodeInfos.ConvertAll(info => { var node = new NodeByFactRule <TFactRule> { Childs = new List <NodeByFactRule <TFactRule> >(), Info = info, }; var tree = new TreeByFactRule <TFactRule, TWantAction, TFactContainer> { Levels = new List <List <NodeByFactRule <TFactRule> > > { new List <NodeByFactRule <TFactRule> > { node }, }, NodeInfos = nodeInfos, Root = node, Context = context, }; if (info.RequiredFactTypes.Count == 0) { tree.Built(); } return tree; })); }
/// <inheritdoc/> /// <remarks>Adds a <see cref="Interfaces.IVersionFact"/> to the parameters of the calculated fact.</remarks> public override async ValueTask <IFact> CalculateFactAsync <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) { var version = node.Info.Rule.InputFactTypes.GetVersionFact(context); return((await base.CalculateFactAsync(node, context).ConfigureAwait(false)).AddVerionParameter(version)); }
/// <summary> /// Returns nodes by rules. /// </summary> /// <typeparam name="TFactRule">FatcRule type.</typeparam> /// <typeparam name="TWantAction">WantAction type.</typeparam> /// <typeparam name="TFactContainer">FactContainer type.</typeparam> /// <param name="rules">List of rule.</param> /// <param name="treeByFactRule">Rule tree.</param> /// <param name="parentNode">Parent node.</param> /// <returns>Node list.</returns> public static List <NodeByFactRule <TFactRule> > GetNodesByRules <TFactRule, TWantAction, TFactContainer>(this IEnumerable <TFactRule> rules, NodeByFactRule <TFactRule> parentNode, TreeByFactRule <TFactRule, TWantAction, TFactContainer> treeByFactRule) where TFactRule : IFactRule where TWantAction : IWantAction where TFactContainer : IFactContainer { var context = treeByFactRule.Context; var result = new List <NodeByFactRule <TFactRule> >(); foreach (var rule in rules) { NodeByFactRuleInfo <TFactRule> nodeInfo = treeByFactRule.NodeInfos.FirstOrDefault(nInfo => nInfo.Rule.EqualsWork(rule, context.WantAction, context.Container)); if (nodeInfo == null) { nodeInfo = new NodeByFactRuleInfo <TFactRule> { Rule = rule, BuildSuccessConditions = new List <IBuildConditionFact>(rule.InputFactTypes.Count(type => type.IsFactType <IBuildConditionFact>())), BuildFailedConditions = new List <IBuildConditionFact>(), RuntimeConditions = new List <IRuntimeConditionFact>(rule.InputFactTypes.Count(type => type.IsFactType <IRuntimeConditionFact>())), RequiredFactTypes = context.SingleEntity.GetRequiredTypesOfFacts(rule, context).ToList(), CompatibleRules = rule.GetCompatibleRulesEx(context.FactRules, context), } } ; result.Add(new NodeByFactRule <TFactRule> { Childs = new List <NodeByFactRule <TFactRule> >(), Info = nodeInfo, Parent = parentNode, }); } return(result); }
/// <inheritdoc/> public override async ValueTask <IFact> CalculateFactAsync <TFactRule, TWantAction, TFactContainer>(NodeByFactRule <TFactRule> node, IWantActionContext <TWantAction, TFactContainer> context) { var fact = await base.CalculateFactAsync(node, context).ConfigureAwait(false); WriteLog(() => $"FactFactory | FactRule\n{node.Info.Rule}\nInput facts: {string.Join(", ", GetRequireFacts(node.Info.Rule, context))}\nResult: {fact}"); return(fact); }