/// <summary> /// Join an sub-CART tree this . /// </summary> /// <param name="isLeft">Is a left child .</param> /// <param name="idx">Node index .</param> /// <param name="subRoot">New child node .</param> public void JoinSubTree(bool isLeft, ref int idx, CartNode subRoot) { subRoot.Parent = this; subRoot.Index = idx; if (isLeft) { LeftChild = subRoot; subRoot.ParentIndex = Index; } else { RightChild = subRoot; subRoot.ParentIndex = -Index; } if (subRoot.LeftChild != null) { idx++; subRoot.JoinSubTree(true, ref idx, subRoot.LeftChild); } if (subRoot.RightChild != null) { idx++; subRoot.JoinSubTree(false, ref idx, subRoot.RightChild); } }
/// <summary> /// Load a Cart Node from bindary stream, which is Mulan CRT compatible. /// </summary> /// <param name="br">Binary reader to load CART node.</param> public void Load(BinaryReader br) { if (br == null) { throw new ArgumentNullException("br"); } try { br.ReadInt32(); // Skip the yes child's offset br.ReadInt32(); // Skip the no child's offset NodeType noteType = (NodeType)br.ReadInt32(); if (noteType == NodeType.NotLeaf) { _question = new Question(_metaCart); uint size = br.ReadUInt32(); int startPos = br.ReadInt32(); OperatorSerial[] express = new OperatorSerial[size]; for (uint i = 0; i < size; i++) { express[i] = OperatorSerial.Read(br); } // TODO: parse it into logical presentation string logic = OperatorSerial.ToString(startPos, express); _question.Parse(logic); _leftChild = new CartNode(_metaCart); _leftChild.Load(br); _leftChild.Parent = this; _rightChild = new CartNode(_metaCart); _rightChild.Load(br); _rightChild.Parent = this; QuestionLogic = _question.ToString(); } else if (noteType == NodeType.Leaf) { // AbstractSet int setType = br.ReadInt32(); Debug.Assert(setType == (int)SetType.AbstractSet); int minValue = br.ReadInt32(); int maxValue = br.ReadInt32(); Debug.Assert(maxValue >= minValue); setType = br.ReadInt32(); _setType = (SetType)setType; switch (_setType) { case SetType.BitSet: { // BitSet int size = br.ReadInt32(); Debug.Assert(size == maxValue - minValue + 1); int setCount = br.ReadInt32(); // calculate the number of bytes to allocate to save // the bit set data. the data is INT (4 bytes) aligned int bytesRequired = ((size + 31) >> 5) * 4; byte[] bits = br.ReadBytes(bytesRequired); if (bits.Length != bytesRequired) { string message = string.Format(CultureInfo.InvariantCulture, "Malformed data found, for there is no enough data for Bit set."); throw new InvalidDataException(message); } _unitSet = new BitArray(bits); _unitSet.Length = size; int loadSetCount = 0; for (int k = 0; k < _unitSet.Length; k++) { loadSetCount += _unitSet.Get(k) ? 1 : 0; } Debug.Assert(loadSetCount == setCount); } break; case SetType.IndexSet: { // Count of integer int size = br.ReadInt32(); // Index data _unitSet = new BitArray(maxValue - minValue + 1); _unitSet.SetAll(false); int n = 0; for (int i = 0; i < size; i++) { n = br.ReadInt32(); if (n > _unitSet.Length - 1 || n < 0) { throw new InvalidDataException("Invalid index set data"); } _unitSet.Set(n, true); } } break; default: { throw new InvalidDataException("Invalid set type"); } } } else { Debug.Assert(false); string message = string.Format(CultureInfo.InvariantCulture, "Invalid node type [{0}] of CART tree node found", noteType); throw new InvalidDataException(message); } } catch (EndOfStreamException ese) { string message = string.Format(CultureInfo.InvariantCulture, "Fail to CART tree node from binary stream for invalid data."); throw new InvalidDataException(message, ese); } catch (InvalidDataException ide) { string message = string.Format(CultureInfo.InvariantCulture, "Fail to load CART node from binary stream"); throw new InvalidDataException(message, ide); } }
/// <summary> /// Load CART tree from text file. /// </summary> /// <param name="filePath">Text CART file to load.</param> public void Load(string filePath) { Nodes.Clear(); try { using (StreamReader sr = new StreamReader(filePath)) { string line = null; while ((line = sr.ReadLine()) != null) { line = line.Trim(); if (string.IsNullOrEmpty(line)) { continue; } Match m = Regex.Match(line, @"(\S+)\s+(\S+)\s+(\S+)\s+(.*)"); if (!m.Success) { System.Diagnostics.Debug.Assert(m.Success); } CartNode node = new CartNode(_metaCart); node.Index = int.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture); node.ParentIndex = int.Parse(m.Groups[2].Value, CultureInfo.InvariantCulture); node.QuestionLogic = m.Groups[3].Value; node.SetPresent = m.Groups[4].Value; if (node.QuestionLogic != "*") { node.Question = new Question(MetaCart); node.Question.Parse(node.QuestionLogic); } if (node.SetPresent != "*") { ParseSetPresentation(node.SetPresent, node.UnitSet); } Nodes.Add(node); System.Diagnostics.Debug.Assert(node.Index == Nodes.IndexOf(node) + 1); } } } catch (NotSupportedException nse) { string message = string.Format(CultureInfo.InvariantCulture, "Failed to load CART tree file in text format from [{0}]", filePath); throw new InvalidDataException(message, nse); } // PostBuild PostLoad(); }
/// <summary> /// Run post-load. /// </summary> private void PostLoad() { for (int i = Nodes.Count - 1; i >= 0; --i) { CartNode node = Nodes[i]; if (node.ParentIndex == 0) { Root = node; break; } else if (node.ParentIndex > 0) { if (node.ParentIndex - 1 < 0 || node.ParentIndex - 1 >= Nodes.Count) { string message = string.Format(CultureInfo.InvariantCulture, "The cart tree file is malformed for the parent index [{0}] is out of range [{1}].", node.ParentIndex - 1, Nodes.Count); throw new InvalidDataException(message); } node.Parent = Nodes[node.ParentIndex - 1]; if (node.Parent == null) { string message = string.Format(CultureInfo.InvariantCulture, "The cart tree file is malformed for the parent index [{0}] has no parent.", node.ParentIndex - 1); throw new InvalidDataException(message); } System.Diagnostics.Debug.Assert(node.Parent.LeftChild == null); node.Parent.LeftChild = node; } else { // node.ParentIndex < 0 if (-node.ParentIndex - 1 < 0 || -node.ParentIndex - 1 >= Nodes.Count) { string message = string.Format(CultureInfo.InvariantCulture, "The cart tree file is malformed for the parent index [{0}] is out of range [{1}].", -node.ParentIndex - 1, Nodes.Count); throw new InvalidDataException(message); } node.Parent = Nodes[-node.ParentIndex - 1]; if (node.Parent == null) { string message = string.Format(CultureInfo.InvariantCulture, "The cart tree file is malformed for the parent index [{0}] has no parent.", -node.ParentIndex - 1); throw new InvalidDataException(message); } System.Diagnostics.Debug.Assert(node.Parent.RightChild == null); node.Parent.RightChild = node; } } }
/// <summary> /// Load CART tree from binary stream. /// </summary> /// <param name="br">Binary reader to load CART tree from.</param> public void Load(BinaryReader br) { Nodes.Clear(); CartNode node = new CartNode(_metaCart); node.Load(br); Root = node; }