1 package net.obsearch.example;
2
3 import java.io.DataInputStream;
4 import java.io.DataOutputStream;
5 import java.io.IOException;
6 import java.io.StringReader;
7 import java.util.LinkedList;
8 import java.util.List;
9 import java.util.ListIterator;
10
11 import net.obsearch.OB;
12 import net.obsearch.exception.OBException;
13 import net.obsearch.ob.OBShort;
14
15
16
17 import antlr.RecognitionException;
18
19 import com.sleepycat.bind.tuple.TupleInput;
20 import com.sleepycat.bind.tuple.TupleOutput;
21
22 /*
23 OBSearch: a distributed similarity search engine
24 This project is to similarity search what 'bit-torrent' is to downloads.
25 Copyright (C) 2007 Arnoldo Jose Muller Molina
26
27 This program is free software; you can redistribute it and/or modify
28 it under the terms of the GNU General Public License as published by
29 the Free Software Foundation; either version 2 of the License, or
30 (at your option) any later version.
31
32 This program is distributed in the hope that it will be useful,
33 but WITHOUT ANY WARRANTY; without even the implied warranty of
34 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 GNU General Public License for more details.
36
37 You should have received a copy of the GNU General Public License along
38 with this program; if not, write to the Free Software Foundation, Inc.,
39 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
40 */
41 /**
42 * Example Object that can be stored in OBSearch This class reads strings
43 * representations of trees and calculates the distance between the objects by
44 * using a tree distance function.
45 * @author Arnoldo Jose Muller Molina
46 * @since 0.7
47 */
48
49 public class OBSlice implements OBShort {
50
51
52
53 /**
54 * The root node of the tree.
55 */
56 protected SliceAST tree;
57 private int hashCode;
58
59
60
61 /**
62 * Default constructor must be provided by every object that implements the
63 * interface OB.
64 */
65 public OBSlice() {
66
67 }
68
69 public SliceAST getTree(){
70 return tree;
71 }
72
73 /**
74 * Creates an slice object.
75 * @param slice
76 * A string representation of a tree.
77 */
78 public OBSlice(final String slice) throws OBException {
79 this.updateTree(slice);
80 assert tree.equalsTree( this.parseTree(tree.toFuriaChanTree())) : "This: " + tree.toFuriaChanTree() + " slice: " + slice + " size: " + tree.getSize();
81 }
82
83 /**
84 * Calculates the distance between two trees. TODO: traverse the smallest
85 * tree.
86 * @param object
87 * The other object to compare
88 * @see net.obsearch.OB#distance(net.obsearch.OB,
89 * net.obsearch.result.Dim)
90 * @throws OBException
91 * if something wrong happens.
92 * @return A short that indicates how similar or different the trees are.
93 */
94 public final short distance(final OBShort object) throws OBException {
95 OBSlice b = (OBSlice) object;
96 assert this.tree != null;
97 assert b.tree != null;
98 if (this.tree.getSize() < b.tree.getSize()) {
99 return distance(this.tree, b.tree);
100 } else {
101 return distance(b.tree, this.tree);
102 }
103 }
104
105 /**
106 * Calculates the distance between trees a and b.
107 * @param a
108 * The first tree (should be smaller than b)
109 * @param b
110 * The second tree
111 * @return The distance of the trees.
112 */
113 private final short distance(SliceAST a, SliceAST b) {
114
115 List < SliceAST > aExpanded = a.depthFirst();
116 List < SliceAST > bExpanded = b.depthFirst();
117 List < SliceAST > bExpanded2 = new LinkedList < SliceAST >();
118 bExpanded2.addAll(bExpanded);
119 int Na = aExpanded.size() * 2;
120 int Nb = bExpanded.size() * 2;
121
122 ListIterator < SliceAST > ait = aExpanded.listIterator();
123 int res = 0;
124 while (ait.hasNext()) {
125 SliceAST aTree = ait.next();
126 ListIterator < SliceAST > bit = bExpanded.listIterator();
127 while (bit.hasNext()) {
128 SliceAST bTree = bit.next();
129 if (aTree.equalsTree(bTree)) {
130 res++;
131 bit.remove();
132 break;
133 }
134 }
135 // do the same for the nodes without children
136 bit = bExpanded2.listIterator();
137 while (bit.hasNext()) {
138 SliceAST bTree = bit.next();
139 if (aTree.getText().equals(bTree.getText())) {
140 res++;
141 bit.remove();
142 break;
143 }
144 }
145 }
146 // return Na - res + Nb - res;
147 // return (Na + Nb) - ( 2 * res);
148 short r = (short) (((Na + Nb) - (2 * res)) / 2);
149 assert r >= 0;
150 return r;
151 }
152
153 /**
154 * Internal method that updates the Tree from the String
155 * @throws OBException
156 */
157 protected final void updateTree(String x) throws OBException {
158 tree = parseTree(x);
159 this.hashCode = tree.toFuriaChanTree().hashCode();
160 }
161
162 private final SliceAST parseTree(String x) throws SliceParseException {
163 try {
164 SliceLexer lexer = new SliceLexer(new StringReader(x));
165 SliceParser parser = new SliceParser(lexer);
166 parser.setASTNodeClass("net.obsearch.example.SliceAST");
167 parser.slice();
168 SliceAST t = (SliceAST) parser.getAST();
169 t.updateDecendantInformation();
170 return t;
171 } catch (Exception e) {
172 throw new SliceParseException(x, e);
173 }
174 }
175
176
177
178 /**
179 * Returns the size (in nodes) of the tree.
180 * @return The size of the tree.
181 * @throws OBException
182 * If something goes wrong.
183 */
184 public final int size() throws OBException {
185 return tree.getSize();
186 }
187
188 /**
189 * @return A String representation of the tree.
190 */
191 public final String toString() {
192 String res = ":)";
193 try {
194 res = tree.toFuriaChanTree() + "|" + tree.getSize() + "|";
195 } catch (Exception e) {
196 assert false;
197 }
198 return res;
199 }
200
201 /**
202 * Re-creates this object from the given byte stream
203 * @param in
204 * A byte vector from which the stream will be loaded.
205 * @see net.obsearch.Storable#load(com.sleepycat.bind.tuple.TupleInput)
206 */
207 public final void load(byte [] in) throws IOException, OBException {
208 updateTree(new String(in));
209 }
210
211 public final int recordSize(){
212 return 0;
213 }
214
215 /**
216 * Stores this object into the given byte stream.
217 * @param out
218 * The byte stream to be used
219 * @see net.obsearch.Storable#store(com.sleepycat.bind.tuple.TupleOutput)
220 */
221 public final byte[] store() throws IOException{
222 return tree.toFuriaChanTree().getBytes();
223 }
224
225 /**
226 * Returns true of this.tree.equals(obj.tree). For this distance function
227 * this.distance(obj) == 0 implies that this.equals(obj) == true
228 * @param obj
229 * Object to compare.
230 * @return true if this == obj
231 */
232 public final boolean equals(final Object obj) {
233 if (!(obj instanceof OBSlice)) {
234 assert false;
235 return false;
236 }
237 OBSlice o = (OBSlice) obj;
238 return tree.equalsTree(o.tree);
239 }
240
241 /**
242 * A hashCode based on the string representation of the tree.
243 * @return a hash code of the string representation of this tree.
244 */
245 public final int hashCode() {
246 return this.hashCode;
247 }
248
249 }