(no commit message)
[jalview.git] / forester / java / src / org / forester / evoinference / TestPhylogenyReconstruction.java
1 // $Id:
2 // $
3 //
4 // FORESTER -- software libraries and applications
5 // for evolutionary biology research and applications.
6 //
7 // Copyright (C) 2008-2009 Christian M. Zmasek
8 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
9 // All rights reserved
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 //
25 // Contact: phylosoft @ gmail . com
26 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
27
28 package org.forester.evoinference;
29
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.StringWriter;
33 import java.util.Date;
34 import java.util.List;
35 import java.util.Set;
36
37 import org.forester.evoinference.distance.NeighborJoining;
38 import org.forester.evoinference.distance.NeighborJoiningF;
39 import org.forester.evoinference.distance.NeighborJoiningR;
40 import org.forester.evoinference.distance.PairwiseDistanceCalculator;
41 import org.forester.evoinference.distance.Sarray;
42 import org.forester.evoinference.distance.Sset;
43 import org.forester.evoinference.matrix.character.BasicCharacterStateMatrix;
44 import org.forester.evoinference.matrix.character.CharacterStateMatrix;
45 import org.forester.evoinference.matrix.character.CharacterStateMatrix.BinaryStates;
46 import org.forester.evoinference.matrix.character.CharacterStateMatrix.GainLossStates;
47 import org.forester.evoinference.matrix.distance.BasicSymmetricalDistanceMatrix;
48 import org.forester.evoinference.matrix.distance.DistanceMatrix;
49 import org.forester.evoinference.parsimony.DolloParsimony;
50 import org.forester.evoinference.parsimony.FitchParsimony;
51 import org.forester.io.parsers.GeneralMsaParser;
52 import org.forester.io.parsers.SymmetricalDistanceMatrixParser;
53 import org.forester.io.parsers.nhx.NHXParser;
54 import org.forester.msa.Msa;
55 import org.forester.phylogeny.Phylogeny;
56 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
57 import org.forester.phylogeny.factories.PhylogenyFactory;
58 import org.forester.util.ForesterUtil;
59
60 public class TestPhylogenyReconstruction {
61
62     private final static double ZERO_DIFF = 1.0E-9;
63
64     public static boolean isEqual( final double a, final double b ) {
65         return ( ( Math.abs( a - b ) ) < ZERO_DIFF );
66     }
67
68     public static boolean isUnequal( final double a, final double b ) {
69         return !isEqual( a, b );
70     }
71
72     public static void main( final String[] args ) {
73         System.out.println( "NJ" );
74         if ( testNeighborJoining() ) {
75             System.out.println( "  OK." );
76         }
77         else {
78             System.out.println( "  failed." );
79         }
80         System.out.println( "S" );
81         if ( testS() ) {
82             System.out.println( "  OK." );
83         }
84         else {
85             System.out.println( "  failed." );
86         }
87         System.out.println( "Sarray" );
88         if ( testSarray() ) {
89             System.out.println( "  OK." );
90         }
91         else {
92             System.out.println( "  failed." );
93         }
94         System.out.println( "NJR" );
95         if ( testNeighborJoiningR() ) {
96             System.out.println( "  OK." );
97         }
98         else {
99             System.out.println( "  failed." );
100         }
101         timeNeighborJoining();
102     }
103
104     public static boolean test( final File test_dir ) {
105         System.out.print( "  Basic symmetrical distance matrix: " );
106         if ( !testBasicSymmetricalDistanceMatrix() ) {
107             System.out.println( "failed." );
108             return false;
109         }
110         System.out.println( "OK." );
111         System.out.print( "  Basic character state matrix: " );
112         if ( !testBasicCharacterStateMatrix() ) {
113             System.out.println( "failed." );
114             return false;
115         }
116         System.out.println( "OK." );
117         System.out.print( "  Symmetrical distance matrix parser: " );
118         if ( !testSymmetricalDistanceMatrixParser() ) {
119             System.out.println( "failed." );
120             return false;
121         }
122         System.out.println( "OK." );
123         System.out.print( "  Distance Calculation: " );
124         if ( !testDistanceCalculationMethods( test_dir ) ) {
125             System.out.println( "failed." );
126             return false;
127         }
128         System.out.println( "OK." );
129         System.out.print( "  Datastructure S: " );
130         if ( !testS() ) {
131             System.out.println( "failed." );
132             return false;
133         }
134         System.out.println( "OK." );
135         System.out.print( "  Neighbor Joining: " );
136         if ( !testNeighborJoining() ) {
137             System.out.println( "failed." );
138             return false;
139         }
140         System.out.println( "OK." );
141         System.out.print( "  Dollo Parsimony: " );
142         if ( !testDolloParsimony() ) {
143             System.out.println( "failed." );
144             return false;
145         }
146         System.out.println( "OK." );
147         System.out.print( "  Dollo Parsimony on non binary trees: " );
148         if ( !testDolloParsimonyOnNonBinaryTree() ) {
149             System.out.println( "failed." );
150             return false;
151         }
152         System.out.println( "OK." );
153         System.out.print( "  Fitch Parsimony: " );
154         if ( !testFitchParsimony() ) {
155             System.out.println( "failed." );
156             return false;
157         }
158         System.out.println( "OK." );
159         return true;
160     }
161
162     private static boolean testBasicCharacterStateMatrix() {
163         try {
164             final CharacterStateMatrix<String> matrix_0 = new BasicCharacterStateMatrix<String>( 4, 8 );
165             final CharacterStateMatrix<String> matrix_00 = new BasicCharacterStateMatrix<String>( 4, 8 );
166             matrix_0.setIdentifier( 0, "A" );
167             matrix_0.setIdentifier( 1, "B" );
168             matrix_0.setIdentifier( 2, "C" );
169             matrix_0.setIdentifier( 3, "D" );
170             matrix_0.setCharacter( 0, "0" );
171             matrix_0.setCharacter( 1, "1" );
172             matrix_0.setCharacter( 2, "2" );
173             matrix_0.setCharacter( 3, "3" );
174             matrix_0.setCharacter( 4, "4" );
175             matrix_0.setCharacter( 5, "5" );
176             matrix_0.setCharacter( 6, "6" );
177             matrix_0.setCharacter( 7, "7" );
178             matrix_00.setIdentifier( 0, "A" );
179             matrix_00.setIdentifier( 1, "B" );
180             matrix_00.setIdentifier( 2, "C" );
181             matrix_00.setIdentifier( 3, "D" );
182             matrix_00.setCharacter( 3, "3" );
183             matrix_00.setCharacter( 4, "4" );
184             if ( !matrix_0.getCharacter( 1 ).equals( "1" ) ) {
185                 return false;
186             }
187             if ( !matrix_0.getIdentifier( 0 ).equals( "A" ) ) {
188                 return false;
189             }
190             matrix_0.setState( 0, 0, "00" );
191             matrix_00.setState( 0, 0, "00" );
192             if ( !matrix_0.getState( 0, 0 ).equals( "00" ) ) {
193                 return false;
194             }
195             matrix_0.setState( 0, 1, "01" );
196             matrix_00.setState( 0, 1, "01" );
197             if ( !matrix_0.getState( 0, 1 ).equals( "01" ) ) {
198                 return false;
199             }
200             matrix_0.setState( 1, 1, "11" );
201             matrix_00.setState( 1, 1, "11" );
202             if ( !matrix_0.getState( 1, 1 ).equals( "11" ) ) {
203                 return false;
204             }
205             matrix_0.setState( 1, 0, "10" );
206             matrix_00.setState( 1, 0, "10" );
207             if ( !matrix_0.getState( 1, 0 ).equals( "10" ) ) {
208                 return false;
209             }
210             matrix_0.setState( 1, 2, "12" );
211             matrix_00.setState( 1, 2, "12" );
212             if ( !matrix_0.getState( 1, 2 ).equals( "12" ) ) {
213                 return false;
214             }
215             matrix_0.setState( 3, 7, "37" );
216             matrix_00.setState( 3, 7, "37" );
217             if ( !matrix_0.getState( 3, 7 ).equals( "37" ) ) {
218                 return false;
219             }
220             matrix_0.setState( 2, 6, "26" );
221             matrix_00.setState( 2, 6, "26" );
222             if ( !matrix_0.getState( 2, 6 ).equals( "26" ) ) {
223                 return false;
224             }
225             matrix_0.setState( "D", "3", "33" );
226             matrix_00.setState( "D", "3", "33" );
227             if ( !matrix_0.getState( 3, 3 ).equals( "33" ) ) {
228                 return false;
229             }
230             if ( !matrix_0.getState( "D", "3" ).equals( "33" ) ) {
231                 return false;
232             }
233             matrix_0.setState( "C", "4", "24" );
234             matrix_00.setState( "C", "4", "24" );
235             if ( !matrix_0.getState( 2, 4 ).equals( "24" ) ) {
236                 return false;
237             }
238             if ( !matrix_0.getState( "C", "4" ).equals( "24" ) ) {
239                 return false;
240             }
241             if ( matrix_0.isEmpty() ) {
242                 return false;
243             }
244             if ( matrix_0.getNumberOfIdentifiers() != 4 ) {
245                 return false;
246             }
247             if ( matrix_0.getNumberOfCharacters() != 8 ) {
248                 return false;
249             }
250             if ( !matrix_0.equals( matrix_0 ) ) {
251                 return false;
252             }
253             if ( !matrix_0.equals( matrix_00 ) ) {
254                 return false;
255             }
256             matrix_00.setState( "C", "4", "123" );
257             if ( matrix_0.equals( matrix_00 ) ) {
258                 return false;
259             }
260             final Integer[][] ints = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
261             final CharacterStateMatrix<Integer> matrix_000 = new BasicCharacterStateMatrix<Integer>( ints );
262             matrix_000.toString();
263             if ( matrix_000.getNumberOfCharacters() != 4 ) {
264                 return false;
265             }
266             if ( matrix_000.getNumberOfIdentifiers() != 3 ) {
267                 return false;
268             }
269             if ( matrix_000.getState( 0, 1 ) != 2 ) {
270                 return false;
271             }
272             if ( matrix_000.getState( 2, 3 ) != 12 ) {
273                 return false;
274             }
275             final Integer[][] ints0 = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
276             final CharacterStateMatrix<Integer> matrix_0000 = new BasicCharacterStateMatrix<Integer>( ints0 );
277             if ( !matrix_000.equals( matrix_0000 ) ) {
278                 return false;
279             }
280             final Integer[][] ints00 = { { 1, 2, 3, -4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
281             final CharacterStateMatrix<Integer> matrix_00000 = new BasicCharacterStateMatrix<Integer>( ints00 );
282             if ( matrix_000.equals( matrix_00000 ) ) {
283                 return false;
284             }
285             final CharacterStateMatrix<String> clone0 = matrix_0.copy();
286             final CharacterStateMatrix<String> clone00 = matrix_00.copy();
287             if ( !clone0.equals( matrix_0 ) ) {
288                 return false;
289             }
290             if ( !clone00.equals( matrix_00 ) ) {
291                 return false;
292             }
293             if ( clone00.equals( clone0 ) ) {
294                 return false;
295             }
296             final CharacterStateMatrix<String> pivot0 = matrix_0.pivot();
297             final CharacterStateMatrix<String> pivot00 = matrix_00.pivot();
298             if ( !pivot0.getState( 1, 0 ).equals( "01" ) ) {
299                 return false;
300             }
301             if ( !pivot0.getState( 6, 2 ).equals( "26" ) ) {
302                 return false;
303             }
304             if ( !matrix_0.getState( 2, 6 ).equals( "26" ) ) {
305                 return false;
306             }
307             final CharacterStateMatrix<String> pivotpivot00 = pivot00.pivot();
308             if ( !pivotpivot00.equals( matrix_00 ) ) {
309                 return false;
310             }
311             final CharacterStateMatrix<BinaryStates> nex = new BasicCharacterStateMatrix<BinaryStates>( 4, 3 );
312             nex.setIdentifier( 0, "amphioxus" );
313             nex.setIdentifier( 1, "sponge" );
314             nex.setIdentifier( 2, "sea_anemone" );
315             nex.setIdentifier( 3, "cobra" );
316             nex.setCharacter( 0, "notch" );
317             nex.setCharacter( 1, "homeobox" );
318             nex.setCharacter( 2, "wnt" );
319             nex.setState( 0, 0, BinaryStates.ABSENT );
320             nex.setState( 0, 1, BinaryStates.ABSENT );
321             nex.setState( 0, 2, BinaryStates.ABSENT );
322             nex.setState( 1, 0, BinaryStates.PRESENT );
323             nex.setState( 1, 1, BinaryStates.PRESENT );
324             nex.setState( 1, 2, BinaryStates.ABSENT );
325             nex.setState( 2, 0, BinaryStates.PRESENT );
326             nex.setState( 2, 1, BinaryStates.PRESENT );
327             nex.setState( 2, 2, BinaryStates.PRESENT );
328             nex.setState( 3, 0, BinaryStates.PRESENT );
329             nex.setState( 3, 1, BinaryStates.ABSENT );
330             nex.setState( 3, 2, BinaryStates.ABSENT );
331             StringWriter w = new StringWriter();
332             nex.toWriter( w, CharacterStateMatrix.Format.NEXUS_BINARY );
333             //System.out.println( w.getBuffer().toString() );
334             w = new StringWriter();
335             nex.pivot().toWriter( w, CharacterStateMatrix.Format.NEXUS_BINARY );
336             //System.out.println( w.getBuffer().toString() );
337         }
338         catch ( final Exception e ) {
339             e.printStackTrace( System.out );
340             return false;
341         }
342         return true;
343     }
344
345     private static boolean testBasicSymmetricalDistanceMatrix() {
346         try {
347             final DistanceMatrix matrix_0 = new BasicSymmetricalDistanceMatrix( 4 );
348             matrix_0.setIdentifier( 0, "A" );
349             matrix_0.setIdentifier( 1, "B" );
350             matrix_0.setIdentifier( 2, "C" );
351             matrix_0.setIdentifier( 3, "0123456789012" );
352             matrix_0.setValue( 1, 0, 0.00001 );
353             matrix_0.setValue( 0, 2, 0.0000009 );
354             matrix_0.setValue( 3, 0, 3.0 );
355             matrix_0.setValue( 1, 2, 4.0 );
356             matrix_0.setValue( 3, 1, 5.0 );
357             matrix_0.setValue( 2, 3, 6.0 );
358             if ( !matrix_0.getIdentifier( 0 ).equals( "A" ) ) {
359                 return false;
360             }
361             if ( !matrix_0.getIdentifier( 1 ).equals( "B" ) ) {
362                 return false;
363             }
364             if ( !matrix_0.getIdentifier( 2 ).equals( "C" ) ) {
365                 return false;
366             }
367             if ( !matrix_0.getIdentifier( 3 ).equals( "0123456789012" ) ) {
368                 return false;
369             }
370             if ( matrix_0.getSize() != 4 ) {
371                 return false;
372             }
373             if ( !isEqual( matrix_0.getValue( 0, 0 ), 0.0 ) ) {
374                 return false;
375             }
376             if ( !isEqual( matrix_0.getValue( 3, 3 ), 0.0 ) ) {
377                 return false;
378             }
379             if ( !isEqual( matrix_0.getValue( 0, 1 ), 0.00001 ) ) {
380                 return false;
381             }
382             if ( !isEqual( matrix_0.getValue( 0, 2 ), 0.0000009 ) ) {
383                 return false;
384             }
385             if ( !isEqual( matrix_0.getValue( 0, 3 ), 3 ) ) {
386                 return false;
387             }
388             if ( !isEqual( matrix_0.getValue( 1, 0 ), 0.00001 ) ) {
389                 return false;
390             }
391             if ( !isEqual( matrix_0.getValue( 1, 2 ), 4 ) ) {
392                 return false;
393             }
394             if ( !isEqual( matrix_0.getValue( 1, 3 ), 5 ) ) {
395                 return false;
396             }
397             if ( !isEqual( matrix_0.getValue( 2, 0 ), 0.0000009 ) ) {
398                 return false;
399             }
400             if ( !isEqual( matrix_0.getValue( 2, 1 ), 4 ) ) {
401                 return false;
402             }
403             if ( !isEqual( matrix_0.getValue( 2, 3 ), 6 ) ) {
404                 return false;
405             }
406             if ( !isEqual( matrix_0.getValue( 3, 0 ), 3 ) ) {
407                 return false;
408             }
409             if ( !isEqual( matrix_0.getValue( 3, 1 ), 5 ) ) {
410                 return false;
411             }
412             if ( !isEqual( matrix_0.getValue( 3, 2 ), 6 ) ) {
413                 return false;
414             }
415             final StringBuffer matrix_0_phylip = new StringBuffer();
416             matrix_0_phylip.append( "    4" );
417             matrix_0_phylip.append( ForesterUtil.LINE_SEPARATOR );
418             matrix_0_phylip.append( "A           0.000000  0.000010  0.000001  3.000000" );
419             matrix_0_phylip.append( ForesterUtil.LINE_SEPARATOR );
420             matrix_0_phylip.append( "B           0.000010  0.000000  4.000000  5.000000" );
421             matrix_0_phylip.append( ForesterUtil.LINE_SEPARATOR );
422             matrix_0_phylip.append( "C           0.000001  4.000000  0.000000  6.000000" );
423             matrix_0_phylip.append( ForesterUtil.LINE_SEPARATOR );
424             matrix_0_phylip.append( "0123456789  3.000000  5.000000  6.000000  0.000000" );
425             if ( !matrix_0_phylip.toString()
426                     .equals( matrix_0.toStringBuffer( DistanceMatrix.Format.PHYLIP ).toString() ) ) {
427                 return false;
428             }
429         }
430         catch ( final Exception e ) {
431             e.printStackTrace( System.out );
432             return false;
433         }
434         return true;
435     }
436
437     private static boolean testDistanceCalculationMethods( final File test_dir ) {
438         try {
439             final Msa msa0 = GeneralMsaParser.parse( new FileInputStream( test_dir + ForesterUtil.FILE_SEPARATOR
440                                                                           + "bcl.aln" ) );
441             final BasicSymmetricalDistanceMatrix pwd0 = PairwiseDistanceCalculator.calcKimuraDistances( msa0 );
442             if ( pwd0.getSize() != 120 ) {
443                 return false;
444             }
445             for( int i = 0; i < pwd0.getSize(); ++i ) {
446                 if ( !isEqual( pwd0.getValue( i, i ), 0.0 ) ) {
447                     return false;
448                 }
449             }
450         }
451         catch ( final Exception e ) {
452             e.printStackTrace( System.out );
453             return false;
454         }
455         return true;
456     }
457
458     private static boolean testDolloParsimony() {
459         try {
460             final BinaryStates PRESENT = BinaryStates.PRESENT;
461             final BinaryStates ABSENT = BinaryStates.ABSENT;
462             final GainLossStates UNCHANGED_PRESENT = GainLossStates.UNCHANGED_PRESENT;
463             final DolloParsimony dollo1 = DolloParsimony.createInstance();
464             final PhylogenyFactory factory1 = ParserBasedPhylogenyFactory.getInstance();
465             final String p1_str = "((((((a,b)ab,c)ac,d)ad,(e,f)ef)af,(g,h)gh)ah,i)r";
466             final Phylogeny p1 = factory1.create( p1_str, new NHXParser() )[ 0 ];
467             CharacterStateMatrix<CharacterStateMatrix.BinaryStates> m1 = new BasicCharacterStateMatrix<CharacterStateMatrix.BinaryStates>( 9,
468                     1 );
469             m1.setIdentifier( 0, "a" );
470             m1.setIdentifier( 1, "b" );
471             m1.setIdentifier( 2, "c" );
472             m1.setIdentifier( 3, "d" );
473             m1.setIdentifier( 4, "e" );
474             m1.setIdentifier( 5, "f" );
475             m1.setIdentifier( 6, "g" );
476             m1.setIdentifier( 7, "h" );
477             m1.setIdentifier( 8, "i" );
478             m1.setCharacter( 0, "0" );
479             m1.setState( "a", "0", PRESENT );
480             m1.setState( "b", "0", ABSENT );
481             m1.setState( "c", "0", PRESENT );
482             m1.setState( "d", "0", ABSENT );
483             m1.setState( "e", "0", ABSENT );
484             m1.setState( "f", "0", ABSENT );
485             m1.setState( "g", "0", ABSENT );
486             m1.setState( "h", "0", ABSENT );
487             m1.setState( "i", "0", ABSENT );
488             dollo1.execute( p1, m1 );
489             if ( dollo1.getTotalGains() != 1 ) {
490                 return false;
491             }
492             if ( dollo1.getTotalLosses() != 1 ) {
493                 return false;
494             }
495             if ( dollo1.getTotalUnchanged() != 15 ) {
496                 return false;
497             }
498             m1.setState( "b", "0", PRESENT );
499             dollo1.execute( p1, m1 );
500             if ( dollo1.getTotalGains() != 1 ) {
501                 return false;
502             }
503             if ( dollo1.getTotalLosses() != 0 ) {
504                 return false;
505             }
506             if ( dollo1.getTotalUnchanged() != 16 ) {
507                 return false;
508             }
509             m1.setState( "b", "0", ABSENT );
510             m1.setState( "e", "0", PRESENT );
511             dollo1.execute( p1, m1 );
512             if ( dollo1.getTotalGains() != 1 ) {
513                 return false;
514             }
515             if ( dollo1.getTotalLosses() != 3 ) {
516                 return false;
517             }
518             if ( dollo1.getTotalUnchanged() != 13 ) {
519                 return false;
520             }
521             m1.setState( "a", "0", ABSENT );
522             m1.setState( "c", "0", ABSENT );
523             m1.setState( "g", "0", PRESENT );
524             dollo1.setReturnInternalStates( true );
525             dollo1.setReturnGainLossMatrix( true );
526             dollo1.execute( p1, m1 );
527             if ( dollo1.getTotalGains() != 1 ) {
528                 return false;
529             }
530             if ( dollo1.getTotalLosses() != 3 ) {
531                 return false;
532             }
533             if ( dollo1.getTotalUnchanged() != 13 ) {
534                 return false;
535             }
536             final DolloParsimony dollo2 = DolloParsimony.createInstance();
537             final PhylogenyFactory factory2 = ParserBasedPhylogenyFactory.getInstance();
538             final String p2_str = "((((((a,b)ab,c)ac,d)ad,(e,f)ef)af,(g,h,i)gi)ai,((j,k,l)jl,(m,n,o)mo,(p,q,r)pr)jr)root";
539             final Phylogeny p2 = factory2.create( p2_str, new NHXParser() )[ 0 ];
540             final CharacterStateMatrix<CharacterStateMatrix.BinaryStates> m2 = new BasicCharacterStateMatrix<CharacterStateMatrix.BinaryStates>( 18,
541                     4 );
542             m2.setIdentifier( 0, "a" );
543             m2.setIdentifier( 1, "b" );
544             m2.setIdentifier( 2, "c" );
545             m2.setIdentifier( 3, "d" );
546             m2.setIdentifier( 4, "e" );
547             m2.setIdentifier( 5, "f" );
548             m2.setIdentifier( 6, "g" );
549             m2.setIdentifier( 7, "h" );
550             m2.setIdentifier( 8, "i" );
551             m2.setIdentifier( 9, "j" );
552             m2.setIdentifier( 10, "k" );
553             m2.setIdentifier( 11, "l" );
554             m2.setIdentifier( 12, "m" );
555             m2.setIdentifier( 13, "n" );
556             m2.setIdentifier( 14, "o" );
557             m2.setIdentifier( 15, "p" );
558             m2.setIdentifier( 16, "q" );
559             m2.setIdentifier( 17, "r" );
560             m2.setCharacter( 0, "0" );
561             m2.setCharacter( 1, "1" );
562             m2.setCharacter( 2, "2" );
563             m2.setCharacter( 3, "3" );
564             m2.setState( "a", "0", PRESENT );
565             m2.setState( "b", "0", ABSENT );
566             m2.setState( "c", "0", PRESENT );
567             m2.setState( "d", "0", ABSENT );
568             m2.setState( "e", "0", ABSENT );
569             m2.setState( "f", "0", ABSENT );
570             m2.setState( "g", "0", ABSENT );
571             m2.setState( "h", "0", ABSENT );
572             m2.setState( "i", "0", ABSENT );
573             m2.setState( "j", "0", ABSENT );
574             m2.setState( "k", "0", ABSENT );
575             m2.setState( "l", "0", ABSENT );
576             m2.setState( "m", "0", ABSENT );
577             m2.setState( "n", "0", ABSENT );
578             m2.setState( "o", "0", ABSENT );
579             m2.setState( "p", "0", ABSENT );
580             m2.setState( "q", "0", ABSENT );
581             m2.setState( "r", "0", ABSENT );
582             m2.setState( "a", "1", PRESENT );
583             m2.setState( "b", "1", ABSENT );
584             m2.setState( "c", "1", PRESENT );
585             m2.setState( "d", "1", ABSENT );
586             m2.setState( "e", "1", ABSENT );
587             m2.setState( "f", "1", ABSENT );
588             m2.setState( "g", "1", PRESENT );
589             m2.setState( "h", "1", ABSENT );
590             m2.setState( "i", "1", ABSENT );
591             m2.setState( "j", "1", PRESENT );
592             m2.setState( "k", "1", ABSENT );
593             m2.setState( "l", "1", ABSENT );
594             m2.setState( "m", "1", PRESENT );
595             m2.setState( "n", "1", ABSENT );
596             m2.setState( "o", "1", ABSENT );
597             m2.setState( "p", "1", ABSENT );
598             m2.setState( "q", "1", ABSENT );
599             m2.setState( "r", "1", ABSENT );
600             m2.setState( "a", "2", ABSENT );
601             m2.setState( "b", "2", ABSENT );
602             m2.setState( "c", "2", ABSENT );
603             m2.setState( "d", "2", ABSENT );
604             m2.setState( "e", "2", ABSENT );
605             m2.setState( "f", "2", ABSENT );
606             m2.setState( "g", "2", ABSENT );
607             m2.setState( "h", "2", ABSENT );
608             m2.setState( "i", "2", ABSENT );
609             m2.setState( "j", "2", PRESENT );
610             m2.setState( "k", "2", ABSENT );
611             m2.setState( "l", "2", ABSENT );
612             m2.setState( "m", "2", PRESENT );
613             m2.setState( "n", "2", ABSENT );
614             m2.setState( "o", "2", ABSENT );
615             m2.setState( "p", "2", PRESENT );
616             m2.setState( "q", "2", ABSENT );
617             m2.setState( "r", "2", ABSENT );
618             m2.setState( "a", "3", ABSENT );
619             m2.setState( "b", "3", ABSENT );
620             m2.setState( "c", "3", PRESENT );
621             m2.setState( "d", "3", ABSENT );
622             m2.setState( "e", "3", ABSENT );
623             m2.setState( "f", "3", ABSENT );
624             m2.setState( "g", "3", PRESENT );
625             m2.setState( "h", "3", ABSENT );
626             m2.setState( "i", "3", ABSENT );
627             m2.setState( "j", "3", ABSENT );
628             m2.setState( "k", "3", ABSENT );
629             m2.setState( "l", "3", ABSENT );
630             m2.setState( "m", "3", ABSENT );
631             m2.setState( "n", "3", ABSENT );
632             m2.setState( "o", "3", ABSENT );
633             m2.setState( "p", "3", ABSENT );
634             m2.setState( "q", "3", ABSENT );
635             m2.setState( "r", "3", ABSENT );
636             dollo2.setReturnInternalStates( true );
637             dollo2.setReturnGainLossMatrix( true );
638             dollo2.execute( p2, m2 );
639             final CharacterStateMatrix<BinaryStates> i_m = dollo2.getInternalStatesMatrix();
640             final CharacterStateMatrix<GainLossStates> gl_m = dollo2.getGainLossMatrix();
641             if ( dollo2.getTotalGains() != 3 ) {
642                 return false;
643             }
644             if ( dollo2.getTotalLosses() != 22 ) {
645                 return false;
646             }
647             if ( dollo2.getTotalUnchanged() != 95 ) {
648                 return false;
649             }
650             if ( i_m.getState( "ab", "0" ) != PRESENT ) {
651                 return false;
652             }
653             if ( i_m.getState( "ac", "0" ) != PRESENT ) {
654                 return false;
655             }
656             if ( i_m.getState( "ad", "0" ) != ABSENT ) {
657                 return false;
658             }
659             if ( i_m.getState( "af", "0" ) != ABSENT ) {
660                 return false;
661             }
662             if ( i_m.getState( "ef", "0" ) != ABSENT ) {
663                 return false;
664             }
665             if ( i_m.getState( "ai", "0" ) != ABSENT ) {
666                 return false;
667             }
668             if ( i_m.getState( "gi", "0" ) != ABSENT ) {
669                 return false;
670             }
671             if ( i_m.getState( "jl", "0" ) != ABSENT ) {
672                 return false;
673             }
674             if ( i_m.getState( "mo", "0" ) != ABSENT ) {
675                 return false;
676             }
677             if ( i_m.getState( "pr", "0" ) != ABSENT ) {
678                 return false;
679             }
680             if ( i_m.getState( "jr", "0" ) != ABSENT ) {
681                 return false;
682             }
683             if ( i_m.getState( "root", "0" ) != ABSENT ) {
684                 return false;
685             }
686             if ( i_m.getState( "ab", "1" ) != PRESENT ) {
687                 return false;
688             }
689             if ( i_m.getState( "ac", "1" ) != PRESENT ) {
690                 return false;
691             }
692             if ( i_m.getState( "ad", "1" ) != PRESENT ) {
693                 return false;
694             }
695             if ( i_m.getState( "af", "1" ) != PRESENT ) {
696                 return false;
697             }
698             if ( i_m.getState( "ef", "1" ) != ABSENT ) {
699                 return false;
700             }
701             if ( i_m.getState( "ai", "1" ) != PRESENT ) {
702                 return false;
703             }
704             if ( i_m.getState( "gi", "1" ) != PRESENT ) {
705                 return false;
706             }
707             if ( i_m.getState( "jl", "1" ) != PRESENT ) {
708                 return false;
709             }
710             if ( i_m.getState( "mo", "1" ) != PRESENT ) {
711                 return false;
712             }
713             if ( i_m.getState( "pr", "1" ) != ABSENT ) {
714                 return false;
715             }
716             if ( i_m.getState( "jr", "1" ) != PRESENT ) {
717                 return false;
718             }
719             if ( i_m.getState( "root", "1" ) != PRESENT ) {
720                 return false;
721             }
722             if ( i_m.getState( "ab", "2" ) != ABSENT ) {
723                 return false;
724             }
725             if ( i_m.getState( "ac", "2" ) != ABSENT ) {
726                 return false;
727             }
728             if ( i_m.getState( "ad", "2" ) != ABSENT ) {
729                 return false;
730             }
731             if ( i_m.getState( "af", "2" ) != ABSENT ) {
732                 return false;
733             }
734             if ( i_m.getState( "ef", "2" ) != ABSENT ) {
735                 return false;
736             }
737             if ( i_m.getState( "ai", "2" ) != ABSENT ) {
738                 return false;
739             }
740             if ( i_m.getState( "gi", "2" ) != ABSENT ) {
741                 return false;
742             }
743             if ( i_m.getState( "jl", "2" ) != PRESENT ) {
744                 return false;
745             }
746             if ( i_m.getState( "mo", "2" ) != PRESENT ) {
747                 return false;
748             }
749             if ( i_m.getState( "pr", "2" ) != PRESENT ) {
750                 return false;
751             }
752             if ( i_m.getState( "jr", "2" ) != PRESENT ) {
753                 return false;
754             }
755             if ( i_m.getState( "root", "2" ) != ABSENT ) {
756                 return false;
757             }
758             if ( i_m.getState( "ab", "3" ) != ABSENT ) {
759                 return false;
760             }
761             if ( i_m.getState( "ac", "3" ) != PRESENT ) {
762                 return false;
763             }
764             if ( i_m.getState( "ad", "3" ) != PRESENT ) {
765                 return false;
766             }
767             if ( i_m.getState( "af", "3" ) != PRESENT ) {
768                 return false;
769             }
770             if ( i_m.getState( "ef", "3" ) != ABSENT ) {
771                 return false;
772             }
773             if ( i_m.getState( "ai", "3" ) != PRESENT ) {
774                 return false;
775             }
776             if ( i_m.getState( "gi", "3" ) != PRESENT ) {
777                 return false;
778             }
779             if ( i_m.getState( "jl", "3" ) != ABSENT ) {
780                 return false;
781             }
782             if ( i_m.getState( "mo", "3" ) != ABSENT ) {
783                 return false;
784             }
785             if ( i_m.getState( "pr", "3" ) != ABSENT ) {
786                 return false;
787             }
788             if ( i_m.getState( "jr", "3" ) != ABSENT ) {
789                 return false;
790             }
791             if ( i_m.getState( "root", "3" ) != ABSENT ) {
792                 return false;
793             }
794             if ( gl_m.getState( "a", "0" ) != UNCHANGED_PRESENT ) {
795                 return false;
796             }
797             final DolloParsimony dollo9 = DolloParsimony.createInstance();
798             final PhylogenyFactory factory9 = ParserBasedPhylogenyFactory.getInstance();
799             final String p9_str = "((((((a,b)ab,c)ac,d)ad,(e,f)ef)af,(g,h)gh)ah,i)r";
800             final Phylogeny p9 = factory9.create( p9_str, new NHXParser() )[ 0 ];
801             m1 = new BasicCharacterStateMatrix<CharacterStateMatrix.BinaryStates>( 9, 3 );
802             m1.setIdentifier( 0, "a" );
803             m1.setIdentifier( 1, "b" );
804             m1.setIdentifier( 2, "c" );
805             m1.setIdentifier( 3, "d" );
806             m1.setIdentifier( 4, "e" );
807             m1.setIdentifier( 5, "f" );
808             m1.setIdentifier( 6, "g" );
809             m1.setIdentifier( 7, "h" );
810             m1.setIdentifier( 8, "i" );
811             m1.setState( 0, 0, PRESENT );
812             m1.setState( 1, 0, ABSENT );
813             m1.setState( 2, 0, PRESENT );
814             m1.setState( 3, 0, ABSENT );
815             m1.setState( 4, 0, ABSENT );
816             m1.setState( 5, 0, ABSENT );
817             m1.setState( 6, 0, ABSENT );
818             m1.setState( 7, 0, ABSENT );
819             m1.setState( 8, 0, ABSENT );
820             m1.setState( 0, 1, PRESENT );
821             m1.setState( 1, 1, PRESENT );
822             m1.setState( 2, 1, PRESENT );
823             m1.setState( 3, 1, PRESENT );
824             m1.setState( 4, 1, ABSENT );
825             m1.setState( 5, 1, ABSENT );
826             m1.setState( 6, 1, ABSENT );
827             m1.setState( 7, 1, ABSENT );
828             m1.setState( 8, 1, ABSENT );
829             m1.setState( 0, 2, PRESENT );
830             m1.setState( 1, 2, ABSENT );
831             m1.setState( 2, 2, ABSENT );
832             m1.setState( 3, 2, ABSENT );
833             m1.setState( 4, 2, ABSENT );
834             m1.setState( 5, 2, ABSENT );
835             m1.setState( 6, 2, ABSENT );
836             m1.setState( 7, 2, PRESENT );
837             m1.setState( 8, 2, ABSENT );
838             dollo9.execute( p9, m1 );
839             if ( dollo9.getTotalGains() != 3 ) {
840                 return false;
841             }
842             if ( dollo9.getTotalLosses() != 6 ) {
843                 return false;
844             }
845             final DolloParsimony dollo10 = DolloParsimony.createInstance();
846             final PhylogenyFactory factory10 = ParserBasedPhylogenyFactory.getInstance();
847             final String p10_str = "((((((a,b)ab,c)ac,d)ad,(e,f)ef)af,(g,h)gh)ah,i)r";
848             final Phylogeny p10 = factory10.create( p10_str, new NHXParser() )[ 0 ];
849             final CharacterStateMatrix<CharacterStateMatrix.BinaryStates> m10 = new BasicCharacterStateMatrix<CharacterStateMatrix.BinaryStates>( 9,
850                     1 );
851             m10.setIdentifier( 0, "a" );
852             m10.setIdentifier( 1, "b" );
853             m10.setIdentifier( 2, "c" );
854             m10.setIdentifier( 3, "d" );
855             m10.setIdentifier( 4, "e" );
856             m10.setIdentifier( 5, "f" );
857             m10.setIdentifier( 6, "g" );
858             m10.setIdentifier( 7, "h" );
859             m10.setIdentifier( 8, "i" );
860             m10.setState( 0, 0, PRESENT );
861             m10.setState( 1, 0, ABSENT );
862             m10.setState( 2, 0, PRESENT );
863             m10.setState( 3, 0, ABSENT );
864             m10.setState( 4, 0, ABSENT );
865             m10.setState( 5, 0, ABSENT );
866             m10.setState( 6, 0, ABSENT );
867             m10.setState( 7, 0, ABSENT );
868             m10.setState( 8, 0, ABSENT );
869             dollo10.execute( p10, m10 );
870             if ( dollo10.getTotalGains() != 1 ) {
871                 return false;
872             }
873             if ( dollo10.getTotalLosses() != 1 ) {
874                 return false;
875             }
876         }
877         catch ( final Exception e ) {
878             e.printStackTrace( System.out );
879             return false;
880         }
881         return true;
882     }
883
884     private static boolean testDolloParsimonyOnNonBinaryTree() {
885         try {
886             final BinaryStates PRESENT = BinaryStates.PRESENT;
887             final BinaryStates ABSENT = BinaryStates.ABSENT;
888             final DolloParsimony dollo1 = DolloParsimony.createInstance();
889             final PhylogenyFactory factory1 = ParserBasedPhylogenyFactory.getInstance();
890             final String p1_str = "((((((a,b,y)aby,c)ac,d)ad,(e,f)ef)af,(g,h)gh)ah,i)r";
891             final Phylogeny p1 = factory1.create( p1_str, new NHXParser() )[ 0 ];
892             final CharacterStateMatrix<CharacterStateMatrix.BinaryStates> m1 = new BasicCharacterStateMatrix<CharacterStateMatrix.BinaryStates>( 10,
893                     1 );
894             m1.setIdentifier( 0, "a" );
895             m1.setIdentifier( 1, "b" );
896             m1.setIdentifier( 2, "y" );
897             m1.setIdentifier( 3, "c" );
898             m1.setIdentifier( 4, "d" );
899             m1.setIdentifier( 5, "e" );
900             m1.setIdentifier( 6, "f" );
901             m1.setIdentifier( 7, "g" );
902             m1.setIdentifier( 8, "h" );
903             m1.setIdentifier( 9, "i" );
904             m1.setCharacter( 0, "0" );
905             m1.setState( "a", "0", PRESENT );
906             m1.setState( "b", "0", ABSENT );
907             m1.setState( "y", "0", PRESENT );
908             m1.setState( "c", "0", PRESENT );
909             m1.setState( "d", "0", ABSENT );
910             m1.setState( "e", "0", ABSENT );
911             m1.setState( "f", "0", ABSENT );
912             m1.setState( "g", "0", ABSENT );
913             m1.setState( "h", "0", ABSENT );
914             m1.setState( "i", "0", ABSENT );
915             dollo1.execute( p1, m1 );
916             if ( dollo1.getTotalGains() != 1 ) {
917                 return false;
918             }
919             if ( dollo1.getTotalLosses() != 1 ) {
920                 return false;
921             }
922             if ( dollo1.getTotalUnchanged() != 16 ) {
923                 return false;
924             }
925             m1.setState( "b", "0", PRESENT );
926             dollo1.execute( p1, m1 );
927             if ( dollo1.getTotalGains() != 1 ) {
928                 return false;
929             }
930             if ( dollo1.getTotalLosses() != 0 ) {
931                 return false;
932             }
933             if ( dollo1.getTotalUnchanged() != 17 ) {
934                 return false;
935             }
936             m1.setState( "a", "0", ABSENT );
937             m1.setState( "b", "0", ABSENT );
938             dollo1.execute( p1, m1 );
939             if ( dollo1.getTotalGains() != 1 ) {
940                 return false;
941             }
942             if ( dollo1.getTotalLosses() != 2 ) {
943                 return false;
944             }
945             if ( dollo1.getTotalUnchanged() != 15 ) {
946                 return false;
947             }
948             m1.setState( "y", "0", ABSENT );
949             dollo1.execute( p1, m1 );
950             if ( dollo1.getTotalGains() != 1 ) {
951                 return false;
952             }
953             if ( dollo1.getTotalLosses() != 0 ) {
954                 return false;
955             }
956             if ( dollo1.getTotalUnchanged() != 17 ) {
957                 return false;
958             }
959             final DolloParsimony dollo2 = DolloParsimony.createInstance();
960             final PhylogenyFactory factory2 = ParserBasedPhylogenyFactory.getInstance();
961             final String p2_str = "((((((a,b,y)aby,c,d)cad,e,f)af,(g,h)gh)ah,i))r";
962             final Phylogeny p2 = factory2.create( p2_str, new NHXParser() )[ 0 ];
963             final CharacterStateMatrix<CharacterStateMatrix.BinaryStates> m2 = new BasicCharacterStateMatrix<CharacterStateMatrix.BinaryStates>( 10,
964                     1 );
965             m2.setIdentifier( 0, "a" );
966             m2.setIdentifier( 1, "b" );
967             m2.setIdentifier( 2, "y" );
968             m2.setIdentifier( 3, "c" );
969             m2.setIdentifier( 4, "d" );
970             m2.setIdentifier( 5, "e" );
971             m2.setIdentifier( 6, "f" );
972             m2.setIdentifier( 7, "g" );
973             m2.setIdentifier( 8, "h" );
974             m2.setIdentifier( 9, "i" );
975             m2.setCharacter( 0, "0" );
976             m2.setState( "a", "0", PRESENT );
977             m2.setState( "b", "0", ABSENT );
978             m2.setState( "y", "0", PRESENT );
979             m2.setState( "c", "0", PRESENT );
980             m2.setState( "d", "0", ABSENT );
981             m2.setState( "e", "0", ABSENT );
982             m2.setState( "f", "0", ABSENT );
983             m2.setState( "g", "0", ABSENT );
984             m2.setState( "h", "0", ABSENT );
985             m2.setState( "i", "0", ABSENT );
986             dollo2.setReturnInternalStates( true );
987             dollo2.execute( p2, m2 );
988             CharacterStateMatrix<BinaryStates> i_m2 = dollo2.getInternalStatesMatrix();
989             if ( i_m2.getState( "aby", "0" ) != PRESENT ) {
990                 return false;
991             }
992             if ( i_m2.getState( "cad", "0" ) != PRESENT ) {
993                 return false;
994             }
995             if ( i_m2.getState( "af", "0" ) != ABSENT ) {
996                 return false;
997             }
998             if ( i_m2.getState( "gh", "0" ) != ABSENT ) {
999                 return false;
1000             }
1001             if ( i_m2.getState( "ah", "0" ) != ABSENT ) {
1002                 return false;
1003             }
1004             if ( i_m2.getState( "r", "0" ) != ABSENT ) {
1005                 return false;
1006             }
1007             if ( dollo2.getTotalGains() != 1 ) {
1008                 return false;
1009             }
1010             if ( dollo2.getTotalLosses() != 2 ) {
1011                 return false;
1012             }
1013             if ( dollo2.getTotalUnchanged() != 14 ) {
1014                 return false;
1015             }
1016             m2.setState( "b", "0", PRESENT );
1017             dollo2.execute( p2, m2 );
1018             if ( dollo2.getTotalGains() != 1 ) {
1019                 return false;
1020             }
1021             if ( dollo2.getTotalLosses() != 1 ) {
1022                 return false;
1023             }
1024             if ( dollo2.getTotalUnchanged() != 15 ) {
1025                 return false;
1026             }
1027             m2.setState( "a", "0", ABSENT );
1028             m2.setState( "b", "0", ABSENT );
1029             dollo2.execute( p2, m2 );
1030             if ( dollo2.getTotalGains() != 1 ) {
1031                 return false;
1032             }
1033             if ( dollo2.getTotalLosses() != 3 ) {
1034                 return false;
1035             }
1036             if ( dollo2.getTotalUnchanged() != 13 ) {
1037                 return false;
1038             }
1039             m2.setState( "y", "0", ABSENT );
1040             dollo2.execute( p2, m2 );
1041             if ( dollo2.getTotalGains() != 1 ) {
1042                 return false;
1043             }
1044             if ( dollo2.getTotalLosses() != 0 ) {
1045                 return false;
1046             }
1047             if ( dollo2.getTotalUnchanged() != 16 ) {
1048                 return false;
1049             }
1050             m2.setState( "c", "0", ABSENT );
1051             dollo2.execute( p2, m2 );
1052             if ( dollo2.getTotalGains() != 0 ) {
1053                 return false;
1054             }
1055             if ( dollo2.getTotalLosses() != 0 ) {
1056                 return false;
1057             }
1058             if ( dollo2.getTotalUnchanged() != 17 ) {
1059                 return false;
1060             }
1061             m2.setState( "y", "0", PRESENT );
1062             m2.setState( "e", "0", PRESENT );
1063             dollo2.execute( p2, m2 );
1064             if ( dollo2.getTotalGains() != 1 ) {
1065                 return false;
1066             }
1067             if ( dollo2.getTotalLosses() != 5 ) {
1068                 return false;
1069             }
1070             if ( dollo2.getTotalUnchanged() != 11 ) {
1071                 return false;
1072             }
1073             i_m2 = dollo2.getInternalStatesMatrix();
1074             if ( i_m2.getState( "aby", "0" ) != PRESENT ) {
1075                 return false;
1076             }
1077             if ( i_m2.getState( "cad", "0" ) != PRESENT ) {
1078                 return false;
1079             }
1080             if ( i_m2.getState( "af", "0" ) != PRESENT ) {
1081                 return false;
1082             }
1083             if ( i_m2.getState( "gh", "0" ) != ABSENT ) {
1084                 return false;
1085             }
1086             if ( i_m2.getState( "ah", "0" ) != ABSENT ) {
1087                 return false;
1088             }
1089             if ( i_m2.getState( "r", "0" ) != ABSENT ) {
1090                 return false;
1091             }
1092         }
1093         catch ( final Exception e ) {
1094             e.printStackTrace( System.out );
1095             return false;
1096         }
1097         return true;
1098     }
1099
1100     private static boolean testFitchParsimony() {
1101         try {
1102             final BinaryStates PRESENT = BinaryStates.PRESENT;
1103             final BinaryStates ABSENT = BinaryStates.ABSENT;
1104             final GainLossStates GAIN = GainLossStates.GAIN;
1105             final GainLossStates LOSS = GainLossStates.LOSS;
1106             final GainLossStates UNCHANGED_PRESENT = GainLossStates.UNCHANGED_PRESENT;
1107             final GainLossStates UNCHANGED_ABSENT = GainLossStates.UNCHANGED_ABSENT;
1108             final FitchParsimony<String> fitch1 = new FitchParsimony<String>();
1109             final PhylogenyFactory factory1 = ParserBasedPhylogenyFactory.getInstance();
1110             final String p1_str = "((((((a,b)ab,c)ac,d)ad,(e,f)ef)af,(g,h,i)gi)ai,((j,k,l)jl,(m,n,o)mo,(p,q,r)pr)jr)root";
1111             final Phylogeny p1 = factory1.create( p1_str, new NHXParser() )[ 0 ];
1112             final CharacterStateMatrix<String> m1 = new BasicCharacterStateMatrix<String>( 18, 1 );
1113             m1.setIdentifier( 0, "a" );
1114             m1.setIdentifier( 1, "b" );
1115             m1.setIdentifier( 2, "c" );
1116             m1.setIdentifier( 3, "d" );
1117             m1.setIdentifier( 4, "e" );
1118             m1.setIdentifier( 5, "f" );
1119             m1.setIdentifier( 6, "g" );
1120             m1.setIdentifier( 7, "h" );
1121             m1.setIdentifier( 8, "i" );
1122             m1.setIdentifier( 9, "j" );
1123             m1.setIdentifier( 10, "k" );
1124             m1.setIdentifier( 11, "l" );
1125             m1.setIdentifier( 12, "m" );
1126             m1.setIdentifier( 13, "n" );
1127             m1.setIdentifier( 14, "o" );
1128             m1.setIdentifier( 15, "p" );
1129             m1.setIdentifier( 16, "q" );
1130             m1.setIdentifier( 17, "r" );
1131             m1.setCharacter( 0, "0" );
1132             m1.setState( "a", "0", "A" );
1133             m1.setState( "b", "0", "A" );
1134             m1.setState( "c", "0", "B" );
1135             m1.setState( "d", "0", "C" );
1136             m1.setState( "e", "0", "D" );
1137             m1.setState( "f", "0", "A" );
1138             m1.setState( "g", "0", "A" );
1139             m1.setState( "h", "0", "B" );
1140             m1.setState( "i", "0", "C" );
1141             m1.setState( "j", "0", "A" );
1142             m1.setState( "k", "0", "B" );
1143             m1.setState( "l", "0", "C" );
1144             m1.setState( "m", "0", "B" );
1145             m1.setState( "n", "0", "B" );
1146             m1.setState( "o", "0", "B" );
1147             m1.setState( "p", "0", "A" );
1148             m1.setState( "q", "0", "C" );
1149             m1.setState( "r", "0", "D" );
1150             fitch1.setReturnInternalStates( true );
1151             fitch1.setReturnGainLossMatrix( false );
1152             fitch1.setRandomize( false );
1153             fitch1.execute( p1, m1 );
1154             final CharacterStateMatrix<String> i_m = fitch1.getInternalStatesMatrix();
1155             final CharacterStateMatrix<List<String>> i_m_all = fitch1.getInternalStatesMatrixPriorToTraceback();
1156             if ( fitch1.getCost() != 10 ) {
1157                 return false;
1158             }
1159             if ( !i_m.getState( "ab", "0" ).equals( "A" ) ) {
1160                 return false;
1161             }
1162             if ( !i_m.getState( "ac", "0" ).equals( "A" ) ) {
1163                 return false;
1164             }
1165             if ( !i_m.getState( "ad", "0" ).equals( "A" ) ) {
1166                 return false;
1167             }
1168             if ( !i_m.getState( "ef", "0" ).equals( "A" ) ) {
1169                 return false;
1170             }
1171             if ( !i_m.getState( "ai", "0" ).equals( "A" ) ) {
1172                 return false;
1173             }
1174             if ( !i_m.getState( "gi", "0" ).equals( "A" ) ) {
1175                 return false;
1176             }
1177             if ( !i_m.getState( "jl", "0" ).equals( "A" ) ) {
1178                 return false;
1179             }
1180             if ( !i_m.getState( "mo", "0" ).equals( "B" ) ) {
1181                 return false;
1182             }
1183             if ( !i_m.getState( "pr", "0" ).equals( "A" ) ) {
1184                 return false;
1185             }
1186             if ( i_m_all.getState( "ab", "0" ).size() != 1 ) {
1187                 return false;
1188             }
1189             if ( !i_m_all.getState( "ab", "0" ).contains( "A" ) ) {
1190                 return false;
1191             }
1192             if ( i_m_all.getState( "ac", "0" ).size() != 2 ) {
1193                 return false;
1194             }
1195             if ( !i_m_all.getState( "ac", "0" ).contains( "A" ) ) {
1196                 return false;
1197             }
1198             if ( !i_m_all.getState( "ac", "0" ).contains( "B" ) ) {
1199                 return false;
1200             }
1201             if ( i_m_all.getState( "ad", "0" ).size() != 3 ) {
1202                 return false;
1203             }
1204             if ( !i_m_all.getState( "ad", "0" ).contains( "A" ) ) {
1205                 return false;
1206             }
1207             if ( !i_m_all.getState( "ad", "0" ).contains( "B" ) ) {
1208                 return false;
1209             }
1210             if ( !i_m_all.getState( "ad", "0" ).contains( "C" ) ) {
1211                 return false;
1212             }
1213             if ( i_m_all.getState( "af", "0" ).size() != 1 ) {
1214                 return false;
1215             }
1216             if ( !i_m_all.getState( "af", "0" ).contains( "A" ) ) {
1217                 return false;
1218             }
1219             if ( i_m_all.getState( "ef", "0" ).size() != 2 ) {
1220                 return false;
1221             }
1222             if ( !i_m_all.getState( "ef", "0" ).contains( "A" ) ) {
1223                 return false;
1224             }
1225             if ( !i_m_all.getState( "ef", "0" ).contains( "D" ) ) {
1226                 return false;
1227             }
1228             if ( i_m_all.getState( "gi", "0" ).size() != 3 ) {
1229                 return false;
1230             }
1231             if ( !i_m_all.getState( "gi", "0" ).contains( "A" ) ) {
1232                 return false;
1233             }
1234             if ( !i_m_all.getState( "gi", "0" ).contains( "B" ) ) {
1235                 return false;
1236             }
1237             if ( !i_m_all.getState( "gi", "0" ).contains( "C" ) ) {
1238                 return false;
1239             }
1240             if ( i_m_all.getState( "ai", "0" ).size() != 1 ) {
1241                 return false;
1242             }
1243             if ( !i_m_all.getState( "ai", "0" ).contains( "A" ) ) {
1244                 return false;
1245             }
1246             if ( i_m_all.getState( "jl", "0" ).size() != 3 ) {
1247                 return false;
1248             }
1249             if ( !i_m_all.getState( "jl", "0" ).contains( "A" ) ) {
1250                 return false;
1251             }
1252             if ( !i_m_all.getState( "jl", "0" ).contains( "B" ) ) {
1253                 return false;
1254             }
1255             if ( !i_m_all.getState( "jl", "0" ).contains( "C" ) ) {
1256                 return false;
1257             }
1258             if ( i_m_all.getState( "mo", "0" ).size() != 1 ) {
1259                 return false;
1260             }
1261             if ( !i_m_all.getState( "mo", "0" ).contains( "B" ) ) {
1262                 return false;
1263             }
1264             if ( i_m_all.getState( "pr", "0" ).size() != 3 ) {
1265                 return false;
1266             }
1267             if ( !i_m_all.getState( "pr", "0" ).contains( "A" ) ) {
1268                 return false;
1269             }
1270             if ( !i_m_all.getState( "pr", "0" ).contains( "C" ) ) {
1271                 return false;
1272             }
1273             if ( !i_m_all.getState( "pr", "0" ).contains( "D" ) ) {
1274                 return false;
1275             }
1276             if ( i_m_all.getState( "jr", "0" ).size() != 4 ) {
1277                 return false;
1278             }
1279             if ( !i_m_all.getState( "jr", "0" ).contains( "A" ) ) {
1280                 return false;
1281             }
1282             if ( !i_m_all.getState( "jr", "0" ).contains( "B" ) ) {
1283                 return false;
1284             }
1285             if ( !i_m_all.getState( "jr", "0" ).contains( "C" ) ) {
1286                 return false;
1287             }
1288             if ( !i_m_all.getState( "jr", "0" ).contains( "D" ) ) {
1289                 return false;
1290             }
1291             final FitchParsimony<String> fitch2 = new FitchParsimony<String>();
1292             final PhylogenyFactory factory2 = ParserBasedPhylogenyFactory.getInstance();
1293             final String p2_str = "((a,b)ab,(c,(d,e)de)cde)r";
1294             final Phylogeny p2 = factory2.create( p2_str, new NHXParser() )[ 0 ];
1295             final CharacterStateMatrix<String> m2 = new BasicCharacterStateMatrix<String>( 5, 1 );
1296             m2.setIdentifier( 0, "a" );
1297             m2.setIdentifier( 1, "b" );
1298             m2.setIdentifier( 2, "c" );
1299             m2.setIdentifier( 3, "d" );
1300             m2.setIdentifier( 4, "e" );
1301             m2.setCharacter( 0, "0" );
1302             m2.setState( "a", "0", "C" );
1303             m2.setState( "b", "0", "A" );
1304             m2.setState( "c", "0", "C" );
1305             m2.setState( "d", "0", "A" );
1306             m2.setState( "e", "0", "G" );
1307             fitch2.setReturnInternalStates( true );
1308             fitch2.setReturnGainLossMatrix( false );
1309             fitch2.execute( p2, m2 );
1310             final CharacterStateMatrix<String> i_m2 = fitch2.getInternalStatesMatrix();
1311             final CharacterStateMatrix<List<String>> i_m_all2 = fitch2.getInternalStatesMatrixPriorToTraceback();
1312             if ( fitch2.getCost() != 3 ) {
1313                 return false;
1314             }
1315             if ( !i_m2.getState( "ab", "0" ).equals( "A" ) ) {
1316                 return false;
1317             }
1318             if ( !i_m2.getState( "de", "0" ).equals( "A" ) ) {
1319                 return false;
1320             }
1321             if ( !i_m2.getState( "cde", "0" ).equals( "A" ) ) {
1322                 return false;
1323             }
1324             if ( !i_m2.getState( "r", "0" ).equals( "A" ) ) {
1325                 return false;
1326             }
1327             if ( i_m_all2.getState( "cde", "0" ).size() != 3 ) {
1328                 return false;
1329             }
1330             if ( !i_m_all2.getState( "cde", "0" ).contains( "A" ) ) {
1331                 return false;
1332             }
1333             if ( !i_m_all2.getState( "cde", "0" ).contains( "C" ) ) {
1334                 return false;
1335             }
1336             if ( !i_m_all2.getState( "cde", "0" ).contains( "G" ) ) {
1337                 return false;
1338             }
1339             if ( i_m_all2.getState( "ab", "0" ).size() != 2 ) {
1340                 return false;
1341             }
1342             if ( !i_m_all2.getState( "ab", "0" ).contains( "A" ) ) {
1343                 return false;
1344             }
1345             if ( !i_m_all2.getState( "ab", "0" ).contains( "C" ) ) {
1346                 return false;
1347             }
1348             fitch2.setReturnInternalStates( true );
1349             fitch2.setReturnGainLossMatrix( false );
1350             fitch2.setUseLast( true );
1351             fitch2.execute( p2, m2 );
1352             final CharacterStateMatrix<String> i_m21 = fitch2.getInternalStatesMatrix();
1353             final CharacterStateMatrix<List<String>> i_m_all21 = fitch2.getInternalStatesMatrixPriorToTraceback();
1354             if ( fitch2.getCost() != 3 ) {
1355                 return false;
1356             }
1357             if ( !i_m21.getState( "ab", "0" ).equals( "C" ) ) {
1358                 return false;
1359             }
1360             if ( !i_m21.getState( "de", "0" ).equals( "G" ) ) {
1361                 return false;
1362             }
1363             if ( !i_m21.getState( "cde", "0" ).equals( "C" ) ) {
1364                 return false;
1365             }
1366             if ( !i_m21.getState( "r", "0" ).equals( "C" ) ) {
1367                 return false;
1368             }
1369             if ( i_m_all21.getState( "cde", "0" ).size() != 3 ) {
1370                 return false;
1371             }
1372             if ( !i_m_all21.getState( "cde", "0" ).contains( "A" ) ) {
1373                 return false;
1374             }
1375             if ( !i_m_all21.getState( "cde", "0" ).contains( "C" ) ) {
1376                 return false;
1377             }
1378             if ( !i_m_all21.getState( "cde", "0" ).contains( "G" ) ) {
1379                 return false;
1380             }
1381             final FitchParsimony<String> fitch3 = new FitchParsimony<String>();
1382             final PhylogenyFactory factory3 = ParserBasedPhylogenyFactory.getInstance();
1383             final String p3_str = "(((a,b)ab,((c,d)cd,e)cde)abcde,f)r";
1384             final Phylogeny p3 = factory3.create( p3_str, new NHXParser() )[ 0 ];
1385             final CharacterStateMatrix<String> m3 = new BasicCharacterStateMatrix<String>( 6, 1 );
1386             m3.setIdentifier( 0, "a" );
1387             m3.setIdentifier( 1, "b" );
1388             m3.setIdentifier( 2, "c" );
1389             m3.setIdentifier( 3, "d" );
1390             m3.setIdentifier( 4, "e" );
1391             m3.setIdentifier( 5, "f" );
1392             m3.setCharacter( 0, "0" );
1393             m3.setState( "a", "0", "C" );
1394             m3.setState( "b", "0", "U" );
1395             m3.setState( "c", "0", "G" );
1396             m3.setState( "d", "0", "U" );
1397             m3.setState( "e", "0", "A" );
1398             m3.setState( "f", "0", "A" );
1399             fitch3.setReturnInternalStates( true );
1400             fitch3.setReturnGainLossMatrix( false );
1401             fitch3.execute( p3, m3 );
1402             final CharacterStateMatrix<String> i_m3 = fitch3.getInternalStatesMatrix();
1403             final CharacterStateMatrix<List<String>> i_m_all3 = fitch3.getInternalStatesMatrixPriorToTraceback();
1404             if ( fitch3.getCost() != 4 ) {
1405                 return false;
1406             }
1407             if ( !i_m3.getState( "ab", "0" ).equals( "U" ) ) {
1408                 return false;
1409             }
1410             if ( !i_m3.getState( "cd", "0" ).equals( "U" ) ) {
1411                 return false;
1412             }
1413             if ( !i_m3.getState( "cde", "0" ).equals( "U" ) ) {
1414                 return false;
1415             }
1416             if ( !i_m3.getState( "abcde", "0" ).equals( "U" ) ) {
1417                 return false;
1418             }
1419             if ( !i_m3.getState( "r", "0" ).equals( "A" ) ) {
1420                 return false;
1421             }
1422             if ( i_m_all3.getState( "cde", "0" ).size() != 3 ) {
1423                 return false;
1424             }
1425             if ( !i_m_all3.getState( "cde", "0" ).contains( "A" ) ) {
1426                 return false;
1427             }
1428             if ( !i_m_all3.getState( "cde", "0" ).contains( "G" ) ) {
1429                 return false;
1430             }
1431             if ( !i_m_all3.getState( "cde", "0" ).contains( "U" ) ) {
1432                 return false;
1433             }
1434             if ( i_m_all3.getState( "ab", "0" ).size() != 2 ) {
1435                 return false;
1436             }
1437             if ( !i_m_all3.getState( "ab", "0" ).contains( "C" ) ) {
1438                 return false;
1439             }
1440             if ( !i_m_all3.getState( "ab", "0" ).contains( "U" ) ) {
1441                 return false;
1442             }
1443             if ( i_m_all3.getState( "cd", "0" ).size() != 2 ) {
1444                 return false;
1445             }
1446             if ( !i_m_all3.getState( "cd", "0" ).contains( "G" ) ) {
1447                 return false;
1448             }
1449             if ( !i_m_all3.getState( "cd", "0" ).contains( "U" ) ) {
1450                 return false;
1451             }
1452             if ( i_m_all3.getState( "abcde", "0" ).size() != 1 ) {
1453                 return false;
1454             }
1455             if ( !i_m_all3.getState( "abcde", "0" ).contains( "U" ) ) {
1456                 return false;
1457             }
1458             if ( i_m_all3.getState( "r", "0" ).size() != 2 ) {
1459                 return false;
1460             }
1461             if ( !i_m_all3.getState( "r", "0" ).contains( "A" ) ) {
1462                 return false;
1463             }
1464             if ( !i_m_all3.getState( "r", "0" ).contains( "U" ) ) {
1465                 return false;
1466             }
1467             final FitchParsimony<BinaryStates> fitch4 = new FitchParsimony<BinaryStates>();
1468             final PhylogenyFactory factory4 = ParserBasedPhylogenyFactory.getInstance();
1469             final String p4_str = "(((a,b)ab,((c,d)cd,e)cde)abcde,f)r";
1470             final Phylogeny p4 = factory4.create( p4_str, new NHXParser() )[ 0 ];
1471             final CharacterStateMatrix<BinaryStates> m4 = new BasicCharacterStateMatrix<BinaryStates>( 6, 1 );
1472             m4.setIdentifier( 0, "a" );
1473             m4.setIdentifier( 1, "b" );
1474             m4.setIdentifier( 2, "c" );
1475             m4.setIdentifier( 3, "d" );
1476             m4.setIdentifier( 4, "e" );
1477             m4.setIdentifier( 5, "f" );
1478             m4.setCharacter( 0, "0" );
1479             m4.setState( "a", "0", PRESENT );
1480             m4.setState( "b", "0", ABSENT );
1481             m4.setState( "c", "0", PRESENT );
1482             m4.setState( "d", "0", PRESENT );
1483             m4.setState( "e", "0", ABSENT );
1484             m4.setState( "f", "0", ABSENT );
1485             fitch4.setReturnInternalStates( true );
1486             fitch4.setReturnGainLossMatrix( true );
1487             fitch4.execute( p4, m4 );
1488             final CharacterStateMatrix<GainLossStates> gl_m_4 = fitch4.getGainLossMatrix();
1489             if ( fitch4.getCost() != 2 ) {
1490                 return false;
1491             }
1492             if ( fitch4.getTotalLosses() != 0 ) {
1493                 return false;
1494             }
1495             if ( fitch4.getTotalGains() != 2 ) {
1496                 return false;
1497             }
1498             if ( fitch4.getTotalUnchanged() != 9 ) {
1499                 return false;
1500             }
1501             if ( gl_m_4.getState( "a", "0" ) != GAIN ) {
1502                 return false;
1503             }
1504             if ( gl_m_4.getState( "b", "0" ) != UNCHANGED_ABSENT ) {
1505                 return false;
1506             }
1507             if ( gl_m_4.getState( "ab", "0" ) != UNCHANGED_ABSENT ) {
1508                 return false;
1509             }
1510             if ( gl_m_4.getState( "cd", "0" ) != GAIN ) {
1511                 return false;
1512             }
1513             if ( gl_m_4.getState( "r", "0" ) != UNCHANGED_ABSENT ) {
1514                 return false;
1515             }
1516             final FitchParsimony<BinaryStates> fitch5 = new FitchParsimony<BinaryStates>();
1517             final PhylogenyFactory factory5 = ParserBasedPhylogenyFactory.getInstance();
1518             final String p5_str = "(((a,b)ab,((c,d)cd,e)cde)abcde,f)r";
1519             final Phylogeny p5 = factory5.create( p5_str, new NHXParser() )[ 0 ];
1520             final CharacterStateMatrix<BinaryStates> m5 = new BasicCharacterStateMatrix<BinaryStates>( 6, 1 );
1521             m5.setIdentifier( 0, "a" );
1522             m5.setIdentifier( 1, "b" );
1523             m5.setIdentifier( 2, "c" );
1524             m5.setIdentifier( 3, "d" );
1525             m5.setIdentifier( 4, "e" );
1526             m5.setIdentifier( 5, "f" );
1527             m5.setCharacter( 0, "0" );
1528             m5.setState( "a", "0", PRESENT );
1529             m5.setState( "b", "0", ABSENT );
1530             m5.setState( "c", "0", PRESENT );
1531             m5.setState( "d", "0", ABSENT );
1532             m5.setState( "e", "0", PRESENT );
1533             m5.setState( "f", "0", ABSENT );
1534             fitch5.setReturnInternalStates( true );
1535             fitch5.setReturnGainLossMatrix( true );
1536             fitch5.execute( p5, m5 );
1537             final CharacterStateMatrix<GainLossStates> gl_m_5 = fitch5.getGainLossMatrix();
1538             if ( fitch5.getCost() != 3 ) {
1539                 return false;
1540             }
1541             if ( fitch5.getTotalLosses() != 2 ) {
1542                 return false;
1543             }
1544             if ( fitch5.getTotalGains() != 1 ) {
1545                 return false;
1546             }
1547             if ( fitch5.getTotalUnchanged() != 8 ) {
1548                 return false;
1549             }
1550             if ( gl_m_5.getState( "abcde", "0" ) != GAIN ) {
1551                 return false;
1552             }
1553             if ( gl_m_5.getState( "a", "0" ) != UNCHANGED_PRESENT ) {
1554                 return false;
1555             }
1556             if ( gl_m_5.getState( "b", "0" ) != LOSS ) {
1557                 return false;
1558             }
1559             if ( gl_m_5.getState( "d", "0" ) != LOSS ) {
1560                 return false;
1561             }
1562             if ( gl_m_5.getState( "r", "0" ) != UNCHANGED_ABSENT ) {
1563                 return false;
1564             }
1565             final FitchParsimony<BinaryStates> fitch6 = new FitchParsimony<BinaryStates>();
1566             final PhylogenyFactory factory6 = ParserBasedPhylogenyFactory.getInstance();
1567             final String p6_str = "(((a,b)ab,((c,d)cd,e)cde)abcde,f)r";
1568             final Phylogeny p6 = factory6.create( p6_str, new NHXParser() )[ 0 ];
1569             final CharacterStateMatrix<BinaryStates> m6 = new BasicCharacterStateMatrix<BinaryStates>( 6, 1 );
1570             m6.setIdentifier( 0, "a" );
1571             m6.setIdentifier( 1, "b" );
1572             m6.setIdentifier( 2, "c" );
1573             m6.setIdentifier( 3, "d" );
1574             m6.setIdentifier( 4, "e" );
1575             m6.setIdentifier( 5, "f" );
1576             m6.setCharacter( 0, "0" );
1577             m6.setState( "a", "0", PRESENT );
1578             m6.setState( "b", "0", ABSENT );
1579             m6.setState( "c", "0", PRESENT );
1580             m6.setState( "d", "0", PRESENT );
1581             m6.setState( "e", "0", ABSENT );
1582             m6.setState( "f", "0", PRESENT );
1583             fitch6.setReturnInternalStates( true );
1584             fitch6.setReturnGainLossMatrix( true );
1585             fitch6.execute( p6, m6 );
1586             final CharacterStateMatrix<GainLossStates> gl_m_6 = fitch6.getGainLossMatrix();
1587             if ( fitch6.getCost() != 2 ) {
1588                 return false;
1589             }
1590             if ( fitch6.getTotalLosses() != 2 ) {
1591                 return false;
1592             }
1593             if ( fitch6.getTotalGains() != 0 ) {
1594                 return false;
1595             }
1596             if ( fitch6.getTotalUnchanged() != 9 ) {
1597                 return false;
1598             }
1599             if ( gl_m_6.getState( "abcde", "0" ) != UNCHANGED_PRESENT ) {
1600                 return false;
1601             }
1602             if ( gl_m_6.getState( "r", "0" ) != UNCHANGED_PRESENT ) {
1603                 return false;
1604             }
1605             if ( gl_m_6.getState( "b", "0" ) != LOSS ) {
1606                 return false;
1607             }
1608             if ( gl_m_6.getState( "e", "0" ) != LOSS ) {
1609                 return false;
1610             }
1611             final FitchParsimony<BinaryStates> fitch7 = new FitchParsimony<BinaryStates>();
1612             final PhylogenyFactory factory7 = ParserBasedPhylogenyFactory.getInstance();
1613             final String p7_str = "(((a,b)ab,(c,d)cd)abcd,((e,f)ef,(g,h)gh)efgh)r";
1614             final Phylogeny p7 = factory7.create( p7_str, new NHXParser() )[ 0 ];
1615             final CharacterStateMatrix<BinaryStates> m7 = new BasicCharacterStateMatrix<BinaryStates>( 8, 1 );
1616             m7.setIdentifier( 0, "a" );
1617             m7.setIdentifier( 1, "b" );
1618             m7.setIdentifier( 2, "c" );
1619             m7.setIdentifier( 3, "d" );
1620             m7.setIdentifier( 4, "e" );
1621             m7.setIdentifier( 5, "f" );
1622             m7.setIdentifier( 6, "g" );
1623             m7.setIdentifier( 7, "h" );
1624             m7.setCharacter( 0, "0" );
1625             m7.setState( "a", "0", PRESENT );
1626             m7.setState( "b", "0", ABSENT );
1627             m7.setState( "c", "0", PRESENT );
1628             m7.setState( "d", "0", ABSENT );
1629             m7.setState( "e", "0", PRESENT );
1630             m7.setState( "f", "0", ABSENT );
1631             m7.setState( "g", "0", PRESENT );
1632             m7.setState( "h", "0", ABSENT );
1633             fitch7.setReturnInternalStates( true );
1634             fitch7.setReturnGainLossMatrix( true );
1635             fitch7.execute( p7, m7 );
1636             final CharacterStateMatrix<GainLossStates> gl_m_7 = fitch7.getGainLossMatrix();
1637             if ( fitch7.getCost() != 4 ) {
1638                 return false;
1639             }
1640             if ( fitch7.getTotalLosses() != 0 ) {
1641                 return false;
1642             }
1643             if ( fitch7.getTotalGains() != 4 ) {
1644                 return false;
1645             }
1646             if ( fitch7.getTotalUnchanged() != 11 ) {
1647                 return false;
1648             }
1649             if ( gl_m_7.getState( "a", "0" ) != GAIN ) {
1650                 return false;
1651             }
1652             if ( gl_m_7.getState( "c", "0" ) != GAIN ) {
1653                 return false;
1654             }
1655             if ( gl_m_7.getState( "e", "0" ) != GAIN ) {
1656                 return false;
1657             }
1658             if ( gl_m_7.getState( "g", "0" ) != GAIN ) {
1659                 return false;
1660             }
1661             if ( gl_m_7.getState( "r", "0" ) != UNCHANGED_ABSENT ) {
1662                 return false;
1663             }
1664             fitch7.setReturnInternalStates( true );
1665             fitch7.setReturnGainLossMatrix( true );
1666             fitch7.setUseLast( true );
1667             fitch7.execute( p7, m7 );
1668             final CharacterStateMatrix<GainLossStates> gl_m_71 = fitch7.getGainLossMatrix();
1669             if ( fitch7.getCost() != 4 ) {
1670                 return false;
1671             }
1672             if ( fitch7.getTotalLosses() != 4 ) {
1673                 return false;
1674             }
1675             if ( fitch7.getTotalGains() != 0 ) {
1676                 return false;
1677             }
1678             if ( fitch7.getTotalUnchanged() != 11 ) {
1679                 return false;
1680             }
1681             if ( gl_m_71.getState( "b", "0" ) != LOSS ) {
1682                 return false;
1683             }
1684             if ( gl_m_71.getState( "d", "0" ) != LOSS ) {
1685                 return false;
1686             }
1687             if ( gl_m_71.getState( "f", "0" ) != LOSS ) {
1688                 return false;
1689             }
1690             if ( gl_m_71.getState( "h", "0" ) != LOSS ) {
1691                 return false;
1692             }
1693             if ( gl_m_71.getState( "r", "0" ) != UNCHANGED_PRESENT ) {
1694                 return false;
1695             }
1696             final FitchParsimony<BinaryStates> fitch8 = new FitchParsimony<BinaryStates>();
1697             final PhylogenyFactory factory8 = ParserBasedPhylogenyFactory.getInstance();
1698             final String p8_str = "(((a,b)ab,(c,d)cd)abcd,((e,f)ef,(g,h)gh)efgh)r";
1699             final Phylogeny p8 = factory8.create( p8_str, new NHXParser() )[ 0 ];
1700             final CharacterStateMatrix<BinaryStates> m8 = new BasicCharacterStateMatrix<BinaryStates>( 8, 1 );
1701             m8.setIdentifier( 0, "a" );
1702             m8.setIdentifier( 1, "b" );
1703             m8.setIdentifier( 2, "c" );
1704             m8.setIdentifier( 3, "d" );
1705             m8.setIdentifier( 4, "e" );
1706             m8.setIdentifier( 5, "f" );
1707             m8.setIdentifier( 6, "g" );
1708             m8.setIdentifier( 7, "h" );
1709             m8.setCharacter( 0, "0" );
1710             m8.setState( "a", "0", PRESENT );
1711             m8.setState( "b", "0", PRESENT );
1712             m8.setState( "c", "0", PRESENT );
1713             m8.setState( "d", "0", ABSENT );
1714             m8.setState( "e", "0", ABSENT );
1715             m8.setState( "f", "0", ABSENT );
1716             m8.setState( "g", "0", ABSENT );
1717             m8.setState( "h", "0", ABSENT );
1718             fitch8.setReturnInternalStates( true );
1719             fitch8.setReturnGainLossMatrix( true );
1720             fitch8.execute( p8, m8 );
1721             final CharacterStateMatrix<GainLossStates> gl_m_8 = fitch8.getGainLossMatrix();
1722             if ( fitch8.getCost() != 2 ) {
1723                 return false;
1724             }
1725             if ( fitch8.getTotalLosses() != 1 ) {
1726                 return false;
1727             }
1728             if ( fitch8.getTotalGains() != 1 ) {
1729                 return false;
1730             }
1731             if ( fitch8.getTotalUnchanged() != 13 ) {
1732                 return false;
1733             }
1734             if ( gl_m_8.getState( "d", "0" ) != LOSS ) {
1735                 return false;
1736             }
1737             if ( gl_m_8.getState( "abcd", "0" ) != GAIN ) {
1738                 return false;
1739             }
1740             final FitchParsimony<BinaryStates> fitch9 = new FitchParsimony<BinaryStates>();
1741             final PhylogenyFactory factory9 = ParserBasedPhylogenyFactory.getInstance();
1742             final String p9_str = "(((a,b)ab,c)abc,d)abcd";
1743             final Phylogeny p9 = factory9.create( p9_str, new NHXParser() )[ 0 ];
1744             final CharacterStateMatrix<BinaryStates> m9 = new BasicCharacterStateMatrix<BinaryStates>( 4, 1 );
1745             m9.setIdentifier( 0, "a" );
1746             m9.setIdentifier( 1, "b" );
1747             m9.setIdentifier( 2, "c" );
1748             m9.setIdentifier( 3, "d" );
1749             m9.setCharacter( 0, "0" );
1750             m9.setState( "a", "0", PRESENT );
1751             m9.setState( "b", "0", ABSENT );
1752             m9.setState( "c", "0", PRESENT );
1753             m9.setState( "d", "0", ABSENT );
1754             fitch9.setReturnInternalStates( true );
1755             fitch9.setReturnGainLossMatrix( true );
1756             fitch9.setUseLast( false );
1757             fitch9.execute( p9, m9 );
1758             final CharacterStateMatrix<GainLossStates> gl_m_9a = fitch9.getGainLossMatrix();
1759             if ( fitch9.getCost() != 2 ) {
1760                 return false;
1761             }
1762             if ( fitch9.getTotalLosses() != 1 ) {
1763                 return false;
1764             }
1765             if ( fitch9.getTotalGains() != 1 ) {
1766                 return false;
1767             }
1768             if ( fitch9.getTotalUnchanged() != 5 ) {
1769                 return false;
1770             }
1771             if ( gl_m_9a.getState( "a", "0" ) != UNCHANGED_PRESENT ) {
1772                 return false;
1773             }
1774             if ( gl_m_9a.getState( "b", "0" ) != LOSS ) {
1775                 return false;
1776             }
1777             if ( gl_m_9a.getState( "c", "0" ) != UNCHANGED_PRESENT ) {
1778                 return false;
1779             }
1780             if ( gl_m_9a.getState( "d", "0" ) != UNCHANGED_ABSENT ) {
1781                 return false;
1782             }
1783             if ( gl_m_9a.getState( "ab", "0" ) != UNCHANGED_PRESENT ) {
1784                 return false;
1785             }
1786             if ( gl_m_9a.getState( "abc", "0" ) != GAIN ) {
1787                 return false;
1788             }
1789             if ( gl_m_9a.getState( "abcd", "0" ) != UNCHANGED_ABSENT ) {
1790                 return false;
1791             }
1792             fitch9.setUseLast( true );
1793             fitch9.execute( p9, m9 );
1794             final CharacterStateMatrix<GainLossStates> gl_m_9b = fitch9.getGainLossMatrix();
1795             if ( fitch9.getCost() != 2 ) {
1796                 return false;
1797             }
1798             if ( fitch9.getTotalLosses() != 2 ) {
1799                 return false;
1800             }
1801             if ( fitch9.getTotalGains() != 0 ) {
1802                 return false;
1803             }
1804             if ( fitch9.getTotalUnchanged() != 5 ) {
1805                 return false;
1806             }
1807             if ( gl_m_9b.getState( "a", "0" ) != UNCHANGED_PRESENT ) {
1808                 return false;
1809             }
1810             if ( gl_m_9b.getState( "b", "0" ) != LOSS ) {
1811                 return false;
1812             }
1813             if ( gl_m_9b.getState( "c", "0" ) != UNCHANGED_PRESENT ) {
1814                 return false;
1815             }
1816             if ( gl_m_9b.getState( "d", "0" ) != LOSS ) {
1817                 return false;
1818             }
1819             if ( gl_m_9b.getState( "ab", "0" ) != UNCHANGED_PRESENT ) {
1820                 return false;
1821             }
1822             if ( gl_m_9b.getState( "abc", "0" ) != UNCHANGED_PRESENT ) {
1823                 return false;
1824             }
1825             if ( gl_m_9b.getState( "abcd", "0" ) != UNCHANGED_PRESENT ) {
1826                 return false;
1827             }
1828             fitch9.setUseLast( false );
1829             fitch9.setRandomize( true );
1830             fitch9.setRandomNumberSeed( 8722445 );
1831             fitch9.execute( p9, m9 );
1832             fitch9.getGainLossMatrix();
1833             if ( fitch9.getCost() != 2 ) {
1834                 return false;
1835             }
1836             if ( fitch9.getTotalLosses() != 1 ) {
1837                 return false;
1838             }
1839             if ( fitch9.getTotalGains() != 1 ) {
1840                 return false;
1841             }
1842             if ( fitch9.getTotalUnchanged() != 5 ) {
1843                 return false;
1844             }
1845             final FitchParsimony<BinaryStates> fitch10 = new FitchParsimony<BinaryStates>();
1846             final PhylogenyFactory factory10 = ParserBasedPhylogenyFactory.getInstance();
1847             final String p10_str = "((((a,b)ab,c)abc,d)abcd,e)abcde";
1848             final Phylogeny p10 = factory10.create( p10_str, new NHXParser() )[ 0 ];
1849             final CharacterStateMatrix<BinaryStates> m10 = new BasicCharacterStateMatrix<BinaryStates>( 5, 1 );
1850             m10.setIdentifier( 0, "a" );
1851             m10.setIdentifier( 1, "b" );
1852             m10.setIdentifier( 2, "c" );
1853             m10.setIdentifier( 3, "d" );
1854             m10.setIdentifier( 4, "e" );
1855             m10.setCharacter( 0, "0" );
1856             m10.setState( "a", "0", PRESENT );
1857             m10.setState( "b", "0", ABSENT );
1858             m10.setState( "c", "0", ABSENT );
1859             m10.setState( "d", "0", PRESENT );
1860             m10.setState( "e", "0", ABSENT );
1861             fitch10.setReturnInternalStates( true );
1862             fitch10.setReturnGainLossMatrix( true );
1863             fitch10.setUseLast( false );
1864             fitch10.execute( p10, m10 );
1865             final CharacterStateMatrix<GainLossStates> gl_m_10a = fitch10.getGainLossMatrix();
1866             if ( fitch10.getCost() != 2 ) {
1867                 return false;
1868             }
1869             if ( fitch10.getTotalLosses() != 0 ) {
1870                 return false;
1871             }
1872             if ( fitch10.getTotalGains() != 2 ) {
1873                 return false;
1874             }
1875             if ( fitch10.getTotalUnchanged() != 7 ) {
1876                 return false;
1877             }
1878             if ( gl_m_10a.getState( "a", "0" ) != GAIN ) {
1879                 return false;
1880             }
1881             if ( gl_m_10a.getState( "b", "0" ) != UNCHANGED_ABSENT ) {
1882                 return false;
1883             }
1884             if ( gl_m_10a.getState( "c", "0" ) != UNCHANGED_ABSENT ) {
1885                 return false;
1886             }
1887             if ( gl_m_10a.getState( "d", "0" ) != GAIN ) {
1888                 return false;
1889             }
1890             if ( gl_m_10a.getState( "e", "0" ) != UNCHANGED_ABSENT ) {
1891                 return false;
1892             }
1893             if ( gl_m_10a.getState( "ab", "0" ) != UNCHANGED_ABSENT ) {
1894                 return false;
1895             }
1896             if ( gl_m_10a.getState( "abc", "0" ) != UNCHANGED_ABSENT ) {
1897                 return false;
1898             }
1899             if ( gl_m_10a.getState( "abcd", "0" ) != UNCHANGED_ABSENT ) {
1900                 return false;
1901             }
1902             if ( gl_m_10a.getState( "abcde", "0" ) != UNCHANGED_ABSENT ) {
1903                 return false;
1904             }
1905             fitch10.setUseLast( true );
1906             fitch10.execute( p10, m10 );
1907             final CharacterStateMatrix<GainLossStates> gl_m_10b = fitch10.getGainLossMatrix();
1908             if ( fitch10.getCost() != 2 ) {
1909                 return false;
1910             }
1911             if ( fitch10.getTotalLosses() != 0 ) {
1912                 return false;
1913             }
1914             if ( fitch10.getTotalGains() != 2 ) {
1915                 return false;
1916             }
1917             if ( fitch10.getTotalUnchanged() != 7 ) {
1918                 return false;
1919             }
1920             if ( gl_m_10b.getState( "a", "0" ) != GAIN ) {
1921                 return false;
1922             }
1923             if ( gl_m_10b.getState( "b", "0" ) != UNCHANGED_ABSENT ) {
1924                 return false;
1925             }
1926             if ( gl_m_10b.getState( "c", "0" ) != UNCHANGED_ABSENT ) {
1927                 return false;
1928             }
1929             if ( gl_m_10b.getState( "d", "0" ) != GAIN ) {
1930                 return false;
1931             }
1932             if ( gl_m_10b.getState( "e", "0" ) != UNCHANGED_ABSENT ) {
1933                 return false;
1934             }
1935             if ( gl_m_10b.getState( "ab", "0" ) != UNCHANGED_ABSENT ) {
1936                 return false;
1937             }
1938             if ( gl_m_10b.getState( "abc", "0" ) != UNCHANGED_ABSENT ) {
1939                 return false;
1940             }
1941             if ( gl_m_10b.getState( "abcd", "0" ) != UNCHANGED_ABSENT ) {
1942                 return false;
1943             }
1944             if ( gl_m_10b.getState( "abcde", "0" ) != UNCHANGED_ABSENT ) {
1945                 return false;
1946             }
1947         }
1948         catch ( final Exception e ) {
1949             e.printStackTrace( System.out );
1950             return false;
1951         }
1952         return true;
1953     }
1954
1955     private static boolean testNeighborJoining() {
1956         try {
1957             NeighborJoining nj = NeighborJoining.createInstance();
1958             final BasicSymmetricalDistanceMatrix m0 = new BasicSymmetricalDistanceMatrix( 4 );
1959             m0.setIdentifier( 0, "A" );
1960             m0.setIdentifier( 1, "B" );
1961             m0.setIdentifier( 2, "C" );
1962             m0.setIdentifier( 3, "D" );
1963             m0.setRow( "5 ", 1 );
1964             m0.setRow( "3 6 ", 2 );
1965             m0.setRow( "7.5 10.5 5.5", 3 );
1966             final Phylogeny p0 = nj.execute( m0 );
1967             p0.reRoot( p0.getNode( "D" ) );
1968             if ( isUnequal( p0.getNode( "A" ).getDistanceToParent(), 1 ) ) {
1969                 return false;
1970             }
1971             if ( isUnequal( p0.getNode( "B" ).getDistanceToParent(), 4 ) ) {
1972                 return false;
1973             }
1974             if ( isUnequal( p0.getNode( "C" ).getDistanceToParent(), 0.5 ) ) {
1975                 return false;
1976             }
1977             if ( isUnequal( p0.getNode( "D" ).getDistanceToParent(), 2.5 ) ) {
1978                 return false;
1979             }
1980             if ( isUnequal( p0.getNode( "A" ).getParent().getDistanceToParent(), 1.5 ) ) {
1981                 return false;
1982             }
1983             if ( isUnequal( p0.getNode( "A" ).getParent().getParent().getDistanceToParent(), 2.5 ) ) {
1984                 return false;
1985             }
1986             nj = NeighborJoining.createInstance();
1987             final BasicSymmetricalDistanceMatrix m00 = new BasicSymmetricalDistanceMatrix( 4 );
1988             m00.setIdentifier( 0, "A" );
1989             m00.setIdentifier( 1, "B" );
1990             m00.setIdentifier( 2, "C" );
1991             m00.setIdentifier( 3, "D" );
1992             m00.setRow( "2.01 ", 1 );
1993             m00.setRow( "3 3.01 ", 2 );
1994             m00.setRow( "3.01 3.02 1.01", 3 );
1995             final Phylogeny p00 = nj.execute( m00 );
1996             p00.reRoot( p00.getNode( "D" ) );
1997             if ( isUnequal( p00.getNode( "A" ).getDistanceToParent(), 1 ) ) {
1998                 return false;
1999             }
2000             if ( isUnequal( p00.getNode( "B" ).getDistanceToParent(), 1.01 ) ) {
2001                 return false;
2002             }
2003             if ( isUnequal( p00.getNode( "C" ).getDistanceToParent(), 0.5 ) ) {
2004                 return false;
2005             }
2006             if ( isUnequal( p00.getNode( "D" ).getDistanceToParent(), 0.255 ) ) {
2007                 return false;
2008             }
2009             if ( isUnequal( p00.getNode( "A" ).getParent().getDistanceToParent(), 1.5 ) ) {
2010                 return false;
2011             }
2012             if ( isUnequal( p00.getNode( "A" ).getParent().getParent().getDistanceToParent(), 0.255 ) ) {
2013                 return false;
2014             }
2015             BasicSymmetricalDistanceMatrix m = new BasicSymmetricalDistanceMatrix( 6 );
2016             m.setRow( "5", 1 );
2017             m.setRow( "4 7", 2 );
2018             m.setRow( "7 10 7", 3 );
2019             m.setRow( "6 9 6 5", 4 );
2020             m.setRow( "8 11 8 9 8", 5 );
2021             m.setIdentifier( 0, "A" );
2022             m.setIdentifier( 1, "B" );
2023             m.setIdentifier( 2, "C" );
2024             m.setIdentifier( 3, "D" );
2025             m.setIdentifier( 4, "E" );
2026             m.setIdentifier( 5, "F" );
2027             nj = NeighborJoining.createInstance();
2028             final Phylogeny p1 = nj.execute( m );
2029             p1.reRoot( p1.getNode( "F" ) );
2030             if ( isUnequal( p1.getNode( "A" ).getDistanceToParent(), 1 ) ) {
2031                 return false;
2032             }
2033             if ( isUnequal( p1.getNode( "B" ).getDistanceToParent(), 4 ) ) {
2034                 return false;
2035             }
2036             if ( isUnequal( p1.getNode( "C" ).getDistanceToParent(), 2 ) ) {
2037                 return false;
2038             }
2039             if ( isUnequal( p1.getNode( "D" ).getDistanceToParent(), 3 ) ) {
2040                 return false;
2041             }
2042             if ( isUnequal( p1.getNode( "E" ).getDistanceToParent(), 2 ) ) {
2043                 return false;
2044             }
2045             if ( isUnequal( p1.getNode( "F" ).getDistanceToParent(), 2.5 ) ) {
2046                 return false;
2047             }
2048             if ( isUnequal( p1.getNode( "A" ).getParent().getDistanceToParent(), 1 ) ) {
2049                 return false;
2050             }
2051             if ( isUnequal( p1.getNode( "A" ).getParent().getParent().getDistanceToParent(), 1 ) ) {
2052                 return false;
2053             }
2054             if ( isUnequal( p1.getNode( "A" ).getParent().getParent().getParent().getDistanceToParent(), 2.5 ) ) {
2055                 return false;
2056             }
2057             if ( isUnequal( p1.getNode( "B" ).getParent().getDistanceToParent(), 1 ) ) {
2058                 return false;
2059             }
2060             if ( isUnequal( p1.getNode( "D" ).getParent().getDistanceToParent(), 1 ) ) {
2061                 return false;
2062             }
2063             if ( isUnequal( p1.getNode( "E" ).getParent().getDistanceToParent(), 1 ) ) {
2064                 return false;
2065             }
2066             m = new BasicSymmetricalDistanceMatrix( 7 );
2067             m.setIdentifier( 0, "Bovine" );
2068             m.setIdentifier( 1, "Mouse" );
2069             m.setIdentifier( 2, "Gibbon" );
2070             m.setIdentifier( 3, "Orang" );
2071             m.setIdentifier( 4, "Gorilla" );
2072             m.setIdentifier( 5, "Chimp" );
2073             m.setIdentifier( 6, "Human" );
2074             m.setRow( "0.00000 1.68660 1.71980 1.66060 1.52430 1.60430 1.59050", 0 );
2075             m.setRow( "1.68660 0.00000 1.52320 1.48410 1.44650 1.43890 1.46290", 1 );
2076             m.setRow( "1.71980 1.52320 0.00000 0.71150 0.59580 0.61790 0.55830", 2 );
2077             m.setRow( "1.66060 1.48410 0.71150 0.00000 0.46310 0.50610 0.47100", 3 );
2078             m.setRow( "1.52430 1.44650 0.59580 0.46310 0.00000 0.34840 0.30830", 4 );
2079             m.setRow( "1.60430 1.43890 0.61790 0.50610 0.34840 0.00000 0.26920", 5 );
2080             m.setRow( "1.59050 1.46290 0.55830 0.47100 0.30830 0.26920 0.00000", 6 );
2081             //NeighborJoiningR njr = NeighborJoiningR.createInstance( true, 6 );
2082             nj = NeighborJoining.createInstance( true, 6 );
2083             final Phylogeny p2 = nj.execute( m );
2084             //Archaeopteryx.createApplication( p2 );
2085             p2.reRoot( p2.getNode( "Bovine" ) );
2086             if ( isUnequal( p2.getNode( "Chimp" ).getDistanceToParent(), 0.151675 ) ) {
2087                 return false;
2088             }
2089             if ( isUnequal( p2.getNode( "Human" ).getDistanceToParent(), 0.117525 ) ) {
2090                 return false;
2091             }
2092             if ( isUnequal( p2.getNode( "Gorilla" ).getDistanceToParent(), 0.153932 ) ) {
2093                 return false;
2094             }
2095             if ( isUnequal( p2.getNode( "Orang" ).getDistanceToParent(), 0.284694 ) ) {
2096                 return false;
2097             }
2098             if ( isUnequal( p2.getNode( "Gibbon" ).getDistanceToParent(), 0.357931 ) ) {
2099                 return false;
2100             }
2101             if ( isUnequal( p2.getNode( "Mouse" ).getDistanceToParent(), 0.76891 ) ) {
2102                 return false;
2103             }
2104             if ( isUnequal( p2.getNode( "Bovine" ).getDistanceToParent(), 0.458845 ) ) {
2105                 return false;
2106             }
2107             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getDistanceToParent(), 0.039819 ) ) {
2108                 return false;
2109             }
2110             if ( isUnequal( p2.getNode( "Human" ).getParent().getDistanceToParent(), 0.039819 ) ) {
2111                 return false;
2112             }
2113             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getDistanceToParent(), 0.026956 ) ) {
2114                 return false;
2115             }
2116             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getParent().getDistanceToParent(), 0.046481 ) ) {
2117                 return false;
2118             }
2119             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getParent().getParent().getDistanceToParent(),
2120                             0.420269 ) ) {
2121                 return false;
2122             }
2123             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getParent().getParent().getParent()
2124                             .getDistanceToParent(), 0.458845 ) ) {
2125                 return false;
2126             }
2127             m = new BasicSymmetricalDistanceMatrix( 4 );
2128             m.setIdentifier( 0, "A" );
2129             m.setIdentifier( 1, "B" );
2130             m.setIdentifier( 2, "C" );
2131             m.setIdentifier( 3, "D" );
2132             m.setRow( "0.00 0.95 0.17 0.98", 0 );
2133             m.setRow( "0.95 0.00 1.02 1.83", 1 );
2134             m.setRow( "0.17 1.02 0.00 1.01", 2 );
2135             m.setRow( "0.98 1.83 1.01 0.00", 3 );
2136             final Phylogeny p3 = nj.execute( m );
2137             p3.reRoot( p3.getNode( "C" ) );
2138             if ( isUnequal( p3.getNode( "A" ).getDistanceToParent(), 0.05 ) ) {
2139                 return false;
2140             }
2141             if ( isUnequal( p3.getNode( "B" ).getDistanceToParent(), 0.90 ) ) {
2142                 return false;
2143             }
2144             if ( !isEqual( p3.getNode( "C" ).getDistanceToParent(), 0.05 ) ) {
2145                 return false;
2146             }
2147             if ( !isEqual( p3.getNode( "D" ).getDistanceToParent(), 0.91 ) ) {
2148                 return false;
2149             }
2150             if ( isUnequal( p3.getNode( "A" ).getParent().getDistanceToParent(), 0.02 ) ) {
2151                 return false;
2152             }
2153             if ( isUnequal( p3.getNode( "A" ).getParent().getParent().getDistanceToParent(), 0.05 ) ) {
2154                 return false;
2155             }
2156             //
2157             NeighborJoiningF njf = NeighborJoiningF.createInstance();
2158             final BasicSymmetricalDistanceMatrix m0f = new BasicSymmetricalDistanceMatrix( 4 );
2159             m0f.setIdentifier( 0, "A" );
2160             m0f.setIdentifier( 1, "B" );
2161             m0f.setIdentifier( 2, "C" );
2162             m0f.setIdentifier( 3, "D" );
2163             m0f.setRow( "5 ", 1 );
2164             m0f.setRow( "3 6 ", 2 );
2165             m0f.setRow( "7.5 10.5 5.5", 3 );
2166             final Phylogeny p0f = njf.execute( m0f );
2167             p0f.reRoot( p0f.getNode( "D" ) );
2168             if ( isUnequal( p0f.getNode( "A" ).getDistanceToParent(), 1 ) ) {
2169                 return false;
2170             }
2171             if ( isUnequal( p0f.getNode( "B" ).getDistanceToParent(), 4 ) ) {
2172                 return false;
2173             }
2174             if ( isUnequal( p0f.getNode( "C" ).getDistanceToParent(), 0.5 ) ) {
2175                 return false;
2176             }
2177             if ( isUnequal( p0f.getNode( "D" ).getDistanceToParent(), 2.5 ) ) {
2178                 return false;
2179             }
2180             if ( isUnequal( p0f.getNode( "A" ).getParent().getDistanceToParent(), 1.5 ) ) {
2181                 return false;
2182             }
2183             if ( isUnequal( p0f.getNode( "A" ).getParent().getParent().getDistanceToParent(), 2.5 ) ) {
2184                 return false;
2185             }
2186             //
2187             m = new BasicSymmetricalDistanceMatrix( 7 );
2188             m.setIdentifier( 0, "Bovine" );
2189             m.setIdentifier( 1, "Mouse" );
2190             m.setIdentifier( 2, "Gibbon" );
2191             m.setIdentifier( 3, "Orang" );
2192             m.setIdentifier( 4, "Gorilla" );
2193             m.setIdentifier( 5, "Chimp" );
2194             m.setIdentifier( 6, "Human" );
2195             m.setRow( "0.00000 1.68660 1.71980 1.66060 1.52430 1.60430 1.59050", 0 );
2196             m.setRow( "1.68660 0.00000 1.52320 1.48410 1.44650 1.43890 1.46290", 1 );
2197             m.setRow( "1.71980 1.52320 0.00000 0.71150 0.59580 0.61790 0.55830", 2 );
2198             m.setRow( "1.66060 1.48410 0.71150 0.00000 0.46310 0.50610 0.47100", 3 );
2199             m.setRow( "1.52430 1.44650 0.59580 0.46310 0.00000 0.34840 0.30830", 4 );
2200             m.setRow( "1.60430 1.43890 0.61790 0.50610 0.34840 0.00000 0.26920", 5 );
2201             m.setRow( "1.59050 1.46290 0.55830 0.47100 0.30830 0.26920 0.00000", 6 );
2202             njf = NeighborJoiningF.createInstance( true, 5 );
2203             final Phylogeny p2f = njf.execute( m );
2204             p2f.reRoot( p2f.getNode( "Bovine" ) );
2205             if ( isUnequal( p2f.getNode( "Chimp" ).getDistanceToParent(), 0.15168 ) ) {
2206                 return false;
2207             }
2208             if ( isUnequal( p2f.getNode( "Human" ).getDistanceToParent(), 0.11752 ) ) {
2209                 return false;
2210             }
2211             if ( isUnequal( p2f.getNode( "Gorilla" ).getDistanceToParent(), 0.15393 ) ) {
2212                 return false;
2213             }
2214             if ( isUnequal( p2f.getNode( "Orang" ).getDistanceToParent(), 0.28469 ) ) {
2215                 return false;
2216             }
2217             if ( isUnequal( p2f.getNode( "Gibbon" ).getDistanceToParent(), 0.35793 ) ) {
2218                 return false;
2219             }
2220             if ( isUnequal( p2f.getNode( "Mouse" ).getDistanceToParent(), 0.76891 ) ) {
2221                 return false;
2222             }
2223             if ( isUnequal( p2f.getNode( "Bovine" ).getDistanceToParent(), 0.458845 ) ) {
2224                 return false;
2225             }
2226             if ( isUnequal( p2f.getNode( "Chimp" ).getParent().getDistanceToParent(), 0.03982 ) ) {
2227                 return false;
2228             }
2229             if ( isUnequal( p2f.getNode( "Human" ).getParent().getDistanceToParent(), 0.03982 ) ) {
2230                 return false;
2231             }
2232             if ( isUnequal( p2f.getNode( "Chimp" ).getParent().getParent().getDistanceToParent(), 0.02696 ) ) {
2233                 return false;
2234             }
2235             if ( isUnequal( p2f.getNode( "Chimp" ).getParent().getParent().getParent().getDistanceToParent(), 0.04648 ) ) {
2236                 return false;
2237             }
2238             if ( isUnequal( p2f.getNode( "Chimp" ).getParent().getParent().getParent().getParent()
2239                             .getDistanceToParent(), 0.42027 ) ) {
2240                 return false;
2241             }
2242             if ( isUnequal( p2f.getNode( "Chimp" ).getParent().getParent().getParent().getParent().getParent()
2243                             .getDistanceToParent(), 0.458845 ) ) {
2244                 return false;
2245             }
2246         }
2247         catch ( final Exception e ) {
2248             e.printStackTrace( System.out );
2249             return false;
2250         }
2251         return true;
2252     }
2253
2254     private static boolean testS() {
2255         try {
2256             final Sset s0 = new Sset();
2257             s0.initialize( 1 );
2258             s0.addPairing( 0, 1, 0 );
2259             s0.addPairing( 7, 8, 0 );
2260             s0.addPairing( 4, 55, 0 );
2261             s0.addPairing( 2, 3, 0 );
2262             s0.addPairing( 4, 5, 0 );
2263             s0.addPairing( 5, 6666, 0 );
2264             s0.addPairing( 5, 666, 0 );
2265             s0.addPairing( 5, 66, 0 );
2266             s0.addPairing( 5, 6, 0 );
2267             s0.addPairing( 6, 7, 0 );
2268             s0.addPairing( 3, 4, 0 );
2269             s0.addPairing( 1, 2, 0 );
2270             if ( s0.size() != 1 ) {
2271                 return false;
2272             }
2273             if ( s0.getS( 0 ).size() != 8 ) {
2274                 return false;
2275             }
2276             if ( s0.getValues( 0, 0 ).size() != 1 ) {
2277                 return false;
2278             }
2279             if ( s0.getValues( 1, 0 ).size() != 1 ) {
2280                 return false;
2281             }
2282             if ( s0.getValues( 2, 0 ).size() != 1 ) {
2283                 return false;
2284             }
2285             if ( s0.getValues( 3, 0 ).size() != 1 ) {
2286                 return false;
2287             }
2288             if ( s0.getValues( 4, 0 ).size() != 2 ) {
2289                 return false;
2290             }
2291             if ( s0.getValues( 5, 0 ).size() != 4 ) {
2292                 return false;
2293             }
2294             if ( s0.getValues( 6, 0 ).size() != 1 ) {
2295                 return false;
2296             }
2297             if ( s0.getValues( 7, 0 ).size() != 1 ) {
2298                 return false;
2299             }
2300             if ( !s0.getValues( 0, 0 ).contains( 1 ) ) {
2301                 return false;
2302             }
2303             if ( !s0.getValues( 5, 0 ).contains( 6 ) ) {
2304                 return false;
2305             }
2306             if ( !s0.getValues( 5, 0 ).contains( 66 ) ) {
2307                 return false;
2308             }
2309             if ( !s0.getValues( 5, 0 ).contains( 666 ) ) {
2310                 return false;
2311             }
2312             if ( !s0.getValues( 5, 0 ).contains( 6666 ) ) {
2313                 return false;
2314             }
2315             s0.removePairing( 5, 6666, 0 );
2316             if ( s0.getValues( 5, 0 ).contains( 6666 ) ) {
2317                 return false;
2318             }
2319             s0.removePairing( 5, 666, 0 );
2320             if ( s0.getValues( 5, 0 ).contains( 666 ) ) {
2321                 return false;
2322             }
2323             s0.removePairing( 5, 66, 0 );
2324             if ( s0.getValues( 5, 0 ).contains( 66 ) ) {
2325                 return false;
2326             }
2327             if ( s0.getValues( 5, 0 ).size() != 1 ) {
2328                 return false;
2329             }
2330             if ( s0.getS( 0 ).size() != 8 ) {
2331                 return false;
2332             }
2333             s0.removePairing( 5, 6, 0 );
2334             if ( s0.getS( 0 ).size() != 7 ) {
2335                 return false;
2336             }
2337             s0.addPairing( 5, 6, 0 );
2338             if ( s0.getS( 0 ).size() != 8 ) {
2339                 return false;
2340             }
2341             if ( s0.getValues( 5, 0 ).size() != 1 ) {
2342                 return false;
2343             }
2344             if ( !s0.getValues( 5, 0 ).contains( 6 ) ) {
2345                 return false;
2346             }
2347             s0.addPairing( 5, 403, 0 );
2348             if ( s0.getValues( 5, 0 ).size() != 2 ) {
2349                 return false;
2350             }
2351             if ( !s0.getValues( 5, 0 ).contains( 403 ) ) {
2352                 return false;
2353             }
2354             s0.addPairing( 693, 100, 0 );
2355             s0.addPairing( 693, 101, 0 );
2356             if ( s0.getValues( 693, 0 ).size() != 2 ) {
2357                 return false;
2358             }
2359             s0.addPairing( 2, 33, 0 );
2360             s0.addPairing( 2, 333, 0 );
2361             final Set<Integer>[] a = s0.toArray( 0 );
2362             if ( !a[ 0 ].contains( 1 ) ) {
2363                 return false;
2364             }
2365             if ( a[ 0 ].size() != 1 ) {
2366                 return false;
2367             }
2368             if ( !a[ 1 ].contains( 2 ) ) {
2369                 return false;
2370             }
2371             if ( a[ 1 ].size() != 1 ) {
2372                 return false;
2373             }
2374             if ( !a[ 2 ].contains( 3 ) ) {
2375                 return false;
2376             }
2377             if ( !a[ 2 ].contains( 33 ) ) {
2378                 return false;
2379             }
2380             if ( !a[ 2 ].contains( 333 ) ) {
2381                 return false;
2382             }
2383         }
2384         catch ( final Exception e ) {
2385             e.printStackTrace( System.out );
2386             return false;
2387         }
2388         return true;
2389     }
2390
2391     private static boolean testSarray() {
2392         try {
2393             final Sarray s0 = new Sarray();
2394             s0.initialize( 1 );
2395             s0.addPairing( 0, 1, 0 );
2396             s0.addPairing( 7, 8, 0 );
2397             s0.addPairing( 4, 55, 0 );
2398             s0.addPairing( 2, 3, 0 );
2399             s0.addPairing( 4, 5, 0 );
2400             s0.addPairing( 5, 6666, 0 );
2401             s0.addPairing( 5, 666, 0 );
2402             s0.addPairing( 5, 66, 0 );
2403             s0.addPairing( 5, 6, 0 );
2404             s0.addPairing( 6, 7, 0 );
2405             s0.addPairing( 3, 4, 0 );
2406             s0.addPairing( 1, 2, 0 );
2407             if ( s0.size() != 1 ) {
2408                 return false;
2409             }
2410             if ( s0.getS( 0 ).size() != 8 ) {
2411                 return false;
2412             }
2413             if ( s0.getValues( 0, 0 ).length != 1 ) {
2414                 return false;
2415             }
2416             if ( s0.getValues( 1, 0 ).length != 1 ) {
2417                 return false;
2418             }
2419             if ( s0.getValues( 2, 0 ).length != 1 ) {
2420                 return false;
2421             }
2422             if ( s0.getValues( 3, 0 ).length != 1 ) {
2423                 return false;
2424             }
2425             if ( s0.getValues( 4, 0 ).length != 2 ) {
2426                 return false;
2427             }
2428             if ( s0.getValues( 5, 0 ).length != 4 ) {
2429                 return false;
2430             }
2431             if ( s0.getValues( 6, 0 ).length != 1 ) {
2432                 return false;
2433             }
2434             if ( s0.getValues( 7, 0 ).length != 1 ) {
2435                 return false;
2436             }
2437             if ( s0.getValues( 0, 0 )[ 0 ] != 1 ) {
2438                 return false;
2439             }
2440             if ( s0.getValues( 5, 0 )[ 3 ] != 6 ) {
2441                 return false;
2442             }
2443             if ( s0.getValues( 5, 0 )[ 2 ] != 66 ) {
2444                 return false;
2445             }
2446             if ( s0.getValues( 5, 0 )[ 1 ] != 666 ) {
2447                 return false;
2448             }
2449             if ( s0.getValues( 5, 0 )[ 0 ] != 6666 ) {
2450                 return false;
2451             }
2452             s0.removePairing( 5, 6666, 0 );
2453             if ( s0.getValues( 5, 0 ).length != 3 ) {
2454                 System.out.println( s0.getValues( 5, 0 ).length );
2455                 return false;
2456             }
2457             //            if ( s0.getValues( 5, 0 ).contains( 6666 ) ) {
2458             //                return false;
2459             //            }
2460             //            s0.removePairing( 5, 666, 0 );
2461             //            if ( s0.getValues( 5, 0 ).contains( 666 ) ) {
2462             //                return false;
2463             //            }
2464             //            s0.removePairing( 5, 66, 0 );
2465             //            if ( s0.getValues( 5, 0 ).contains( 66 ) ) {
2466             //                return false;
2467             //            }
2468             //            if ( s0.getValues( 5, 0 ).size() != 1 ) {
2469             //                return false;
2470             //            }
2471             //            if ( s0.getS( 0 ).size() != 8 ) {
2472             //                return false;
2473             //            }
2474             //            s0.removePairing( 5, 6, 0 );
2475             //            if ( s0.getS( 0 ).size() != 7 ) {
2476             //                return false;
2477             //            }
2478             //            s0.addPairing( 5, 6, 0 );
2479             //            if ( s0.getS( 0 ).size() != 8 ) {
2480             //                return false;
2481             //            }
2482             //            if ( s0.getValues( 5, 0 ).size() != 1 ) {
2483             //                return false;
2484             //            }
2485             //            if ( !s0.getValues( 5, 0 ).contains( 6 ) ) {
2486             //                return false;
2487             //            }
2488             //            s0.addPairing( 5, 403, 0 );
2489             //            if ( s0.getValues( 5, 0 ).size() != 2 ) {
2490             //                return false;
2491             //            }
2492             //            if ( !s0.getValues( 5, 0 ).contains( 403 ) ) {
2493             //                return false;
2494             //            }
2495             //            s0.addPairing( 693, 100, 0 );
2496             //            s0.addPairing( 693, 101, 0 );
2497             //            if ( s0.getValues( 693, 0 ).size() != 2 ) {
2498             //                return false;
2499             //            }
2500             //            s0.addPairing( 2, 33, 0 );
2501             //            s0.addPairing( 2, 333, 0 );
2502             //            final Set<Integer>[] a = s0.toArray( 0 );
2503             //            if ( !a[ 0 ].contains( 1 ) ) {
2504             //                return false;
2505             //            }
2506             //            if ( a[ 0 ].size() != 1 ) {
2507             //                return false;
2508             //            }
2509             //            if ( !a[ 1 ].contains( 2 ) ) {
2510             //                return false;
2511             //            }
2512             //            if ( a[ 1 ].size() != 1 ) {
2513             //                return false;
2514             //            }
2515             //            if ( !a[ 2 ].contains( 3 ) ) {
2516             //                return false;
2517             //            }
2518             //            if ( !a[ 2 ].contains( 33 ) ) {
2519             //                return false;
2520             //            }
2521             //            if ( !a[ 2 ].contains( 333 ) ) {
2522             //                return false;
2523             //            }
2524         }
2525         catch ( final Exception e ) {
2526             e.printStackTrace( System.out );
2527             return false;
2528         }
2529         return true;
2530     }
2531
2532     private static boolean testNeighborJoiningR() {
2533         try {
2534             final NeighborJoiningR nj0 = NeighborJoiningR.createInstance();
2535             final BasicSymmetricalDistanceMatrix m0 = new BasicSymmetricalDistanceMatrix( 4 );
2536             m0.setIdentifier( 0, "A" );
2537             m0.setIdentifier( 1, "B" );
2538             m0.setIdentifier( 2, "C" );
2539             m0.setIdentifier( 3, "D" );
2540             m0.setRow( "5 ", 1 );
2541             m0.setRow( "3 6 ", 2 );
2542             m0.setRow( "7.5 10.5 5.5", 3 );
2543             final Phylogeny p0 = nj0.execute( m0 );
2544             p0.reRoot( p0.getNode( "D" ) );
2545             if ( isUnequal( p0.getNode( "A" ).getDistanceToParent(), 1 ) ) {
2546                 return false;
2547             }
2548             if ( isUnequal( p0.getNode( "B" ).getDistanceToParent(), 4 ) ) {
2549                 return false;
2550             }
2551             if ( isUnequal( p0.getNode( "C" ).getDistanceToParent(), 0.5 ) ) {
2552                 return false;
2553             }
2554             if ( isUnequal( p0.getNode( "D" ).getDistanceToParent(), 2.5 ) ) {
2555                 return false;
2556             }
2557             if ( isUnequal( p0.getNode( "A" ).getParent().getDistanceToParent(), 1.5 ) ) {
2558                 return false;
2559             }
2560             if ( isUnequal( p0.getNode( "A" ).getParent().getParent().getDistanceToParent(), 2.5 ) ) {
2561                 return false;
2562             }
2563             final BasicSymmetricalDistanceMatrix m1 = new BasicSymmetricalDistanceMatrix( 6 );
2564             m1.setRow( "5", 1 );
2565             m1.setRow( "4 7", 2 );
2566             m1.setRow( "7 10 7", 3 );
2567             m1.setRow( "6 9 6 5", 4 );
2568             m1.setRow( "8 11 8 9 8", 5 );
2569             m1.setIdentifier( 0, "A" );
2570             m1.setIdentifier( 1, "B" );
2571             m1.setIdentifier( 2, "C" );
2572             m1.setIdentifier( 3, "D" );
2573             m1.setIdentifier( 4, "E" );
2574             m1.setIdentifier( 5, "F" );
2575             final NeighborJoiningR nj1 = NeighborJoiningR.createInstance();
2576             final Phylogeny p1 = nj1.execute( m1 );
2577             p1.reRoot( p1.getNode( "F" ) );
2578             if ( isUnequal( p1.getNode( "A" ).getDistanceToParent(), 1 ) ) {
2579                 return false;
2580             }
2581             if ( isUnequal( p1.getNode( "B" ).getDistanceToParent(), 4 ) ) {
2582                 return false;
2583             }
2584             if ( isUnequal( p1.getNode( "C" ).getDistanceToParent(), 2 ) ) {
2585                 return false;
2586             }
2587             if ( isUnequal( p1.getNode( "D" ).getDistanceToParent(), 3 ) ) {
2588                 return false;
2589             }
2590             if ( isUnequal( p1.getNode( "E" ).getDistanceToParent(), 2 ) ) {
2591                 return false;
2592             }
2593             if ( isUnequal( p1.getNode( "F" ).getDistanceToParent(), 2.5 ) ) {
2594                 return false;
2595             }
2596             if ( isUnequal( p1.getNode( "A" ).getParent().getDistanceToParent(), 1 ) ) {
2597                 return false;
2598             }
2599             if ( isUnequal( p1.getNode( "A" ).getParent().getParent().getDistanceToParent(), 1 ) ) {
2600                 return false;
2601             }
2602             if ( isUnequal( p1.getNode( "A" ).getParent().getParent().getParent().getDistanceToParent(), 2.5 ) ) {
2603                 return false;
2604             }
2605             if ( isUnequal( p1.getNode( "B" ).getParent().getDistanceToParent(), 1 ) ) {
2606                 return false;
2607             }
2608             if ( isUnequal( p1.getNode( "D" ).getParent().getDistanceToParent(), 1 ) ) {
2609                 return false;
2610             }
2611             if ( isUnequal( p1.getNode( "E" ).getParent().getDistanceToParent(), 1 ) ) {
2612                 return false;
2613             }
2614             final BasicSymmetricalDistanceMatrix m2 = new BasicSymmetricalDistanceMatrix( 7 );
2615             m2.setIdentifier( 0, "Bovine" );
2616             m2.setIdentifier( 1, "Mouse" );
2617             m2.setIdentifier( 2, "Gibbon" );
2618             m2.setIdentifier( 3, "Orang" );
2619             m2.setIdentifier( 4, "Gorilla" );
2620             m2.setIdentifier( 5, "Chimp" );
2621             m2.setIdentifier( 6, "Human" );
2622             m2.setRow( "0.00000 1.68660 1.71980 1.66060 1.52430 1.60430 1.59050", 0 );
2623             m2.setRow( "1.68660 0.00000 1.52320 1.48410 1.44650 1.43890 1.46290", 1 );
2624             m2.setRow( "1.71980 1.52320 0.00000 0.71150 0.59580 0.61790 0.55830", 2 );
2625             m2.setRow( "1.66060 1.48410 0.71150 0.00000 0.46310 0.50610 0.47100", 3 );
2626             m2.setRow( "1.52430 1.44650 0.59580 0.46310 0.00000 0.34840 0.30830", 4 );
2627             m2.setRow( "1.60430 1.43890 0.61790 0.50610 0.34840 0.00000 0.26920", 5 );
2628             m2.setRow( "1.59050 1.46290 0.55830 0.47100 0.30830 0.26920 0.00000", 6 );
2629             final NeighborJoiningR nj2 = NeighborJoiningR.createInstance( true, 6 );
2630             final Phylogeny p2 = nj2.execute( m2 );
2631             // Archaeopteryx.createApplication( p2 );
2632             p2.reRoot( p2.getNode( "Bovine" ) );
2633             if ( isUnequal( p2.getNode( "Chimp" ).getDistanceToParent(), 0.151675 ) ) {
2634                 System.out.println( p2.getNode( "Chimp" ).getDistanceToParent() );
2635                 return false;
2636             }
2637             if ( isUnequal( p2.getNode( "Human" ).getDistanceToParent(), 0.117525 ) ) {
2638                 return false;
2639             }
2640             if ( isUnequal( p2.getNode( "Gorilla" ).getDistanceToParent(), 0.153931 ) ) {
2641                 return false;
2642             }
2643             if ( isUnequal( p2.getNode( "Orang" ).getDistanceToParent(), 0.284694 ) ) {
2644                 return false;
2645             }
2646             if ( isUnequal( p2.getNode( "Gibbon" ).getDistanceToParent(), 0.357931 ) ) {
2647                 return false;
2648             }
2649             if ( isUnequal( p2.getNode( "Mouse" ).getDistanceToParent(), 0.76891 ) ) {
2650                 return false;
2651             }
2652             if ( isUnequal( p2.getNode( "Bovine" ).getDistanceToParent(), 0.458845 ) ) {
2653                 return false;
2654             }
2655             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getDistanceToParent(), 0.039819 ) ) {
2656                 return false;
2657             }
2658             if ( isUnequal( p2.getNode( "Human" ).getParent().getDistanceToParent(), 0.039819 ) ) {
2659                 return false;
2660             }
2661             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getDistanceToParent(), 0.026956 ) ) {
2662                 return false;
2663             }
2664             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getParent().getDistanceToParent(), 0.046481 ) ) {
2665                 return false;
2666             }
2667             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getParent().getParent().getDistanceToParent(),
2668                             0.420269 ) ) {
2669                 return false;
2670             }
2671             if ( isUnequal( p2.getNode( "Chimp" ).getParent().getParent().getParent().getParent().getParent()
2672                             .getDistanceToParent(), 0.458845 ) ) {
2673                 return false;
2674             }
2675             //
2676             // System.exit( 1 );
2677             final BasicSymmetricalDistanceMatrix m3 = new BasicSymmetricalDistanceMatrix( 20 );
2678             m3.setIdentifier( 0, "F_MOUSE" );
2679             m3.setIdentifier( 1, "11_RAT" );
2680             m3.setIdentifier( 2, "A_CAVPO" );
2681             m3.setIdentifier( 3, "D_HUMAN" );
2682             m3.setIdentifier( 4, "E_HUMAN" );
2683             m3.setIdentifier( 5, "F_HUMAN" );
2684             m3.setIdentifier( 6, "C_HUMAN" );
2685             m3.setIdentifier( 7, "6_FELCA" );
2686             m3.setIdentifier( 8, "D_MOUSE" );
2687             m3.setIdentifier( 9, "E_MOUSE" );
2688             m3.setIdentifier( 10, "E_RAT " );
2689             m3.setIdentifier( 11, "C_MOUSE" );
2690             m3.setIdentifier( 12, "10_RAT" );
2691             m3.setIdentifier( 13, "3_TAEGU" );
2692             m3.setIdentifier( 14, "2_SACKO" );
2693             m3.setIdentifier( 15, "2_PANTR" );
2694             m3.setIdentifier( 16, "3_CANFA" );
2695             m3.setIdentifier( 17, "9_HUMAN" );
2696             m3.setIdentifier( 18, "A_HUMAN" );
2697             m3.setIdentifier( 19, "B_HUMAN" );
2698             m3.setRow( "0.000000  0.000010  0.020875  0.010376  0.010376  0.010376  0.010376  0.010368  0.000010  0.000010  0.000010  0.000010  0.000010  0.087165  0.743570  0.010376  0.010376  0.010376  0.010376  0.010376 ",
2699                        0 );
2700             m3.setRow( "0.000010  0.000000  0.020875  0.010376  0.010376  0.010376  0.010376  0.010368  0.000010  0.000010  0.000010  0.000010  0.000010  0.087165  0.743570  0.010376  0.010376  0.010376  0.010376  0.010376",
2701                        1 );
2702             m3.setRow( "0.020875  0.020875  0.000000  0.031503  0.031503  0.031503  0.031503  0.031477  0.020875  0.020875  0.020875  0.020875  0.020875  0.096983  0.768150  0.031503  0.031503  0.031503  0.031503  0.031503",
2703                        2 );
2704             m3.setRow( "0.010376  0.010376  0.031503  0.000000  0.000010  0.000010  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000010  0.000010  0.000010  0.000010",
2705                        3 );
2706             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000000  0.000010  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000010  0.000010  0.000010  0.000010",
2707                        4 );
2708             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000010  0.000000  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000010  0.000010  0.000010  0.000010",
2709                        5 );
2710             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000010  0.000010  0.000000  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000010  0.000010  0.000010  0.000010",
2711                        6 );
2712             m3.setRow( "0.010368  0.010368  0.031477  0.010375  0.010375  0.010375  0.010375  0.000000  0.010368  0.010368  0.010368  0.010368  0.010368  0.098591  0.745047  0.010375  0.010375  0.010375  0.010375  0.010375",
2713                        7 );
2714             m3.setRow( "0.000010  0.000010  0.020875  0.010376  0.010376  0.010376  0.010376  0.010368  0.000000  0.000010  0.000010  0.000010  0.000010  0.087165  0.743570  0.010376  0.010376  0.010376  0.010376  0.010376",
2715                        8 );
2716             m3.setRow( "0.000010  0.000010  0.020875  0.010376  0.010376  0.010376  0.010376  0.010368  0.000010  0.000000  0.000010  0.000010  0.000010  0.087165  0.743570  0.010376  0.010376  0.010376  0.010376  0.010376",
2717                        9 );
2718             m3.setRow( "0.000010  0.000010  0.020875  0.010376  0.010376  0.010376  0.010376  0.010368  0.000010  0.000010  0.000000  0.000010  0.000010  0.087165  0.743570  0.010376  0.010376  0.010376  0.010376  0.010376",
2719                        10 );
2720             m3.setRow( "0.000010  0.000010  0.020875  0.010376  0.010376  0.010376  0.010376  0.010368  0.000010  0.000010  0.000010  0.000000  0.000010  0.087165  0.743570  0.010376  0.010376  0.010376  0.010376  0.010376",
2721                        11 );
2722             m3.setRow( "0.000010  0.000010  0.020875  0.010376  0.010376  0.010376  0.010376  0.010368  0.000010  0.000010  0.000010  0.000010  0.000000  0.087165  0.743570  0.010376  0.010376  0.010376  0.010376  0.010376",
2723                        12 );
2724             m3.setRow( "0.087165  0.087165  0.096983  0.098678  0.098678  0.098678  0.098678  0.098591  0.087165  0.087165  0.087165  0.087165  0.087165  0.000000  0.720387  0.098678  0.098678  0.098678  0.098678  0.098678",
2725                        13 );
2726             m3.setRow( "0.743570  0.743570  0.768150  0.741282  0.741282  0.741282  0.741282  0.745047  0.743570  0.743570  0.743570  0.743570  0.743570  0.720387  0.000000  0.741282  0.741282  0.741282  0.741282  0.741282",
2727                        14 );
2728             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000010  0.000010  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000000  0.000010  0.000010  0.000010  0.000010",
2729                        15 );
2730             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000010  0.000010  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000000  0.000010  0.000010  0.000010",
2731                        16 );
2732             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000010  0.000010  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000010  0.000000  0.000010  0.000010",
2733                        17 );
2734             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000010  0.000010  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000010  0.000010  0.000000  0.000010",
2735                        18 );
2736             m3.setRow( "0.010376  0.010376  0.031503  0.000010  0.000010  0.000010  0.000010  0.010375  0.010376  0.010376  0.010376  0.010376  0.010376  0.098678  0.741282  0.000010  0.000010  0.000010  0.000010  0.000000",
2737                        19 );
2738             final NeighborJoiningR nj3 = NeighborJoiningR.createInstance( false, 6 );
2739             final Phylogeny p3 = nj3.execute( m3 );
2740             //Archaeopteryx.createApplication( p3 );
2741             ////
2742             final int size = 10;
2743             for( int n = 0; n <= 100; ++n ) {
2744                 final NeighborJoiningR njn = NeighborJoiningR.createInstance( false, 6 );
2745                 final BasicSymmetricalDistanceMatrix mt = new BasicSymmetricalDistanceMatrix( size );
2746                 mt.randomize( new Date().getTime() );
2747                 final long start_time = new Date().getTime();
2748                 njn.execute( mt );
2749                 System.out.println( "Size: " + size + " -> " + ( new Date().getTime() - start_time ) + "ms" );
2750             }
2751         }
2752         catch ( final Exception e ) {
2753             e.printStackTrace( System.out );
2754             return false;
2755         }
2756         return true;
2757     }
2758
2759     private static boolean testSymmetricalDistanceMatrixParser() {
2760         try {
2761             final String l = ForesterUtil.getLineSeparator();
2762             StringBuffer source = new StringBuffer();
2763             source.append( " 4" + l );
2764             source.append( "A 0 0 0 0" + l );
2765             source.append( "B 1 0 0 0" + l );
2766             source.append( "C 2 4 0 0" + l );
2767             source.append( "D 3 5 6 0" + l );
2768             source.append( l );
2769             source.append( " 4" + l );
2770             source.append( "A 0   11  12  13" + l );
2771             source.append( "B 11  0   14  15" + l );
2772             source.append( "C 12  14  0   16" + l );
2773             source.append( "D 13  15  16  0" + l );
2774             source.append( l );
2775             source.append( l );
2776             source.append( "     " + l );
2777             source.append( " 4" + l );
2778             source.append( " A        0     " + l );
2779             source.append( " B            21 0" + l );
2780             source.append( " C            22 24    0  " + l );
2781             source.append( " # 2 222 2 2 " + l );
2782             source.append( " D            23 25 26 0" + l );
2783             source.append( l );
2784             source.append( l );
2785             source.append( "     " + l );
2786             final SymmetricalDistanceMatrixParser p0 = SymmetricalDistanceMatrixParser.createInstance();
2787             final DistanceMatrix[] ma0 = p0.parse( source.toString() );
2788             if ( ma0.length != 3 ) {
2789                 return false;
2790             }
2791             if ( !isEqual( ma0[ 0 ].getValue( 0, 0 ), 0 ) ) {
2792                 return false;
2793             }
2794             if ( !isEqual( ma0[ 0 ].getValue( 1, 0 ), 1 ) ) {
2795                 return false;
2796             }
2797             if ( !isEqual( ma0[ 0 ].getValue( 2, 0 ), 2 ) ) {
2798                 return false;
2799             }
2800             if ( !isEqual( ma0[ 0 ].getValue( 3, 0 ), 3 ) ) {
2801                 return false;
2802             }
2803             if ( !isEqual( ma0[ 0 ].getValue( 0, 1 ), 1 ) ) {
2804                 return false;
2805             }
2806             if ( !isEqual( ma0[ 0 ].getValue( 1, 1 ), 0 ) ) {
2807                 return false;
2808             }
2809             if ( !isEqual( ma0[ 0 ].getValue( 2, 1 ), 4 ) ) {
2810                 return false;
2811             }
2812             if ( !isEqual( ma0[ 0 ].getValue( 3, 1 ), 5 ) ) {
2813                 return false;
2814             }
2815             if ( !isEqual( ma0[ 1 ].getValue( 0, 0 ), 0 ) ) {
2816                 return false;
2817             }
2818             if ( !isEqual( ma0[ 1 ].getValue( 1, 0 ), 11 ) ) {
2819                 return false;
2820             }
2821             if ( !isEqual( ma0[ 1 ].getValue( 2, 0 ), 12 ) ) {
2822                 return false;
2823             }
2824             if ( !isEqual( ma0[ 1 ].getValue( 3, 0 ), 13 ) ) {
2825                 return false;
2826             }
2827             if ( !isEqual( ma0[ 1 ].getValue( 0, 1 ), 11 ) ) {
2828                 return false;
2829             }
2830             if ( !isEqual( ma0[ 1 ].getValue( 1, 1 ), 0 ) ) {
2831                 return false;
2832             }
2833             if ( !isEqual( ma0[ 1 ].getValue( 2, 1 ), 14 ) ) {
2834                 return false;
2835             }
2836             if ( !isEqual( ma0[ 1 ].getValue( 3, 1 ), 15 ) ) {
2837                 return false;
2838             }
2839             if ( !isEqual( ma0[ 2 ].getValue( 0, 0 ), 0 ) ) {
2840                 return false;
2841             }
2842             if ( !isEqual( ma0[ 2 ].getValue( 1, 0 ), 21 ) ) {
2843                 return false;
2844             }
2845             if ( !isEqual( ma0[ 2 ].getValue( 2, 0 ), 22 ) ) {
2846                 return false;
2847             }
2848             if ( !isEqual( ma0[ 2 ].getValue( 3, 0 ), 23 ) ) {
2849                 return false;
2850             }
2851             if ( !isEqual( ma0[ 2 ].getValue( 0, 1 ), 21 ) ) {
2852                 return false;
2853             }
2854             if ( !isEqual( ma0[ 2 ].getValue( 1, 1 ), 0 ) ) {
2855                 return false;
2856             }
2857             if ( !isEqual( ma0[ 2 ].getValue( 2, 1 ), 24 ) ) {
2858                 return false;
2859             }
2860             if ( !isEqual( ma0[ 2 ].getValue( 3, 1 ), 25 ) ) {
2861                 return false;
2862             }
2863             source = new StringBuffer();
2864             source.append( "A 0 0 0 0" + l );
2865             source.append( "B 1 0 0 0" + l );
2866             source.append( "C 2 4 0 0" + l );
2867             source.append( "D 3 5 6 0" + l );
2868             source.append( " " + l );
2869             source.append( "A 0   11  12  13" + l );
2870             source.append( "B 11  0   14  15" + l );
2871             source.append( "C 12  14  0   16" + l );
2872             source.append( "D 13  15  16  0" + l );
2873             source.append( l );
2874             source.append( " A        0     " + l );
2875             source.append( " B            21 0" + l );
2876             source.append( " C            22 24    0  " + l );
2877             source.append( " # 2 222 2 2 " + l );
2878             source.append( " D            23 25 26 0" + l );
2879             final DistanceMatrix[] ma1 = p0.parse( source.toString() );
2880             if ( ma1.length != 3 ) {
2881                 return false;
2882             }
2883             if ( !isEqual( ma1[ 0 ].getValue( 0, 0 ), 0 ) ) {
2884                 return false;
2885             }
2886             if ( !isEqual( ma1[ 0 ].getValue( 1, 0 ), 1 ) ) {
2887                 return false;
2888             }
2889             if ( !isEqual( ma1[ 0 ].getValue( 2, 0 ), 2 ) ) {
2890                 return false;
2891             }
2892             if ( !isEqual( ma1[ 0 ].getValue( 3, 0 ), 3 ) ) {
2893                 return false;
2894             }
2895             if ( !isEqual( ma1[ 0 ].getValue( 0, 1 ), 1 ) ) {
2896                 return false;
2897             }
2898             if ( !isEqual( ma1[ 0 ].getValue( 1, 1 ), 0 ) ) {
2899                 return false;
2900             }
2901             if ( !isEqual( ma1[ 0 ].getValue( 2, 1 ), 4 ) ) {
2902                 return false;
2903             }
2904             if ( !isEqual( ma1[ 0 ].getValue( 3, 1 ), 5 ) ) {
2905                 return false;
2906             }
2907             if ( !isEqual( ma1[ 1 ].getValue( 0, 0 ), 0 ) ) {
2908                 return false;
2909             }
2910             if ( !isEqual( ma1[ 1 ].getValue( 1, 0 ), 11 ) ) {
2911                 return false;
2912             }
2913             if ( !isEqual( ma1[ 1 ].getValue( 2, 0 ), 12 ) ) {
2914                 return false;
2915             }
2916             if ( !isEqual( ma1[ 1 ].getValue( 3, 0 ), 13 ) ) {
2917                 return false;
2918             }
2919             if ( !isEqual( ma1[ 1 ].getValue( 0, 1 ), 11 ) ) {
2920                 return false;
2921             }
2922             if ( !isEqual( ma1[ 1 ].getValue( 1, 1 ), 0 ) ) {
2923                 return false;
2924             }
2925             if ( !isEqual( ma1[ 1 ].getValue( 2, 1 ), 14 ) ) {
2926                 return false;
2927             }
2928             if ( !isEqual( ma1[ 1 ].getValue( 3, 1 ), 15 ) ) {
2929                 return false;
2930             }
2931             if ( !isEqual( ma1[ 2 ].getValue( 0, 0 ), 0 ) ) {
2932                 return false;
2933             }
2934             if ( !isEqual( ma1[ 2 ].getValue( 1, 0 ), 21 ) ) {
2935                 return false;
2936             }
2937             if ( !isEqual( ma1[ 2 ].getValue( 2, 0 ), 22 ) ) {
2938                 return false;
2939             }
2940             if ( !isEqual( ma1[ 2 ].getValue( 3, 0 ), 23 ) ) {
2941                 return false;
2942             }
2943             if ( !isEqual( ma1[ 2 ].getValue( 0, 1 ), 21 ) ) {
2944                 return false;
2945             }
2946             if ( !isEqual( ma1[ 2 ].getValue( 1, 1 ), 0 ) ) {
2947                 return false;
2948             }
2949             if ( !isEqual( ma1[ 2 ].getValue( 2, 1 ), 24 ) ) {
2950                 return false;
2951             }
2952             if ( !isEqual( ma1[ 2 ].getValue( 3, 1 ), 25 ) ) {
2953                 return false;
2954             }
2955             source = new StringBuffer();
2956             source.append( "A 0" + l );
2957             source.append( "B 10 0" + l );
2958             final DistanceMatrix[] ma2 = p0.parse( source.toString() );
2959             if ( ma2.length != 1 ) {
2960                 return false;
2961             }
2962             if ( !isEqual( ma2[ 0 ].getValue( 0, 1 ), 10 ) ) {
2963                 return false;
2964             }
2965             source = new StringBuffer();
2966             source.append( " " + l );
2967             source.append( "#" + l );
2968             final DistanceMatrix[] ma3 = p0.parse( source.toString() );
2969             if ( ma3.length != 0 ) {
2970                 return false;
2971             }
2972             source = new StringBuffer();
2973             source.append( " " + l );
2974             source.append( "A 0   11  12  13" + l );
2975             source.append( "B     0   14  15" + l );
2976             source.append( "C         0   16" + l );
2977             source.append( "D              0" + l );
2978             source.append( l );
2979             source.append( "A 0 21  22  23" + l );
2980             source.append( "B 0 24  25" + l );
2981             source.append( "C 0 26" + l );
2982             source.append( "D 0" + l );
2983             p0.setInputMatrixType( SymmetricalDistanceMatrixParser.InputMatrixType.UPPER_TRIANGLE );
2984             final DistanceMatrix[] ma4 = p0.parse( source );
2985             if ( ma4.length != 2 ) {
2986                 return false;
2987             }
2988             if ( !isEqual( ma4[ 0 ].getValue( 0, 0 ), 0 ) ) {
2989                 return false;
2990             }
2991             if ( !isEqual( ma4[ 0 ].getValue( 1, 0 ), 11 ) ) {
2992                 return false;
2993             }
2994             if ( !isEqual( ma4[ 0 ].getValue( 2, 0 ), 12 ) ) {
2995                 return false;
2996             }
2997             if ( !isEqual( ma4[ 0 ].getValue( 3, 0 ), 13 ) ) {
2998                 return false;
2999             }
3000             if ( !isEqual( ma4[ 0 ].getValue( 0, 1 ), 11 ) ) {
3001                 return false;
3002             }
3003             if ( !isEqual( ma4[ 0 ].getValue( 1, 1 ), 0 ) ) {
3004                 return false;
3005             }
3006             if ( !isEqual( ma4[ 0 ].getValue( 2, 1 ), 14 ) ) {
3007                 return false;
3008             }
3009             if ( !isEqual( ma4[ 0 ].getValue( 3, 1 ), 15 ) ) {
3010                 return false;
3011             }
3012             if ( !isEqual( ma4[ 0 ].getValue( 0, 2 ), 12 ) ) {
3013                 return false;
3014             }
3015             if ( !isEqual( ma4[ 0 ].getValue( 1, 2 ), 14 ) ) {
3016                 return false;
3017             }
3018             if ( !isEqual( ma4[ 0 ].getValue( 2, 2 ), 0 ) ) {
3019                 return false;
3020             }
3021             if ( !isEqual( ma4[ 0 ].getValue( 3, 2 ), 16 ) ) {
3022                 return false;
3023             }
3024             if ( !isEqual( ma4[ 0 ].getValue( 0, 3 ), 13 ) ) {
3025                 return false;
3026             }
3027             if ( !isEqual( ma4[ 0 ].getValue( 1, 3 ), 15 ) ) {
3028                 return false;
3029             }
3030             if ( !isEqual( ma4[ 0 ].getValue( 2, 3 ), 16 ) ) {
3031                 return false;
3032             }
3033             if ( !isEqual( ma4[ 0 ].getValue( 3, 3 ), 0 ) ) {
3034                 return false;
3035             }
3036             source = new StringBuffer();
3037             source.append( " 4 " + l );
3038             source.append( "A 0   11  12  13" + l );
3039             source.append( "B     0   14  15" + l );
3040             source.append( "C         0   16" + l );
3041             source.append( "D              0" + l );
3042             source.append( " 4" + l );
3043             source.append( "A 0 21  22  23" + l );
3044             source.append( "B 0 24  25" + l );
3045             source.append( "C 0 26" + l );
3046             source.append( "D 0" + l );
3047             source.append( "     " + l );
3048             source.append( " 4" + l );
3049             source.append( "A 0 21  22  23" + l );
3050             source.append( "B 0 24  25" + l );
3051             source.append( "C 0 26" + l );
3052             source.append( "D 0" + l );
3053             source.append( l );
3054             source.append( "A 0 21  22  23" + l );
3055             source.append( "B 0 24  25" + l );
3056             source.append( "C 0 26" + l );
3057             source.append( "D 0" + l );
3058             p0.setInputMatrixType( SymmetricalDistanceMatrixParser.InputMatrixType.UPPER_TRIANGLE );
3059             final DistanceMatrix[] ma5 = p0.parse( source );
3060             if ( ma5.length != 4 ) {
3061                 return false;
3062             }
3063             if ( !isEqual( ma5[ 0 ].getValue( 0, 0 ), 0 ) ) {
3064                 return false;
3065             }
3066             if ( !isEqual( ma5[ 0 ].getValue( 1, 0 ), 11 ) ) {
3067                 return false;
3068             }
3069             if ( !isEqual( ma5[ 0 ].getValue( 2, 0 ), 12 ) ) {
3070                 return false;
3071             }
3072             if ( !isEqual( ma5[ 0 ].getValue( 3, 0 ), 13 ) ) {
3073                 return false;
3074             }
3075             if ( !isEqual( ma5[ 0 ].getValue( 0, 1 ), 11 ) ) {
3076                 return false;
3077             }
3078             if ( !isEqual( ma5[ 0 ].getValue( 1, 1 ), 0 ) ) {
3079                 return false;
3080             }
3081             if ( !isEqual( ma5[ 0 ].getValue( 2, 1 ), 14 ) ) {
3082                 return false;
3083             }
3084             if ( !isEqual( ma5[ 0 ].getValue( 3, 1 ), 15 ) ) {
3085                 return false;
3086             }
3087             if ( !isEqual( ma5[ 0 ].getValue( 0, 2 ), 12 ) ) {
3088                 return false;
3089             }
3090             if ( !isEqual( ma5[ 0 ].getValue( 1, 2 ), 14 ) ) {
3091                 return false;
3092             }
3093             if ( !isEqual( ma5[ 0 ].getValue( 2, 2 ), 0 ) ) {
3094                 return false;
3095             }
3096             if ( !isEqual( ma5[ 0 ].getValue( 3, 2 ), 16 ) ) {
3097                 return false;
3098             }
3099             if ( !isEqual( ma5[ 0 ].getValue( 0, 3 ), 13 ) ) {
3100                 return false;
3101             }
3102             if ( !isEqual( ma5[ 0 ].getValue( 1, 3 ), 15 ) ) {
3103                 return false;
3104             }
3105             if ( !isEqual( ma5[ 0 ].getValue( 2, 3 ), 16 ) ) {
3106                 return false;
3107             }
3108             if ( !isEqual( ma5[ 0 ].getValue( 3, 3 ), 0 ) ) {
3109                 return false;
3110             }
3111         }
3112         catch ( final Exception e ) {
3113             e.printStackTrace( System.out );
3114             return false;
3115         }
3116         return true;
3117     }
3118
3119     private static void timeNeighborJoining() {
3120         final NeighborJoiningR njr = NeighborJoiningR.createInstance();
3121         for( int n = 3; n <= 10; ++n ) {
3122             final int x = ( int ) Math.pow( 2, n );
3123             final BasicSymmetricalDistanceMatrix mt = new BasicSymmetricalDistanceMatrix( x );
3124             mt.randomize( new Date().getTime() );
3125             final long start_time = new Date().getTime();
3126             njr.execute( mt );
3127             System.out.println( "Size: " + x + " -> " + ( new Date().getTime() - start_time ) + "ms" );
3128         }
3129         final NeighborJoiningF njf = NeighborJoiningF.createInstance();
3130         for( int n = 3; n <= 10; ++n ) {
3131             final int x = ( int ) Math.pow( 2, n );
3132             final BasicSymmetricalDistanceMatrix mt = new BasicSymmetricalDistanceMatrix( x );
3133             mt.randomize( new Date().getTime() );
3134             final long start_time = new Date().getTime();
3135             njf.execute( mt );
3136             System.out.println( "Size: " + x + " -> " + ( new Date().getTime() - start_time ) + "ms" );
3137         }
3138         final NeighborJoining nj = NeighborJoining.createInstance();
3139         for( int n = 3; n <= 10; ++n ) {
3140             final int x = ( int ) Math.pow( 2, n );
3141             final BasicSymmetricalDistanceMatrix mt = new BasicSymmetricalDistanceMatrix( x );
3142             mt.randomize( new Date().getTime() );
3143             final long start_time = new Date().getTime();
3144             nj.execute( mt );
3145             System.out.println( "Size: " + x + " -> " + ( new Date().getTime() - start_time ) + "ms" );
3146         }
3147     }
3148 }