public void SetChild(TreeBranch branch) { if (branches.Contains(branch)) { if (childBranch1 != branch && childBranch2 != branch) // If the branch isn't already a child { if (childBranch1 == null) { childBranch1 = branch; } else if (childBranch2 == null) { childBranch2 = branch; } else { throw new OverflowException("This node already has two children."); } } } else { throw new ArgumentException("Cannot set a branch as a child of this node if it isn't connected to this node."); } }
public void AddBranch(TreeBranch branch) { // A node can only support three connections if (branches.Count == 3) { throw new OverflowException("This node already has 3 connections."); } else { // If the branch being added connects this node to a leaf, and one of the other branches also // connects to a leaf, this is a terminal node. Add this node to the list of terminal nodes. if (branch.Follow(this).GetType() == typeof(TreeLeaf)) { foreach (TreeBranch otherBranch in branches) { if (otherBranch.Follow(this).GetType() == typeof(TreeLeaf)) { tree.terminalNodesList.Add(this); } } } branches.Add(branch); } }
private static void EvaluateDescriptionPosition(TreeBranch branch, string description, double x1, double y1, double x2, double y2, Graphics g, Font font, out double dx, out double dy) { double angle = Funcs.Atan(x1, y1, x2, y2); if (branch is ExpressionBranch) { ExpressionBranch e = branch as ExpressionBranch; double xt = x2 + e.DescriptionX * Math.Cos(angle + Math.PI); double yt = y2 - e.DescriptionX * Math.Sin(angle + Math.PI); double d = (branch as ExpressionBranch).DescriptionY; dx = xt + d * Math.Cos(angle + Math.PI / 2) + (branch as ExpressionBranch).DescriptionOffsetX; dy = yt - d * Math.Sin(angle + Math.PI / 2) + (branch as ExpressionBranch).DescriptionOffsetY; } else { dy = y1 - g.MeasureString(description, font).Height / 2; if (x2 < x1) { dx = x1 + 5; } else { dx = x1 - g.MeasureString(description, font).Width - 5; } } }
public void OnClickReset() { ResetOutput(); TreeNode.ResetNodes(); TreeBranch.ResetBranches(); OnResetClicked(); }
public void RemoveBranch(TreeBranch branch) { // List's Remove method handles low-count and not-in-list conditions, // so I won't handle them here. // bool removeFlag = branches.Remove(branch); Not sure why I need the return code. branches.Remove(branch); if (childBranch1 == branch) { childBranch1 = null; } else if (childBranch2 == branch) { childBranch2 = null; } //if (!removeFlag) //{ // return false; //} if (parentBranch == branch) { RemoveParent(); } // If the branch removal results in no connections, the node can be removed from the tree. if (branches.Count == 0) { tree.nodesList.Remove(this); } else if (true) { // If the branch was a terminal node and the branch being removed was connected to a leaf, // if only one other branch is connected to a leaf, this is no longer a terminal node. // Remove this node from the list of terminal nodes. if (branch.Follow(this).GetType() == typeof(TreeLeaf)) { int leafCount = 0; foreach (TreeBranch otherBranch in branches) { if (otherBranch.Follow(this).GetType() == typeof(TreeLeaf)) { leafCount += 1; } } if (leafCount <= 1) { tree.terminalNodesList.Remove(this); } } } //return true; }
void AssertPaternity() // For each branch out from the given root which is not a parent branch, assign that branch // as the child's parent branch. // As this could be deeply recursive and could result in a stack overflow, this must be coded as a loop. { Stack <Tuple <TreeMember, TreeBranch> > arguments = new Stack <Tuple <TreeMember, TreeBranch> >(); TreeBranch prevBranch = new TreeBranch(); bool stepBack = false; foreach (TreeBranch rootBranch in root.Branches) { arguments.Push(Tuple.Create(rootBranch.Follow(root), rootBranch)); while (arguments.Count > 0) { Tuple <TreeMember, TreeBranch> nextArgument = arguments.Peek(); TreeMember member = nextArgument.Item1; TreeBranch parentBranch = nextArgument.Item2; stepBack = false; member.parentBranch = parentBranch; ((TreeNode)parentBranch.Follow(member)).SetChild(parentBranch); if (member.GetType() == typeof(TreeNode)) { TreeNode node = (TreeNode)member; if (node.Branches.Contains(prevBranch)) // If the previously-used branch is a member of this node's branches, that means we've already used the // branches of this node, and can discard it. { stepBack = true; } else { foreach (TreeBranch branch in node.Branches) { if (branch != parentBranch) { arguments.Push(Tuple.Create(branch.Follow(node), branch)); } } } } else { stepBack = true; } if (stepBack) { prevBranch = parentBranch; arguments.Pop(); } } } }
private bool TryDamageBranch(INetObject damager, float amount, InteractionContext context) { int branchID = context.Parameters["branch"]; TreeBranch branch = this.branches[branchID]; if (context.Parameters.ContainsKey("leaf")) { int leafID = context.Parameters["leaf"]; // damage leaf LeafBunch leaf = branch.Leaves[leafID]; if (leaf.Health > 0) { List <IAtomicAction> actions = new List <IAtomicAction>(); if (damager is Player) { var action = PlayerActions.HarvestLeaves.CreateAtomicAction(((Player)damager).User, this); actions.Add(action); if (!PlayerActions.HarvestLeaves.CreateAtomicAction(((Player)damager).User, this).CanApply().Notify((Player)damager)) { // We only want to dispose the action if it is invalid. Othewise we want to keep it around to possibly apply later. action.Dispose(); return(false); } } leaf.Health = Mathf.Max(0, leaf.Health - amount); if (leaf.Health <= 0) { if (!new MultiAtomicAction(actions).TryApply().Success) { throw new Exception("Removing this stump was verified to be legal a moment ago, but is not anymore."); } leaf.Health = 0; this.RPC("DestroyLeaves", branchID, leafID); } else { new MultiAtomicAction(actions).Dispose(); } } this.Save(); return(true); } else { return(this.TryDamageBranch(branch, branchID, amount)); } }
static double GetAverageBranchLength(TreeMember member, TreeBranch baseBranch, bool includeBranch, out int numLeaves) // From the given tree member, this will calculate the average branch length of the branches extending // from it. The switch "includeBranch" indicates whether the branch should be included in the numbers // (used for distance to the other end of the branch). If the TreeMember is a leaf, this function returns 0. { double averageBranchLength = 0; double sumBranchLength = GetSumBranchLength(member, baseBranch, includeBranch, out numLeaves); averageBranchLength = sumBranchLength / numLeaves; return(averageBranchLength); }
void DestroyLeaf(int branchID, int leafID) { TreeBranch branch = this.branches[branchID]; LeafBunch leaf = branch.Leaves[leafID]; if (leaf.Health > 0) { // replicate to all clients leaf.Health = 0; this.RPC("DestroyLeaves", branchID, leafID); } }
/// <summary> /// We override the create world object function for a tree. This is done as we need to load in multiple /// parts of the tree /// </summary> /// <param name="transform"></param> /// <returns></returns> public override WorldObject CreateWorldObject(Transform transform = null) { //Create random with seed unique to tree position - this ensures tree should be same every time. GenerationRandom genRan = new GenerationRandom(WorldPosition.x * World.WorldSize * World.ChunkSize + WorldPosition.z); int canopy = genRan.RandomInt(3, 7); float angleOffset = genRan.Random(0, Mathf.PI); float range = Mathf.Sqrt(canopy * 0.5f) * 0.8f; WorldObject treeBase = WorldObject.CreateWorldObject(this, transform); Vec2i zero = new Vec2i(0, 0); Vector3[] canopyPositions = new Vector3[canopy]; for (int i = 0; i < canopy; i++) { //Define the positions of each canopy as roughly circular about the middle of the tree. float angle = (Mathf.PI * 2 / (canopy)) * i + angleOffset; Vector2 delta = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * range + genRan.RandomVector2(-0.1f, 0.1f); float height = 1.8f + genRan.Random(0, 1f); //Store the total position for use later, then generate the canopy itself. canopyPositions[i] = new Vector3(delta.x, height, delta.y); TreeCanopy tr = new TreeCanopy(zero, canopyPositions[i]); tr.SetRandom(genRan); tr.CreateWorldObject(treeBase.transform); } //Generate the trunk float trunkHeight = 1.2f; float trunkScale = 1.2f; TreeBranch trunk = new TreeBranch(zero); trunk.SetCharacteristic(Vector3.zero, new Vector3(0, 0, 0), new Vector3(1, trunkScale, 1)); WorldObject trunkObj = trunk.CreateWorldObject(treeBase.transform); //MeshCollider mc =trunkObj.gameObject.AddComponent<MeshCollider>(); //mc.sharedMesh = trunkObj.gameObject.GetComponent<MeshFilter>().mesh; Vector3 trunkTop = Vector3.up * trunkHeight * trunkScale; //Scale to correct height foreach (Vector3 v in canopyPositions) { TreeBranch canopyBranch = new TreeBranch(zero); //Calculate the Euler angles from the branch base to the canopy Vector3 delta_pos = v - trunkTop; Quaternion.FromToRotation(Vector3.up, delta_pos); //Vector3 rot = Quaternion.FromToRotation(trunkTop, v*5f).eulerAngles; Vector3 rot = Quaternion.FromToRotation(Vector3.up, delta_pos).eulerAngles; float scale = Vector3.Distance(v, trunkTop) / trunkHeight; canopyBranch.SetCharacteristic(trunkTop, rot, new Vector3(1 / scale, scale, 1 / scale)); canopyBranch.CreateWorldObject(treeBase.transform); } return(treeBase); }
void DestroyBranch(int branchID) { TreeBranch branch = this.branches[branchID]; if (branch.Health > 0) { // replicate to all clients branch.Health = 0; this.RPC("DestroyBranch", branchID); } this.Save(); }
/// <summary> /// reset the tree for generating another one /// </summary> private void ResetTree() { for (int i = 0; i < TreeNode.Nodes.Count; i++) { Destroy(TreeNode.Nodes[i].GO); } TreeNode.Reset(); for (int i = 0; i < TreeBranch.Branches.Count; i++) { Destroy(TreeBranch.Branches[i].GO); } TreeBranch.Reset(); }
private GameObject createResponseButton(TreeBranch branch) { GameObject responseButton = Instantiate(responseButtonPrefab); var responseButtonText = (Text)responseButton.GetComponent <Text>(); responseButtonText.text = branch.description; var button = (Button)responseButton.GetComponent <Button>(); button.onClick.AddListener(() => ClickResponseButton(branch.linkIndex)); responseButton.transform.SetParent(responsePanel.transform, false); return(responseButton); }
void CountNodeChildren() // Walk the tree up from the terminal nodes and count the children of each node. { if (!isRooted) { throw new InvalidOperationException("The tree must be rooted to count children."); } foreach (TreeNode terminalNode in terminalNodesList) { terminalNode.childCount = 2; TreeNode currentNode = terminalNode; while (currentNode != root) { TreeBranch parentBranch = currentNode.parentBranch; TreeNode parentNode = (TreeNode)parentBranch.Follow(currentNode); TreeBranch otherChildBranch; if (parentNode.childBranch1 == parentBranch) { otherChildBranch = parentNode.childBranch2; } else // should be childBranch2 { otherChildBranch = parentNode.childBranch1; } if (otherChildBranch.Follow(parentNode).GetType() == typeof(TreeLeaf)) { parentNode.childCount = currentNode.childCount + 1; } else if (parentNode.childCount > 0) { parentNode.childCount += currentNode.childCount; } else { // Need to wait for another terminal node to propogate up. parentNode.childCount += currentNode.childCount; break; } currentNode = parentNode; } } }
private bool TryDamageBranch(INetObject damager, float amount, InteractionContext context) { int branchID = context.Parameters["branch"]; TreeBranch branch = this.branches[branchID]; if (context.Parameters.ContainsKey("leaf")) { int leafID = context.Parameters["leaf"]; // damage leaf LeafBunch leaf = branch.Leaves[leafID]; if (leaf.Health > 0) { leaf.Health = Mathf.Max(0, leaf.Health - amount); if (leaf.Health <= 0) { leaf.Health = 0; if (RandomUtil.Value < this.Species.SeedDropChance) { var numSeeds = (int)this.Species.SeedRange.Max; int numBonusSeeds = 0; Item[] newSeeds = new Item[] { }; if (numSeeds > 0 && this.Species.SeedItem != null) { var yield = ItemAttribute.Get <YieldAttribute>(this.Species.SeedItem.Type); numBonusSeeds = yield != null?yield.Yield.GetCurrentValueInt(context.Player.User) : 0; context.Player.User.Inventory.TryAddItems(this.Species.SeedItem.Type, numSeeds + numBonusSeeds); } } this.RPC("DestroyLeaves", branchID, leafID); } } this.Save(); return(true); } else { return(this.TryDamageBranch(branch, branchID, amount)); } }
public async Task Tree(CommandContext ctx, Group group) { //Get teh user group if (group == null) { throw new ArgumentNullException($"The group does not exist."); } //Get the tree var tree = await TreeBranch.CreateTreeAsync(group); var sb = new StringBuilder(); tree.BuildTreeString(sb); var export = sb.ToString(); if (export.Length < 1980) { await ctx.ReplyAsync("```\n" + export + "\n```"); } else { string tmppath = "tree_" + ctx.Guild.Id + "_" + group.Name + ".txt"; try { await System.IO.File.WriteAllTextAsync(tmppath, export); await ctx.RespondWithFileAsync(tmppath, "Exported Groups:"); await ctx.ReplyReactionAsync(true); } catch (Exception) { await ctx.ReplyReactionAsync(false); } finally { if (System.IO.File.Exists(tmppath)) { System.IO.File.Delete(tmppath); } } } }
public async void EC02_RoleSubtraction() { var engine = new Engine(); await engine.ImportAsync(@" ::everyone|0 -group.contributor ::contributor +group.role.contributor ::role.builder +group.contributor ::user.vex +group.everyone +group.role.builder ::user.lachee +group.everyone ::user.nobody ::role.contributor "); var vex = await engine.GetGroupAsync("user.vex"); Assert.NotNull(vex); var lachee = await engine.GetGroupAsync("user.lachee"); Assert.NotNull(lachee); var nobody = await engine.GetGroupAsync("user.nobody"); Assert.NotNull(nobody); var tree = await TreeBranch.CreateTreeAsync(vex); Assert.Equal(StateType.Allow, await vex.EvaluatePermissionAsync("group.role.contributor")); Assert.Equal(StateType.Deny, await lachee.EvaluatePermissionAsync("group.role.contributor")); Assert.Equal(StateType.Unset, await nobody.EvaluatePermissionAsync("group.role.contributor")); }
private static List <TreeBranch> getTreeBranchListFromDataStr(string linkDataStr) { List <TreeBranch> branchList = new List <TreeBranch>(); var linkList = ParseHelper.getSplitList(linkDataStr, Environment.NewLine); foreach (var link in linkList) { TreeBranch tb = new TreeBranch(); var linkDataList = ParseHelper.getSplitList(link, ":"); tb.linkIndex = Int64.Parse(linkDataList[0]); tb.description = ParseHelper.removeBlock(linkDataList[1], "{", "}"); tb.conditionList = getTreeBranchConditionList(linkDataList[1]); branchList.Add(tb); } return(branchList); }
private bool TryDamageBranch(TreeBranch branch, int branchID, float amount) { if (branch != null && branch.Health > 0) { branch.Health = Mathf.Max(0, branch.Health - amount); if (branch.Health <= 0) { branch.Health = 0; this.RPC("DestroyBranch", branchID); this.Save(); } return(true); } else { return(false); } }
/// <summary> /// traces the path from the leaf back to the root /// </summary> /// <param name="leaf"></param> private void TracePathToRoot(TreeNode leaf) { Queue <TreeBranch> path = new Queue <TreeBranch> (); SpriteRenderer sr; TreeNode node = leaf; //queue up all nodes from the leaf to the root while (node != TreeGenerator.root) { path.Enqueue(node.parentBranch); node = node.GetParent(); } //change all subsequent branches according to the leaf's state while (path.Count > 0) { TreeBranch branch = path.Dequeue(); sr = branch.GO.GetComponent <SpriteRenderer> (); sr.sprite = activeBranch; } }
public static void Build(TreeMember member1, TreeMember member2, double length) { TreeBranch newBranch = new TreeBranch(member1, member2, length); if (member1.GetType() == typeof(TreeNode)) { ((TreeNode)member1).AddBranch(newBranch); } else { member1.parentBranch = newBranch; } if (member2.GetType() == typeof(TreeNode)) { ((TreeNode)member2).AddBranch(newBranch); } else { member2.parentBranch = newBranch; } }
/// <summary> /// recursive constructor that ends up creating all tree by itself /// </summary> /// <param name="branching">the number of links each node has down the tree</param> /// <param name="currentDepth">how far down the tree is this node</param> /// <param name="type">Max or Min</param> public TreeNode(int branching, int currentDepth, NodeType type) { //node gets new ID, seed, depth and type randomSeed = Random.value; ID = Count++; Type = type; this.depth = currentDepth; SetInitialValues(); if (currentDepth < TreeGenerator.depth) { //sets up the branches linking to child nodes branches = new TreeBranch[branching]; for (int i = 0; i < branches.Length; i++) { NodeType newType = ((currentDepth + 1) % 2 == 0) ? NodeType.Max : NodeType.Min; branches[i] = new TreeBranch(this, new TreeNode(branching, currentDepth + 1, newType)); branches[i].b.parentBranch = branches[i]; } leafID = null; } else { //if its the last depth level, it becomes a leaf Type = NodeType.Leaf; branches = new TreeBranch[0]; Score = Random.Range(0, 20); leafID = ID; leaves.Add(this); } nodes.Add(this); }
private bool TryDamageBranch(INetObject damager, float amount, InteractionContext context) { int branchID = context.Parameters["branch"]; TreeBranch branch = this.branches[branchID]; if (context.Parameters.ContainsKey("leaf")) { int leafID = context.Parameters["leaf"]; // damage leaf LeafBunch leaf = branch.Leaves[leafID]; if (leaf.Health > 0) { List <IAtomicAction> actions = new List <IAtomicAction>(); if (damager is Player) { var action = PlayerActions.HarvestLeaves.CreateAtomicAction((Player)damager, this); actions.Add(action); if (!PlayerActions.HarvestLeaves.CreateAtomicAction((Player)damager, this).CanApply().Notify((Player)damager)) { // We only want to dispose the action if it is invalid. Othewise we want to keep it around to possibly apply later. action.Dispose(); return(false); } } leaf.Health = Mathf.Max(0, leaf.Health - amount); if (leaf.Health <= 0) { if (!new MultiAtomicAction(actions).TryApply().Success) { throw new Exception("Removing this stump was verified to be legal a moment ago, but is not anymore."); } leaf.Health = 0; if (RandomUtil.Value < this.Species.SeedDropChance) { var numSeeds = (int)this.Species.SeedRange.Max; int numBonusSeeds = 0; Item[] newSeeds = new Item[] { }; if (numSeeds > 0 && this.Species.SeedItem.Type != null) { var yield = ItemAttribute.Get <YieldAttribute>(this.Species.SeedItem.Type); numBonusSeeds = yield != null?yield.Yield.GetCurrentValueInt(context.Player.User) : 0; context.Player.User.Inventory.TryAddItems(this.Species.SeedItem.Type, numSeeds + numBonusSeeds); } } this.RPC("DestroyLeaves", branchID, leafID); } else { new MultiAtomicAction(actions).Dispose(); } } this.Save(); return(true); } else { return(this.TryDamageBranch(branch, branchID, amount)); } }
public void CalculateSimilarities() // Construct a similarities matrix // Clustal does this by storing the path to root for each leaf (storing the distance), then finds the common ancestor // for each pair, storing the distance from the other sequence to it. // // I think a better implementation would be to loop over the leaves to get their paths to root, then for each pair, // walk their paths until they diverge { similarityMatrix = new double[leavesCount, leavesCount]; Dictionary <TreeLeaf, List <Tuple <TreeNode, double> > > pathsToRoot = new Dictionary <TreeLeaf, List <Tuple <TreeNode, double> > >(); foreach (TreeLeaf leaf in leavesList) { List <Tuple <TreeNode, double> > pathToRoot = new List <Tuple <TreeNode, double> >(); double distance = 0; TreeBranch parentBranch = leaf.parentBranch; TreeNode parentNode = (TreeNode)parentBranch.Follow(leaf); while (true) { distance += parentBranch.BranchLength; pathToRoot.Add(Tuple.Create(parentNode, distance)); parentBranch = parentNode.parentBranch; if (parentBranch != null) { parentNode = (TreeNode)parentBranch.Follow(parentNode); } else { break; } } pathsToRoot.Add(leaf, pathToRoot); } for (int i = 0; i < leavesCount - 1; i++) { TreeLeaf leafI = leavesList[i]; List <Tuple <TreeNode, double> > pathToRootI = pathsToRoot[leafI]; for (int j = i + 1; j < leavesCount; j++) { TreeLeaf leafJ = leavesList[j]; List <Tuple <TreeNode, double> > pathToRootJ = pathsToRoot[leafJ]; bool found = false; foreach (Tuple <TreeNode, double> pathMemberI in pathToRootI) { foreach (Tuple <TreeNode, double> pathmemberJ in pathToRootJ) { if (pathMemberI.Item1 == pathmemberJ.Item1) { found = true; similarityMatrix[i, j] = 1 - (pathMemberI.Item2 + pathmemberJ.Item2); break; } } if (found) { break; } } } } // Then Clustal forces any values less than 0.01 to be 0.01 (within the sequence ranges) // and sets small values above 1 to 1, but values above 1.1 go into an error handling method. // I won't implement this yet. Note that this is done while they are still in distances, not // similarities. }
void DetermineSteps() // Determine the groups to be used in each step of the alignment. // Step through the tree to find the terminal leaf-only nodes and step back to join them together, // with each step stored in a tuple, and the leaf groups 1 and 2 stored in lists in members 1 and 2 of the // tuple, respectively. // Possible to parallelize, but it looks like the overhead is generally too much for the work being done. // may want to test that on larger sets, however. { if (!isRooted) { throw new InvalidOperationException("The tree must be rooted to determine alignment steps."); } Dictionary <TreeNode, List <TreeLeaf> > waitingList = new Dictionary <TreeNode, List <TreeLeaf> >(); // Store the members of one child of the node until the other child has been evaluated. steps = new List <Tuple <ReadOnlyCollection <T>, ReadOnlyCollection <T>, double> >(); foreach (TreeNode terminalNode in terminalNodesList) { List <TreeLeaf> group1 = new List <TreeLeaf>(); TreeLeaf leaf1 = (TreeLeaf)terminalNode.childBranch1.Follow(terminalNode); group1.Add(leaf1); List <TreeLeaf> group2 = new List <TreeLeaf>(); TreeLeaf leaf2 = (TreeLeaf)terminalNode.childBranch2.Follow(terminalNode); group2.Add(leaf2); steps.Add(CreateStep(group1, group2)); TreeNode currentNode = terminalNode; List <TreeLeaf> childLeaves = new List <TreeLeaf>(); childLeaves.Add(leaf1); childLeaves.Add(leaf2); while (currentNode != root) { TreeBranch parentBranch = currentNode.parentBranch; TreeNode parentNode = (TreeNode)parentBranch.Follow(currentNode); TreeBranch otherChildBranch; group1 = new List <TreeLeaf>(); group2 = new List <TreeLeaf>(); if (parentNode.childBranch1 == parentBranch) { otherChildBranch = parentNode.childBranch2; } else // should be childBranch2 { otherChildBranch = parentNode.childBranch1; } if (otherChildBranch.Follow(parentNode).GetType() == typeof(TreeLeaf)) // The other child is a leaf, so we're okay. { group1 = childLeaves; TreeLeaf otherChildLeaf = (TreeLeaf)otherChildBranch.Follow(parentNode); group2.Add(otherChildLeaf); } else if (waitingList.ContainsKey(parentNode)) // The other child is a node which was waiting for the other children to be evaluated. { group1 = childLeaves.ToList <TreeLeaf>(); group2 = waitingList[parentNode]; } else // The other child is a node. We'll need to save the current child and store the values // for later. This also means we need to start over with another terminal node. { waitingList.Add(parentNode, childLeaves); break; } steps.Add(CreateStep(group1, group2)); foreach (TreeLeaf leaf in group2) { childLeaves.Add(leaf); } currentNode = parentNode; } } }
void ReRoot() // Root an unrooted tree or adjust the root location after a rooted tree has beem modified { // Alternative algorithm: // 0. If the tree is already rooted, remove the root node. // 1. Find the average branch lengths extending from every node. // 2. Compute the differences using the largest branch // Treat the branches as vectors leaving the node separated evenly by 120 degrees, and treat // the largest branch length as the top vertical vector. Subtract the vertical components of the // other two vectors from the largest to find the difference score. // Since cos(60 deg) = 0.5, just multiply the other vectors' magnitudes by 0.5. // 3. Select the node with the smallest difference. // 4. Select the branch from that node with the largest average branch length. // a. If two or three branches are tied, select the branch among the ties with the longest // length to the next node. // b. If they are still tied, arbitrarily pick the first. // 5. Insert the root between the identified nodes, and set the branch lengths // satisfying x = (internode branch length - |difference|) / 2, where the side with the smaller average // branch length is increased by the difference. // 6. Walk the tree from the new root to assert parent relationships as needed. if (isRooted) { double branchLength; TreeMember connection1, connection2; // The root should only connect to two members connection1 = root.Branches[0].Follow(root); connection2 = root.Branches[1].Follow(root); branchLength = root.Branches[0].BranchLength + root.Branches[1].BranchLength; root.Branches[0].Destroy(); root.Branches[1].Destroy(); TreeBranch.Build(connection1, connection2, branchLength); } TreeMember rootConnection1, rootConnection2; TreeNode minNode = new TreeNode(); double minDifference = Double.MaxValue; TreeBranch minNodeMaxBranch = new TreeBranch(); TreeBranch minNodeTiedMaxBranch = new TreeBranch(); // Find the node with the smallest vector difference foreach (TreeNode node in nodesList) // parallelize? { Dictionary <TreeBranch, double> averageBranchLengths = new Dictionary <TreeBranch, double>(); TreeBranch maxBranch = null; TreeBranch tiedMaxBranch = null; double maxAverageBranchLength = 0; foreach (TreeBranch branch in node.Branches) { int numLeaves; double averageBranchLength = GetAverageBranchLength(node, branch, true, out numLeaves); averageBranchLengths.Add(branch, averageBranchLength); if (averageBranchLength > maxAverageBranchLength) { maxAverageBranchLength = averageBranchLength; maxBranch = branch; tiedMaxBranch = null; } else if (averageBranchLength == maxAverageBranchLength) { tiedMaxBranch = branch; } } double vectorDifference = maxAverageBranchLength; foreach (TreeBranch branch in node.Branches) { if (branch != maxBranch) { vectorDifference -= 0.5 * averageBranchLengths[branch]; } } if (vectorDifference < minDifference) { minDifference = vectorDifference; minNode = node; minNodeMaxBranch = maxBranch; minNodeTiedMaxBranch = tiedMaxBranch; } } rootConnection1 = minNode; // Found the minimum node. Now we must decide which branch the root should replace. // In the case of ties (minDifference = 0 or minNodeTiedMaxBranch is not null), the root // will be placed along the longest adjacent branch. If tie isn't broken, it will be the // first branch used. TreeBranch rootBranch; if (minDifference == 0) { double maxBranchLength = 0; TreeBranch maxBranch = new TreeBranch(); foreach (TreeBranch branch in minNode.Branches) { double branchLength = branch.BranchLength; if (branchLength > maxBranchLength) { maxBranchLength = branchLength; maxBranch = branch; } } rootBranch = maxBranch; } else if (minNodeTiedMaxBranch != null) { if (minNodeMaxBranch.BranchLength >= minNodeTiedMaxBranch.BranchLength) { rootBranch = minNodeMaxBranch; } else { rootBranch = minNodeTiedMaxBranch; } } else { rootBranch = minNodeMaxBranch; } rootConnection2 = rootBranch.Follow(rootConnection1); // Determine the lengths of the branches that will connect to the root. // This is determined by the equation: // Li = (Aj - Ai + (Nj * L)) / (Nj + Ni) // Where "i" and "j" each represent one of the root connections, L indicates length, // A indicates average branch length, and N indicates number of leaves. int numLeaves1, numLeaves2; double averageBranchLength1 = GetAverageBranchLength(rootConnection1, rootBranch, false, out numLeaves1); double averageBranchLength2 = GetAverageBranchLength(rootConnection2, rootBranch, false, out numLeaves2); double branchDifference = averageBranchLength1 - averageBranchLength2; double rootBranchLength1, rootBranchLength2; if (branchDifference != 0) { rootBranchLength1 = (averageBranchLength2 - averageBranchLength1 + (numLeaves2 * rootBranch.BranchLength)) / (numLeaves1 + numLeaves2); } else { rootBranchLength1 = (numLeaves2 * rootBranch.BranchLength) / (numLeaves1 + numLeaves2); } rootBranchLength2 = rootBranch.BranchLength - rootBranchLength1; rootBranch.Destroy(); // Remove the branch that will be replaced by the root node. isRooted = true; root = new TreeNode(this); TreeBranch.Build(root, rootConnection1, rootBranchLength1); TreeBranch.Build(root, rootConnection2, rootBranchLength2); // Now we need to walk the tree from the root to ensure that all the downstream // nodes have the parent assigned correctly. AssertPaternity(); }
private GameObject createResponseButton(TreeBranch branch) { GameObject responseButton = Instantiate(responseButtonPrefab); var responseButtonText = (Text)responseButton.GetComponent<Text>(); responseButtonText.text = branch.description; var button = (Button)responseButton.GetComponent<Button>(); button.onClick.AddListener(() => ClickResponseButton(branch.linkIndex)); responseButton.transform.SetParent(responsePanel.transform,false); return responseButton; }
private static List<TreeBranch> getTreeBranchListFromDataStr(string linkDataStr) { List<TreeBranch> branchList = new List<TreeBranch>(); var linkList = ParseHelper.getSplitList(linkDataStr, Environment.NewLine); foreach(var link in linkList) { TreeBranch tb = new TreeBranch(); var linkDataList = ParseHelper.getSplitList(link, ":"); tb.linkIndex = Int64.Parse(linkDataList[0]); tb.description = ParseHelper.removeBlock(linkDataList[1],"{","}"); tb.conditionList = getTreeBranchConditionList(linkDataList[1]); branchList.Add(tb); } return branchList; }
public IList<ITreeNode> FetchNodes(long[] nids) { // The number of nodes, int node_count = nids.Length; // The array of read nodes, ITreeNode[] result_nodes = new ITreeNode[node_count]; // Resolve special nodes first, { int i = 0; foreach (long nodeId in nids) { if ((nodeId & 0x01000000000000000L) != 0) result_nodes[i] = SparseLeafNode.Create(nodeId); ++i; } } // Group all the nodes to the same block, List<long> uniqueBlocks = new List<long>(); List<List<long>> uniqueBlockList = new List<List<long>>(); { int i = 0; foreach (long node_ref in nids) { // If it's not a special node, if ((node_ref & 0x01000000000000000L) == 0) { // Get the block id and add it to the list of unique blocks, DataAddress address = new DataAddress(node_ref); // Check if the node is in the local cache, ITreeNode node = networkCache.GetNode(address); if (node != null) { result_nodes[i] = node; } else { // Not in the local cache so we need to bundle this up in a node // request on the block servers, // Group this node request by the block identifier long blockId = address.BlockId; int ind = uniqueBlocks.IndexOf(blockId); if (ind == -1) { ind = uniqueBlocks.Count; uniqueBlocks.Add(blockId); uniqueBlockList.Add(new List<long>()); } List<long> blist = uniqueBlockList[ind]; blist.Add(node_ref); } } ++i; } } // Exit early if no blocks, if (uniqueBlocks.Count == 0) return result_nodes; // Resolve server records for the given block identifiers, IDictionary<long, IList<BlockServerElement>> servers_map = GetServersForBlock(uniqueBlocks); // The result nodes list, List<ITreeNode> nodes = new List<ITreeNode>(); // For each unique block list, foreach (List<long> blist in uniqueBlockList) { // Make a block server request for each node in the block, MessageStream block_server_msg = new MessageStream(MessageType.Request); long block_id = -1; foreach (long node_ref in blist) { DataAddress address = new DataAddress(node_ref); RequestMessage request = new RequestMessage("readFromBlock"); request.Arguments.Add(address); block_server_msg.AddMessage(request); block_id = address.BlockId; } if (block_id == -1) throw new ApplicationException("block_id == -1"); // Get the shuffled list of servers the block is stored on, IList<BlockServerElement> servers = servers_map[block_id]; // Go through the servers one at a time to fetch the block, bool success = false; for (int z = 0; z < servers.Count && !success; ++z) { BlockServerElement server = servers[z]; // If the server is up, if (server.IsStatusUp) { // Open a connection with the block server, IMessageProcessor block_server_proc = connector.Connect(server.Address, ServiceType.Block); MessageStream message_in = (MessageStream) block_server_proc.Process(block_server_msg); // DEBUG: ++networkCommCount; // DEBUG: ++networkFetchCommCount; bool is_error = false; bool severe_error = false; // Turn each none-error message into a node foreach (ResponseMessage m in message_in) { if (m.HasError) { // See if this error is a block read error. If it is, we don't // tell the manager server to lock this server out completely. bool is_block_read_error = m.Error.Source.Equals("Deveel.Data.Net.BlockReadException"); if (!is_block_read_error) { // If it's something other than a block read error, we mark // this error as severe, severe_error = true; } is_error = true; } else if (!is_error) { // The reply contains the block of data read. NodeSet node_set = (NodeSet)m.Arguments[0].Value; // Decode the node items into node objects, IEnumerator<Node> item_iterator = node_set.GetEnumerator(); while (item_iterator.MoveNext()) { // Get the node item, Node node_item = item_iterator.Current; long node_ref = node_item.Id; DataAddress address = new DataAddress(node_ref); // Wrap around a buffered DataInputStream for reading values // from the store. BinaryReader input = new BinaryReader(node_item.Input, Encoding.Unicode); short node_type = input.ReadInt16(); ITreeNode read_node; // Is the node type a leaf node? if (node_type == LeafType) { // Read the key int leaf_size = input.ReadInt32(); byte[] buf = ReadNodeAsBuffer(node_item); if (buf == null) { buf = new byte[leaf_size + 6]; input.Read(buf, 6, leaf_size); // Technically, we could comment these next two lines out. ByteBuffer.WriteInt2(node_type, buf, 0); ByteBuffer.WriteInt4(leaf_size, buf, 2); } // Create a leaf that's mapped to this data read_node = new ByteArrayTreeLeaf(node_ref, buf); ; } // Is the node type a branch node? else if (node_type == BranchType) { // Note that the entire branch is loaded into memory, int child_data_size = input.ReadInt32(); long[] data_arr = new long[child_data_size]; for (int n = 0; n < child_data_size; ++n) { data_arr[n] = input.ReadInt64(); } // Create the branch node, read_node = new TreeBranch(node_ref, data_arr, child_data_size); } else { throw new InvalidDataState("Unknown node type: " + node_type, address); } // Is the node already in the list? If so we don't add it. if (!IsInNodeList(node_ref, nodes)) { // Put the read node in the cache and add it to the 'nodes' // list. networkCache.SetNode(address, read_node); nodes.Add(read_node); } } } } // If there was no error while reading the result, we assume the node // requests were successfully read. if (is_error == false) { success = true; } else { if (severe_error) { // If this is an error, we need to report the failure to the // manager server, ReportBlockServerFailure(server.Address); // Remove the block id from the server list cache, networkCache.RemoveServers(block_id); } else { // Otherwise, not a severe error (probably a corrupt block on a // server), so shuffle the server list for this block_id so next // time there's less chance of hitting this bad block. IList<BlockServerElement> srvs = networkCache.GetServers(block_id); List<BlockServerElement> server_list = new List<BlockServerElement>(); server_list.AddRange(srvs); CollectionsUtil.Shuffle(server_list); networkCache.SetServers(block_id, server_list, 15 * 60 * 1000); } } } } // If the nodes were not successfully read, we generate an exception, if (!success) { // Remove from the cache, networkCache.RemoveServers(block_id); throw new ApplicationException("Unable to fetch node from block server"); } } int sz = nodes.Count; if (sz == 0) throw new ApplicationException("Empty nodes list"); for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; long node_ref = node.Id; for (int n = 0; n < nids.Length; ++n) { if (nids[n] == node_ref) result_nodes[n] = node; } } // Check the result_nodes list is completely populated, for (int n = 0; n < result_nodes.Length; ++n) { if (result_nodes[n] == null) throw new ApplicationException("Assertion failed: result_nodes not completely populated."); } return result_nodes; }
public void DecomposeTree(AbstractTree parentNode, AbstractTree node, TreeBranch branch, TreePath path) { if (!path.IsAdded) { Possibilities.Add(path); path.IsAdded = true; } // Recursive browse if (node is TreeConnector) { TreeConnector treeConnector = (TreeConnector)node; if (treeConnector.Connection == "&") { DecomposeTree(treeConnector, treeConnector.LeftTree, TreeBranch.Left, path); DecomposeTree(treeConnector, treeConnector.RightTree, TreeBranch.Right, path); } else if (treeConnector.Connection == "|") { // In this case, parentNode is a TreeOperator if (parentNode != null) { // Left distribution TreePath clonedPathLeftDistribution = (TreePath)path.Clone(); TreeConnector parentTreeConnectorLeftDistribution = (TreeConnector)parentNode.Clone(); // Right distribution TreePath clonedPathRightDistribution = (TreePath)path.Clone(); TreeConnector parentTreeConnectorRightDistribution = (TreeConnector)parentNode.Clone(); if (branch == TreeBranch.Left) { parentTreeConnectorLeftDistribution.LeftTree = treeConnector.LeftTree; parentTreeConnectorRightDistribution.LeftTree = treeConnector.RightTree; } else if (branch == TreeBranch.Right) { parentTreeConnectorLeftDistribution.RightTree = treeConnector.LeftTree; parentTreeConnectorRightDistribution.RightTree = treeConnector.RightTree; } // Remove obsolete path Possibilities.Remove(path); // Browse recursively distributed tree ; the path must be different (by ref) if the parent operator is 'OR' DecomposeTree( parentTreeConnectorLeftDistribution, parentTreeConnectorLeftDistribution.LeftTree, TreeBranch.Left, parentTreeConnectorLeftDistribution.Connection == "|" ? (TreePath)clonedPathLeftDistribution.Clone() : clonedPathLeftDistribution ); DecomposeTree( parentTreeConnectorLeftDistribution, parentTreeConnectorLeftDistribution.RightTree, TreeBranch.Right, clonedPathLeftDistribution ); DecomposeTree( parentTreeConnectorRightDistribution, parentTreeConnectorRightDistribution.LeftTree, TreeBranch.Left, parentTreeConnectorLeftDistribution.Connection == "|" ? (TreePath)clonedPathRightDistribution.Clone() : clonedPathRightDistribution ); DecomposeTree( parentTreeConnectorRightDistribution, parentTreeConnectorRightDistribution.RightTree, TreeBranch.Right, clonedPathRightDistribution ); } // The operator is the root of the tree; we simply divide the path else { TreePath clonedLeftPath = (TreePath)path.Clone(); TreePath clonedRightPath = (TreePath)path.Clone(); // Remove obsolete path Possibilities.Remove(path); DecomposeTree(treeConnector, treeConnector.LeftTree, TreeBranch.Left, clonedLeftPath); DecomposeTree(treeConnector, treeConnector.RightTree, TreeBranch.Right, clonedRightPath); } } break; } // Leaf else if (node is TreeValue) { TreeValue treeValue = (TreeValue)node; path.Add(treeValue); } }
private NodeId[] InternalPersist(TreeWrite sequence, int tryCount) { // NOTE: nodes are written in order of branches and then leaf nodes. All // branch nodes and leafs are grouped together. // The list of nodes to be allocated, IList<ITreeNode> allBranches = sequence.BranchNodes; IList<ITreeNode> allLeafs = sequence.LeafNodes; List<ITreeNode> nodes = new List<ITreeNode>(allBranches.Count + allLeafs.Count); nodes.AddRange(allBranches); nodes.AddRange(allLeafs); int sz = nodes.Count; // The list of allocated referenced for the nodes, DataAddress[] refs = new DataAddress[sz]; NodeId[] outNodeIds = new NodeId[sz]; MessageStream allocateMessageStream = new MessageStream(); // Allocate the space first, for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; // Is it a branch node? if (node is TreeBranch) { // Branch nodes are 1K in size, allocateMessageStream.AddMessage(new Message("allocateNode", 1024)); } // Otherwise, it must be a leaf node, else { // Leaf nodes are 4k in size, allocateMessageStream.AddMessage(new Message("allocateNode", 4096)); } } // Process a command on the manager, IEnumerable<Message> resultStream = ProcessManager(allocateMessageStream); // The unique list of blocks, List<BlockId> uniqueBlocks = new List<BlockId>(); // Parse the result stream one message at a time, the order will be the // order of the allocation messages, int n = 0; foreach (Message m in resultStream) { if (m.HasError) throw new ApplicationException(m.ErrorMessage); DataAddress addr = (DataAddress) m.Arguments[0].Value; refs[n] = addr; // Make a list of unique block identifiers, if (!uniqueBlocks.Contains(addr.BlockId)) { uniqueBlocks.Add(addr.BlockId); } ++n; } // Get the block to server map for each of the blocks, IDictionary<BlockId, IList<BlockServerElement>> blockToServerMap = GetServerListForBlocks(uniqueBlocks); // Make message streams for each unique block int ubidCount = uniqueBlocks.Count; MessageStream[] ubidStream = new MessageStream[ubidCount]; for (int i = 0; i < ubidStream.Length; ++i) { ubidStream[i] = new MessageStream(); } // Scan all the blocks and create the message streams, for (int i = 0; i < sz; ++i) { byte[] nodeBuf; ITreeNode node = nodes[i]; // Is it a branch node? if (node is TreeBranch) { TreeBranch branch = (TreeBranch) node; // Make a copy of the branch (NOTE; we clone() the array here). long[] curNodeData = (long[]) branch.NodeData.Clone(); int curNdsz = branch.NodeDataSize; branch = new TreeBranch(refs[i].Value, curNodeData, curNdsz); // The number of children int chsz = branch.ChildCount; // For each child, if it's a heap node, look up the child id and // reference map in the sequence and set the reference accordingly, for (int o = 0; o < chsz; ++o) { NodeId childId = branch.GetChild(o); if (childId.IsInMemory) { // The ref is currently on the heap, so adjust accordingly int refId = sequence.LookupRef(i, o); branch.SetChildOverride(refs[refId].Value, o); } } // Turn the branch into a 'node_buf' byte[] array object for // serialization. long[] nodeData = branch.NodeData; int ndsz = branch.NodeDataSize; MemoryStream bout = new MemoryStream(1024); BinaryWriter dout = new BinaryWriter(bout); dout.Write(StoreBranchType); dout.Write((short) 0); // Reserved for future dout.Write(0); // The crc32 checksum will be written here, dout.Write(ndsz); for (int o = 0; o < ndsz; ++o) { dout.Write(nodeData[o]); } dout.Flush(); // Turn it into a byte array, nodeBuf = bout.ToArray(); // Write the crc32 of the data, Crc32 checksum = new Crc32(); checksum.ComputeHash(nodeBuf, 8, nodeBuf.Length - 8); ByteBuffer.WriteInt4((int) checksum.CrcValue, nodeBuf, 4); // Put this branch into the local cache, networkCache.SetNode(refs[i], branch); } // If it's a leaf node, else { TreeLeaf leaf = (TreeLeaf) node; int lfsz = leaf.Length; nodeBuf = new byte[lfsz + 12]; // Format the data, ByteBuffer.WriteInt2(StoreLeafType, nodeBuf, 0); ByteBuffer.WriteInt2(0, nodeBuf, 2); // Reserved for future ByteBuffer.WriteInt4(lfsz, nodeBuf, 8); leaf.Read(0, nodeBuf, 12, lfsz); // Calculate and set the checksum, Crc32 checksum = new Crc32(); checksum.ComputeHash(nodeBuf, 8, nodeBuf.Length - 8); ByteBuffer.WriteInt4((int) checksum.CrcValue, nodeBuf, 4); // Put this leaf into the local cache, leaf = new MemoryTreeLeaf(refs[i].Value, nodeBuf); networkCache.SetNode(refs[i], leaf); } // The DataAddress this node is being written to, DataAddress address = refs[i]; // Get the block id, BlockId blockId = address.BlockId; int bid = uniqueBlocks.IndexOf(blockId); ubidStream[bid].AddMessage(new Message("writeToBlock", address, nodeBuf, 0, nodeBuf.Length)); // Update 'out_refs' array, outNodeIds[i] = refs[i].Value; } // A log of successfully processed operations, List<object> successProcess = new List<object>(64); // Now process the streams on the servers, for (int i = 0; i < ubidStream.Length; ++i) { // The output message, MessageStream outputStream = ubidStream[i]; // Get the servers this message needs to be sent to, BlockId blockId = uniqueBlocks[i]; IList<BlockServerElement> blockServers = blockToServerMap[blockId]; // Format a message for writing this node out, int bssz = blockServers.Count; IMessageProcessor[] blockServerProcs = new IMessageProcessor[bssz]; // Make the block server connections, for (int o = 0; o < bssz; ++o) { IServiceAddress address = blockServers[o].Address; blockServerProcs[o] = connector.Connect(address, ServiceType.Block); IEnumerable<Message> inputStream = blockServerProcs[o].Process(outputStream); ++NetworkCommCount; foreach (Message m in inputStream) { if (m.HasError) { // If this is an error, we need to report the failure to the // manager server, ReportBlockServerFailure(address); // Remove the block id from the server list cache, networkCache.RemoveServersWithBlock(blockId); // Rollback any server writes already successfully made, for (int p = 0; p < successProcess.Count; p += 2) { IServiceAddress blocksAddr = (IServiceAddress) successProcess[p]; MessageStream toRollback = (MessageStream) successProcess[p + 1]; List<DataAddress> rollbackNodes = new List<DataAddress>(128); foreach (Message rm in toRollback) { DataAddress raddr = (DataAddress) rm.Arguments[0].Value; rollbackNodes.Add(raddr); } // Create the rollback message, MessageStream rollbackMsg = new MessageStream(); rollbackMsg.AddMessage(new Message("rollbackNodes", new object[] {rollbackNodes.ToArray()})); // Send it to the block server, IEnumerable<Message> responseStream = connector.Connect(blocksAddr, ServiceType.Block).Process(rollbackMsg); ++NetworkCommCount; foreach (Message rbm in responseStream) { // If rollback generated an error we throw the error now // because this likely is a serious network error. if (rbm.HasError) { throw new NetworkWriteException("Write failed (rollback failed): " + rbm.ErrorMessage); } } } // Retry, if (tryCount > 0) return InternalPersist(sequence, tryCount - 1); // Otherwise we fail the write throw new NetworkWriteException(m.ErrorMessage); } } // If we succeeded without an error, add to the log successProcess.Add(address); successProcess.Add(outputStream); } } // Return the references, return outNodeIds; }
public IList<ITreeNode> FetchNodes(NodeId[] nids) { // The number of nodes, int nodeCount = nids.Length; // The array of read nodes, ITreeNode[] resultNodes = new ITreeNode[nodeCount]; // Resolve special nodes first, { int i = 0; foreach (NodeId nodeId in nids) { if (nodeId.IsSpecial) { resultNodes[i] = nodeId.CreateSpecialTreeNode(); } ++i; } } // Group all the nodes to the same block, List<BlockId> uniqueBlocks = new List<BlockId>(); List<List<NodeId>> uniqueBlockList = new List<List<NodeId>>(); { int i = 0; foreach (NodeId nodeId in nids) { // If it's not a special node, if (!nodeId.IsSpecial) { // Get the block id and add it to the list of unique blocks, DataAddress address = new DataAddress(nodeId); // Check if the node is in the local cache, ITreeNode node = networkCache.GetNode(address); if (node != null) { resultNodes[i] = node; } else { // Not in the local cache so we need to bundle this up in a node // request on the block servers, // Group this node request by the block identifier BlockId blockId = address.BlockId; int ind = uniqueBlocks.IndexOf(blockId); if (ind == -1) { ind = uniqueBlocks.Count; uniqueBlocks.Add(blockId); uniqueBlockList.Add(new List<NodeId>()); } List<NodeId> blist = uniqueBlockList[ind]; blist.Add(nodeId); } } ++i; } } // Exit early if no blocks, if (uniqueBlocks.Count == 0) { return resultNodes; } // Resolve server records for the given block identifiers, IDictionary<BlockId, IList<BlockServerElement>> serversMap = GetServerListForBlocks(uniqueBlocks); // The result nodes list, List<ITreeNode> nodes = new List<ITreeNode>(); // Checksumming objects byte[] checksumBuf = null; Crc32 crc32 = null; // For each unique block list, foreach (List<NodeId> blist in uniqueBlockList) { // Make a block server request for each node in the block, MessageStream blockServerMsg = new MessageStream(); BlockId blockId = null; foreach (NodeId nodeId in blist) { DataAddress address = new DataAddress(nodeId); blockServerMsg.AddMessage(new Message("readFromBlock", address)); blockId = address.BlockId; } if (blockId == null) { throw new ApplicationException("block_id == null"); } // Get the shuffled list of servers the block is stored on, IList<BlockServerElement> servers = serversMap[blockId]; // Go through the servers one at a time to fetch the block, bool success = false; for (int z = 0; z < servers.Count && !success; ++z) { BlockServerElement server = servers[z]; // If the server is up, if (server.IsStatusUp) { // Open a connection with the block server, IMessageProcessor blockServerProc = connector.Connect(server.Address, ServiceType.Block); IEnumerable<Message> messageIn = blockServerProc.Process(blockServerMsg); ++NetworkCommCount; ++NetworkFetchCommCount; bool isError = false; bool severeError = false; bool crcError = false; bool connectionError = false; // Turn each none-error message into a node foreach (Message m in messageIn) { if (m.HasError) { // See if this error is a block read error. If it is, we don't // tell the manager server to lock this server out completely. bool isBlockReadError = m.Error.Source.Equals("Deveel.Data.Net.BlockReadException"); // If it's a connection fault, if (IsConnectionFailMessage(m)) { connectionError = true; } else if (!isBlockReadError) { // If it's something other than a block read error or // connection failure, we set the severe flag, severeError = true; } isError = true; } else if (isError == false) { // The reply contains the block of data read. NodeSet nodeSet = (NodeSet) m.Arguments[0].Value; DataAddress address = null; // Catch any IOExceptions (corrupt zips, etc) try { // Decode the node items into Java node objects, foreach (Node nodeItem in nodeSet) { NodeId nodeId = nodeItem.Id; address = new DataAddress(nodeId); // Wrap around a buffered DataInputStream for reading values // from the store. BinaryReader input = new BinaryReader(nodeItem.Input); short nodeType = input.ReadInt16(); ITreeNode readNode = null; if (crc32 == null) crc32 = new Crc32(); crc32.Initialize(); // Is the node type a leaf node? if (nodeType == StoreLeafType) { // Read the checksum, input.ReadInt16(); // For future use... int checksum = input.ReadInt32(); // Read the size int leafSize = input.ReadInt32(); byte[] buf = StreamUtil.AsBuffer(nodeItem.Input); if (buf == null) { buf = new byte[leafSize + 12]; ByteBuffer.WriteInt4(leafSize, buf, 8); input.Read(buf, 12, leafSize); } // Check the checksum... crc32.ComputeHash(buf, 8, leafSize + 4); int calcChecksum = (int) crc32.CrcValue; if (checksum != calcChecksum) { // If there's a CRC failure, we reject his node, log.Warning(String.Format("CRC failure on node {0} @ {1}", nodeId, server.Address)); isError = true; crcError = true; // This causes the read to retry on a different server // with this block id } else { // Create a leaf that's mapped to this data ITreeNode leaf = new MemoryTreeLeaf(nodeId, buf); readNode = leaf; } } // Is the node type a branch node? else if (nodeType == StoreBranchType) { // Read the checksum, input.ReadInt16(); // For future use... int checksum = input.ReadInt32(); // Check the checksum objects, if (checksumBuf == null) checksumBuf = new byte[8]; // Note that the entire branch is loaded into memory, int childDataSize = input.ReadInt32(); ByteBuffer.WriteInt4(childDataSize, checksumBuf, 0); crc32.ComputeHash(checksumBuf, 0, 4); long[] dataArr = new long[childDataSize]; for (int n = 0; n < childDataSize; ++n) { long item = input.ReadInt64(); ByteBuffer.WriteInt8(item, checksumBuf, 0); crc32.ComputeHash(checksumBuf, 0, 8); dataArr[n] = item; } // The calculated checksum value, int calcChecksum = (int) crc32.CrcValue; if (checksum != calcChecksum) { // If there's a CRC failure, we reject his node, log.Warning(String.Format("CRC failure on node {0} @ {1}", nodeId, server.Address)); isError = true; crcError = true; // This causes the read to retry on a different server // with this block id } else { // Create the branch node, TreeBranch branch = new TreeBranch(nodeId, dataArr, childDataSize); readNode = branch; } } else { log.Error(String.Format("Unknown node {0} type: {1}", address, nodeType)); isError = true; } // Is the node already in the list? If so we don't add it. if (readNode != null && !IsInNodeList(nodeId, nodes)) { // Put the read node in the cache and add it to the 'nodes' // list. networkCache.SetNode(address, readNode); nodes.Add(readNode); } } // while (item_iterator.hasNext()) } catch (IOException e) { // This catches compression errors, as well as any other misc // IO errors. if (address != null) { log.Error(String.Format("IO Error reading node {0}", address)); } log.Error(e.Message, e); isError = true; } } } // for (Message m : message_in) // If there was no error while reading the result, we assume the node // requests were successfully read. if (isError == false) { success = true; } else { // If this is a connection failure, we report the block failure. if (connectionError) { // If this is an error, we need to report the failure to the // manager server, ReportBlockServerFailure(server.Address); // Remove the block id from the server list cache, networkCache.RemoveServersWithBlock(blockId); } else { String failType = "General"; if (crcError) { failType = "CRC Failure"; } else if (severeError) { failType = "Exception during process"; } // Report to the first manager the block failure, so it may // investigate and hopefully correct. ReportBlockIdCorruption(server.Address, blockId, failType); // Otherwise, not a severe error (probably a corrupt block on a // server), so shuffle the server list for this block_id so next // time there's less chance of hitting this bad block. IEnumerable<BlockServerElement> srvs = networkCache.GetServersWithBlock(blockId); if (srvs != null) { List<BlockServerElement> serverList = new List<BlockServerElement>(); serverList.AddRange(srvs); CollectionsUtil.Shuffle(serverList); networkCache.SetServersForBlock(blockId, serverList, 15*60*1000); } } // We will now go retry the query on the next block server, } } } // If the nodes were not successfully read, we generate an exception, if (!success) { // Remove from the cache, networkCache.RemoveServersWithBlock(blockId); throw new ApplicationException( "Unable to fetch node from a block server" + " (block = " + blockId + ")"); } } int sz = nodes.Count; if (sz == 0) { throw new ApplicationException("Empty nodes list"); } for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; NodeId nodeId = node.Id; for (int n = 0; n < nids.Length; ++n) { if (nids[n].Equals(nodeId)) { resultNodes[n] = node; } } } // Check the result_nodes list is completely populated, for (int n = 0; n < resultNodes.Length; ++n) { if (resultNodes[n] == null) { throw new ApplicationException("Assertion failed: result_nodes not completely populated."); } } return resultNodes; }
public DataAddress CreateDatabase() { // The child reference is a sparse node element NodeId childId = NodeId.CreateSpecialSparseNode((byte) 1, 4); // Create a branch, TreeBranch rootBranch = new TreeBranch(NodeId.CreateInMemoryNode(0L), MaxBranchSize); rootBranch.Set(childId, 4, Key.Tail, childId, 4); TreeWrite seq = new TreeWrite(); seq.NodeWrite(rootBranch); IList<NodeId> refs = Persist(seq); // The written root node reference, NodeId rootId = refs[0]; // Return the root, return new DataAddress(rootId); }
private static RenderBranch Create(double x, double y, int angle, TreeBranch branch, VariableContext variables, Graphics g, Font font) { double x2 = x - branch.Position * Math.Cos(angle * Math.PI / 180); double y2 = y + branch.Position * Math.Sin(angle * Math.PI / 180); double x1 = x2 + branch.Length * Math.Cos((angle + branch.Angle) * Math.PI / 180); double y1 = y2 - branch.Length * Math.Sin((angle + branch.Angle) * Math.PI / 180); double a = Funcs.Atan(x1, y1, x2, y2); x2 = x1 + (branch.Length - 2) * Math.Cos(a); y2 = y1 - (branch.Length - 2) * Math.Sin(a); RenderBranch[] branches = branch.Branches.Select(i => Create(x2, y2, angle + branch.Angle - 180, i, variables, g, font)).ToArray(); string description; double imageX = 0; double imageY = 0; Bitmap expressionImage = null; if (branch is ExpressionBranch) { string[] preVariables = variables.GetAllVariables(); Expression[] expressions = new MathyLanguageService().Compile((branch as ExpressionBranch).Expression, variables); foreach (Expression expression in expressions) { new MathyLanguageService().CreateEvaluator().Evaluate(expression, variables); } StringBuilder b = new StringBuilder(); foreach (string variableName in variables.GetAllVariables().Where(i => !preVariables.Contains(i))) { b.AppendFormat("{0}={1}", variableName, variables.GetValue(variableName)); } description = branch.Description + "\r\n" + b.ToString(); double xt = x2 + (branch as ExpressionBranch).ImageX * Math.Cos(a + Math.PI); double yt = y2 - (branch as ExpressionBranch).ImageX * Math.Sin(a + Math.PI); double d = (branch as ExpressionBranch).ImageY; imageX = xt + d * Math.Cos(a + Math.PI / 2); imageY = yt - d * Math.Sin(a + Math.PI / 2); expressionImage = new NodeVisualizer(expressions.Select(i => new NodeConverter().Convert(i)).ToArray()).VisulizeAsBitmap(); } else { string variableName = (branch as VariableBranch).VariableName; object value = variables.GetValue(variableName); description = string.Format("{0}\r\n{1}={2}", branch.Description, variableName, value); } double dx; double dy; EvaluateDescriptionPosition(branch, description, x1, y1, x2, y2, g, font, out dx, out dy); return(new RenderBranch() { X1 = x1, Y1 = y1, X2 = x2, Y2 = y2, IsVariable = branch is VariableBranch, ImageX = imageX, ImageY = imageY, Image = expressionImage, Branches = branches, DescriptionX = dx, DescriptionY = dy, Description = description }); }
public void RemoveParent() { parentBranch = null; }
private List<long> DoPersist(TreeWrite sequence, int tryCount) { // NOTE: nodes are written in order of branches and then leaf nodes. All // branch nodes and leafs are grouped together. // The list of nodes to be allocated, IList<ITreeNode> allBranches = sequence.BranchNodes; IList<ITreeNode> allLeafs = sequence.LeafNodes; List<ITreeNode> nodes = new List<ITreeNode>(allBranches.Count + allLeafs.Count); nodes.AddRange(allBranches); nodes.AddRange(allLeafs); int sz = nodes.Count; // The list of allocated referenced for the nodes, DataAddress[] refs = new DataAddress[sz]; long[] outRefs = new long[sz]; MessageStream allocateMessage = new MessageStream(MessageType.Request); // Make a connection with the manager server, IMessageProcessor manager = connector.Connect(managerAddress, ServiceType.Manager); // Allocate the space first, for (int i = 0; i < sz; ++i) { ITreeNode node = nodes[i]; RequestMessage request = new RequestMessage("allocateNode"); // Is it a branch node? if (node is TreeBranch) { // Branch nodes are 1K in size, request.Arguments.Add(1024); } else { // Leaf nodes are 4k in size, request.Arguments.Add(4096); } allocateMessage.AddMessage(request); } // The result of the set of allocations, MessageStream resultStream = (MessageStream) manager.Process(allocateMessage); //DEBUG: ++network_comm_count; // The unique list of blocks, List<long> uniqueBlocks = new List<long>(); // Parse the result stream one message at a time, the order will be the // order of the allocation messages, int n = 0; foreach (ResponseMessage m in resultStream) { if (m.HasError) throw m.Error.AsException(); DataAddress addr = (DataAddress) m.Arguments[0].Value; refs[n] = addr; // Make a list of unique block identifiers, if (!uniqueBlocks.Contains(addr.BlockId)) { uniqueBlocks.Add(addr.BlockId); } ++n; } // Get the block to server map for each of the blocks, IDictionary<long, IList<BlockServerElement>> blockToServerMap = GetServersForBlock(uniqueBlocks); // Make message streams for each unique block int ubid_count = uniqueBlocks.Count; MessageStream[] ubidStream = new MessageStream[ubid_count]; for (int i = 0; i < ubidStream.Length; ++i) { ubidStream[i] = new MessageStream(MessageType.Request); } // Scan all the blocks and create the message streams, for (int i = 0; i < sz; ++i) { byte[] nodeBuf; ITreeNode node = nodes[i]; // Is it a branch node? if (node is TreeBranch) { TreeBranch branch = (TreeBranch)node; // Make a copy of the branch (NOTE; we Clone() the array here). long[] curNodeData = (long[])branch.ChildPointers.Clone(); int curNdsz = branch.DataSize; branch = new TreeBranch(refs[i].Value, curNodeData, curNdsz); // The number of children int chsz = branch.ChildCount; // For each child, if it's a heap node, look up the child id and // reference map in the sequence and set the reference accordingly, for (int o = 0; o < chsz; ++o) { long childRef = branch.GetChild(o); if (childRef < 0) { // The ref is currently on the heap, so adjust accordingly int ref_id = sequence.LookupRef(i, o); branch.SetChildOverride(o, refs[ref_id].Value); } } // Turn the branch into a 'node_buf' byte[] array object for // serialization. long[] nodeData = branch.ChildPointers; int ndsz = branch.DataSize; MemoryStream bout = new MemoryStream(1024); BinaryWriter dout = new BinaryWriter(bout, Encoding.Unicode); dout.Write(BranchType); dout.Write(ndsz); for (int o = 0; o < ndsz; ++o) { dout.Write(nodeData[o]); } dout.Flush(); // Turn it into a byte array, nodeBuf = bout.ToArray(); // Put this branch into the local cache, networkCache.SetNode(refs[i], branch); } else { // If it's a leaf node, TreeLeaf leaf = (TreeLeaf)node; int lfsz = leaf.Length; nodeBuf = new byte[lfsz + 6]; // Technically, we could comment these next two lines out. ByteBuffer.WriteInt2(LeafType, nodeBuf, 0); ByteBuffer.WriteInt4(lfsz, nodeBuf, 2); leaf.Read(0, nodeBuf, 6, lfsz); // Put this leaf into the local cache, leaf = new ByteArrayTreeLeaf(refs[i].Value, nodeBuf); networkCache.SetNode(refs[i], leaf); } // The DataAddress this node is being written to, DataAddress address = refs[i]; // Get the block id, long blockId = address.BlockId; int bid = uniqueBlocks.IndexOf(blockId); RequestMessage request = new RequestMessage("writeToBlock"); request.Arguments.Add(address); request.Arguments.Add(nodeBuf); request.Arguments.Add(0); request.Arguments.Add(nodeBuf.Length); ubidStream[bid].AddMessage(request); // Update 'outRefs' array, outRefs[i] = refs[i].Value; } // A log of successfully processed operations, List<object> successProcess = new List<object>(64); // Now process the streams on the servers, for (int i = 0; i < ubidStream.Length; ++i) { // The output message, MessageStream requestMessageStream = ubidStream[i]; // Get the servers this message needs to be sent to, long block_id = uniqueBlocks[i]; IList<BlockServerElement> blockServers = blockToServerMap[block_id]; // Format a message for writing this node out, int bssz = blockServers.Count; IMessageProcessor[] blockServerProcs = new IMessageProcessor[bssz]; // Make the block server connections, for (int o = 0; o < bssz; ++o) { IServiceAddress address = blockServers[o].Address; blockServerProcs[o] = connector.Connect(address, ServiceType.Block); MessageStream responseMessageStream = (MessageStream) blockServerProcs[o].Process(requestMessageStream); //DEBUG: ++network_comm_count; if (responseMessageStream.HasError) { // If this is an error, we need to report the failure to the // manager server, ReportBlockServerFailure(address); // Remove the block id from the server list cache, networkCache.RemoveServers(block_id); // Rollback any server writes already successfully made, for (int p = 0; p < successProcess.Count; p += 2) { IServiceAddress blockAddress = (IServiceAddress) successProcess[p]; MessageStream toRollback = (MessageStream) successProcess[p + 1]; List<DataAddress> rollbackNodes = new List<DataAddress>(128); foreach(Message rm in toRollback) { DataAddress raddr = (DataAddress) rm.Arguments[0].Value; rollbackNodes.Add(raddr); } // Create the rollback message, RequestMessage rollbackRequest = new RequestMessage("rollbackNodes"); rollbackRequest.Arguments.Add(rollbackNodes.ToArray()); // Send it to the block server, Message responseMessage = connector.Connect(blockAddress, ServiceType.Block).Process(rollbackRequest); //DEBUG: ++network_comm_count; // If rollback generated an error we throw the error now // because this likely is a serious network error. if (responseMessage.HasError) throw new NetworkException("Rollback wrote failed: " + responseMessage.ErrorMessage); } // Retry, if (tryCount > 0) return DoPersist(sequence, tryCount - 1); // Otherwise we fail the write throw new NetworkException(responseMessageStream.ErrorMessage); } // If we succeeded without an error, add to the log successProcess.Add(address); successProcess.Add(requestMessageStream); } } // Return the references, return new List<long>(outRefs); }
static double GetSumBranchLength(TreeMember member, TreeBranch baseBranch, bool includeBranch, out int numLeaves) // This is a recursive function // { // Algorithm: // 1. Store the branch length to the current member in "distance" (except the first if includeBranch is true). // 2. If the current member is a node, add the other branches to the stack and continue the loop. // If the current member is a leaf, add 1 to the number of leaves, add the stemLength to the sumBranchLength, and subtract the length to this branch from the distance. // 3. double sumBranchLength = 0; numLeaves = 0; Stack <Tuple <TreeMember, TreeBranch> > arguments = new Stack <Tuple <TreeMember, TreeBranch> >(); double distance = 0; arguments.Push(Tuple.Create(baseBranch.Follow(member), baseBranch)); TreeBranch prevBranch = new TreeBranch(); bool stepBack = false; while (arguments.Count > 0) { Tuple <TreeMember, TreeBranch> nextArgument = arguments.Peek(); TreeMember nextMember = nextArgument.Item1; TreeBranch nextBaseBranch = nextArgument.Item2; if (nextMember.GetType() == typeof(TreeNode)) { TreeNode node = (TreeNode)nextMember; if (node.Branches.Contains(prevBranch)) // If the previously-used branch is a member of this node's branches, that means we've already used the // branches of this node, and can discard it. { stepBack = true; } else { distance += nextBaseBranch.BranchLength; foreach (TreeBranch branch in node.Branches) { if (branch != nextBaseBranch) { arguments.Push(Tuple.Create(branch.Follow(node), branch)); } } } } else // This is a leaf, so add the distance to the sum, increment the leaf count, and step backward { distance += nextBaseBranch.BranchLength; sumBranchLength += distance; numLeaves++; stepBack = true; } if (stepBack) { prevBranch = nextBaseBranch; distance -= nextBaseBranch.BranchLength; arguments.Pop(); stepBack = false; } } if (!includeBranch) { // If we didn't want to include the base branch length, correct for that here. sumBranchLength -= numLeaves * baseBranch.BranchLength; } return(sumBranchLength); }
public bool MoveNext() { // если текущий индекс не находиться в конце списка if (index < iterations.Count) { // текущее изображения берется из списка уже // пройденных на итерациях изображений Current = iterations[index++]; return true; } // иначе определение следующего изображения else { // определение действий на текущей итерациии switch (next) { // остановка метода ветвей и границ case IterationState.Stop: { return false; } // начало метода ветвей и границ case IterationState.Start: { // иницилизация данных dsu = new Dsu(Graph.CountVertex()); min = new Branch(float.PositiveInfinity, null); matrix = new ReductionMatrix(Graph.Adjacency); parent = new Branch(matrix.Reduce(), null); tree = new TreeBranch(Graph, parent); // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // переход в следующее состояние - левое ветвление метода next = IterationState.LeftBranching; return true; } // левое ветвление метода ветвей и границ case IterationState.LeftBranching: { // определение ребер с нулевой стоимостью var zeroEdges = new List<Digraph.Edge>(); for (int i = 0; i < matrix.Size; i++) for (int j = 0; j < matrix.Size; j++) if (matrix[i, j] == 0) zeroEdges.Add(new Digraph.Edge(i, j, matrix.MinInRow(i, j) + matrix.MinInColumn(j, i))); // если нет ребер ветвления - нет маршрута коммивояжера if (zeroEdges.Count == 0) { TsPath = new Digraph.Path(Graph); // остановка метода ветвей и границ next = IterationState.Stop; return false; } // определение ребра ветвления - ребра с максимальным штрафом edge = zeroEdges.OrderByDescending(e => e.Cost).ToList().First(); // создание левого потомка для данного родителя left = new Branch(parent.LowerBound + edge.Cost, new Digraph.Edge(-edge.Begin, -edge.End, float.PositiveInfinity)); // добавление в дерево ветвлений tree.Add(parent, Branch.Direction.Left, left); // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // переход в следующее состояние - правое ветвление метода next = IterationState.RightBranching; return true; } // правое ветвление метода case IterationState.RightBranching: { // исключение подмаршрутов для данного ребра ExcludeSubRoute(matrix, dsu, edge); // создание правого потомка для данного родителя right = new Branch(parent.LowerBound + matrix.Reduce(), new Digraph.Edge(edge.Begin, edge.End, Graph[edge.Begin, edge.End])); // добавление в дерево ветвлений tree.Add(parent, Branch.Direction.Right, right); // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // если размер матрицы достаточно мал if (matrix.RealSize == 2) { // переход в состояние - малый размер матрицы next = IterationState.LittleMatrix; return true; } // выбор новой родительской вершины из еще не подвергшихся ветвлению parent = tree.GetNotGoBranches().OrderBy(b => b.LowerBound).ToList().First(); // проверка на нахождения минимального ветвления и остановки if (min.LowerBound <= parent.LowerBound) { // формирование маршрута коммивояжера TsPath = tree.CreatePathFromBranch(min); // остановка метода next = IterationState.Stop; return false; } // корректировка матрицы для данного ветвления и редуцирование if (parent != right) { // новые непересекающиеся множества вершин dsu = new Dsu(Graph.CountVertex()); // исходная редуцированная матрица matrix = new ReductionMatrix(Graph.Adjacency); // получение текущих вершин для данного ветвления var currentPath = tree.GetEdgesBranching(parent); // исключение всех подмаршрутов foreach (var e in currentPath) ExcludeSubRoute(matrix, dsu, e); // редуцирование матрицы matrix.Reduce(); } // следующая итерация методав ветвей и границ - левое ветвление next = IterationState.LeftBranching; return true; } // малый рамзер матрицы, включение ребер в маршрут case IterationState.LittleMatrix: { // новый родитель parent = right; for (int i = 0; i < matrix.Size && countAdeddEdgeFromMatrix != 1; i++) for (int j = 0; j < matrix.Size && countAdeddEdgeFromMatrix != 1; j++) { if (matrix[i, j] == 0) { // исключение данного ребра из матрицы matrix[i, j] = float.PositiveInfinity; // создание и добавление правого ветвления к родителю right = new Branch(parent.LowerBound, new Digraph.Edge(i, j, Graph[i, j])); tree.Add(parent, Branch.Direction.Right, right); // новый родитель parent = right; // продолжать включать ребра в маршрут на следующей итерации countAdeddEdgeFromMatrix++; } } // если следующая итерация та же if (countAdeddEdgeFromMatrix == 1) { // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // на следующей итерации будет включено второе ребро countAdeddEdgeFromMatrix++; return true; } else // все ребра включены для данной матрицы countAdeddEdgeFromMatrix = 0; // иначе проверка на новое минимальное ветвление if (parent.LowerBound < min.LowerBound) min = parent; // создание и добавление нового изображения ветвления Current = Painter.Drawing(tree); iterations.Add(Current); // перемещение текущего индекса на конец списка index = iterations.Count; // выбор новой родительской вершины из еще не подвергшихся ветвлению parent = tree.GetNotGoBranches().OrderBy(b => b.LowerBound).ToList().First(); // проверка на нахождения минимального ветвления и остановки if (min.LowerBound <= parent.LowerBound) { // формирование маршрута коммивояжера TsPath = tree.CreatePathFromBranch(min); // остановка метода next = IterationState.Stop; return false; } // корректировка матрицы для данного ветвления и редуцирование if (parent != right) { // новые непересекающиеся множества вершин dsu = new Dsu(Graph.CountVertex()); // исходная редуцированная матрица matrix = new ReductionMatrix(Graph.Adjacency); // получение текущих вершин для данного ветвления var currentPath = tree.GetEdgesBranching(parent); // исключение всех подмаршрутов foreach (var e in currentPath) ExcludeSubRoute(matrix, dsu, e); // редуцирование матрицы matrix.Reduce(); } // следующая итерация методав ветвей и границ - левое ветвление next = IterationState.LeftBranching; return true; } default: return false; } } }
/// <summary> /// Нахождение маршрута коммивояжера /// </summary> /// <param name="graph">ограф. граф</param> /// <returns>маршрут коммивояжера</returns> public static Digraph.Path Tsp(Digraph graph) { // маршрут коммивояжера var TsPath = new Digraph.Path(graph); // если граф пуст if (graph.CountVertex() == 0) { // пустой маршрут return TsPath; } // если граф имеет одну вершину else if (graph.CountVertex() == 1) { TsPath.Append(new Digraph.Edge(0, 0, 0)); // маршрут для одной вершины return TsPath; } // если граф имеет две вершины else if (graph.CountVertex() == 2) { TsPath.Append(new Digraph.Edge(0, 1, graph[0, 1])); TsPath.Append(new Digraph.Edge(1, 0, graph[1, 0])); // маршрут для двух вершин return TsPath; } /// Создания неперекающихся множеств вершин в графе, /// для определения и исключения подмаршрутов графа var dsu = new Dsu(graph.CountVertex()); // минимальное ветвление var minBranch = new Branch(float.PositiveInfinity, null); /// Получение исходной матрицы смежности данного графа var matrix = new ReductionMatrix(graph.Adjacency); /// Создание корня и дерева ветвления var parentBranch = new Branch(matrix.Reduce(), null); var tree = new TreeBranch(graph, parentBranch); for (; ; ) { // ребра с нулевой стоимостью var zeroEdges = new List<Digraph.Edge>(); // Получение всех ребер и соответсвующих штрафов for (int i = 0; i < matrix.Size; i++) for (int j = 0; j < matrix.Size; j++) if (matrix[i, j] == 0) zeroEdges.Add(new Digraph.Edge(i, j, matrix.MinInRow(i, j) + matrix.MinInColumn(j, i))); // если нет ребер ветвления - нет маршрута коммивояжера if (zeroEdges.Count == 0) return new Digraph.Path(graph); /// Определение ребра ветвления - ребра с максимальным штрафом var branchingEdge = zeroEdges.OrderByDescending(e => e.Cost).ToList().First(); /// Процесс ветления - не включая данное ребро var leftBranch = new Branch(parentBranch.LowerBound + branchingEdge.Cost, new Digraph.Edge(-branchingEdge.Begin, -branchingEdge.End, float.PositiveInfinity)); // добавление ветвления в дерево tree.Add(parentBranch, Branch.Direction.Left, leftBranch); /// Процесс ветления - включая данное ребро ExcludeSubRoute(matrix, dsu, branchingEdge); var rightBranch = new Branch(parentBranch.LowerBound + matrix.Reduce(), new Digraph.Edge(branchingEdge.Begin, branchingEdge.End, graph[branchingEdge.Begin, branchingEdge.End])); // добавление ветвления в дерево tree.Add(parentBranch, Branch.Direction.Right, rightBranch); /// Проверка на достаточность размера матрцицы if (matrix.RealSize == 2) { // новый родитель parentBranch = rightBranch; /// Добавление оставщихся ребер в дерево ветвлений for (int i = 0; i < matrix.Size; i++) for (int j = 0; j < matrix.Size; j++) if (matrix[i, j] == 0) { // новый потомок rightBranch = new Branch(parentBranch.LowerBound, new Digraph.Edge(i, j, graph[i, j])); tree.Add(parentBranch, Branch.Direction.Right, rightBranch); // потомок теперь родитель parentBranch = rightBranch; } /// Определение нового минимального ветвления if (parentBranch.LowerBound < minBranch.LowerBound) minBranch = parentBranch; } /// Выбор новой родительской вершины из еще не подвергшихся ветвлению parentBranch = tree.GetNotGoBranches().OrderBy(b => b.LowerBound).ToList().First(); /// Проверка на нахождения минимального ветвления и остановки if (minBranch.LowerBound <= parentBranch.LowerBound) break; /// Корректировка матрицы для данного ветвления и редуцирование if (parentBranch != rightBranch) { // новые непересекающиеся множества вершин dsu = new Dsu(graph.CountVertex()); // исходная редуцированная матрица matrix = new ReductionMatrix(graph.Adjacency); // получение текущих вершин для данного ветвления var currentPath = tree.GetEdgesBranching(parentBranch); // исключение всех подмаршрутов foreach (var e in currentPath) ExcludeSubRoute(matrix, dsu, e); // редуцирование матрицы matrix.Reduce(); } } // формирование маршрута коммивояжера TsPath = tree.CreatePathFromBranch(minBranch); return TsPath; }