1 /*
2 
3 HyPhy - Hypothesis Testing Using Phylogenies.
4 
5 This file implements data and interface classes
6 used for linking HyPhy with MEGA
7 
8 Written by SL Kosakovsky Pond; June 2007
9 Dedicated to Comet (http://www.hyphy.org/comet.jpg)
10 ?/?/1999-06/05/2007
11 
12 Copyright (C) 1997-now
13 Core Developers:
14   Sergei L Kosakovsky Pond (sergeilkp@icloud.com)
15   Art FY Poon    (apoon42@uwo.ca)
16   Steven Weaver (sweaver@temple.edu)
17 
18 Module Developers:
19 	Lance Hepler (nlhepler@gmail.com)
20 	Martin Smith (martin.audacis@gmail.com)
21 
22 Significant contributions from:
23   Spencer V Muse (muse@stat.ncsu.edu)
24   Simon DW Frost (sdf22@cam.ac.uk)
25 
26 Permission is hereby granted, free of charge, to any person obtaining a
27 copy of this software and associated documentation files (the
28 "Software"), to deal in the Software without restriction, including
29 without limitation the rights to use, copy, modify, merge, publish,
30 distribute, sublicense, and/or sell copies of the Software, and to
31 permit persons to whom the Software is furnished to do so, subject to
32 the following conditions:
33 
34 The above copyright notice and this permission notice shall be included
35 in all copies or substantial portions of the Software.
36 
37 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
41 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
42 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
43 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44 
45 */
46 
47 
48 #include "THyPhy.h"
49 #include "batchlan.h"
50 #include "string.h"
51 
52 
53 /* declare some utility functions */
54 
55 void    ReadPreferences         (void);
56 void    ApplyPreferences        (void);
57 
58 /* global variables */
59 
60 _String _tHYPHYAskFor           ("_THyPhyAskFor"),
61         _tHYPHYNotHandled       ("_THyPhy_NOT_HANDLED_"),
62         _tHYPHYCurrentStatus;
63 
64 long    _tHYPHYDone             = 0;
65 double  _tHYPHYValue            = 0.0;
66 
67 extern long systemCPUCount;
68 
69 _THyPhy * globalInterfaceInstance = nil;
70 
71 //_________________________________________________________
72 // default callback hanlder
_tHyPhyDefaultHandler(const char *,int,double)73 bool _tHyPhyDefaultHandler (const char*,int,double)
74 {
75     return true;
76 }
77 
78 //_________________________________________________________
79 // default callback hanlder
80 //void SetGlobalInterfaceInstance (const _THyPhy* hi)
81 //{
82 //  globalInterfaceInstance = hi;
83 //}
84 
85 
86 /* Basic return types supported by the interface object */
87 
88 //_________________________________________________________
castToString(void)89 _THyPhyString* _THyPhyReturnObject::castToString(void)
90 {
91     if (myType() == THYPHY_TYPE_STRING) {
92         return (_THyPhyString*)this;
93     }
94     return NULL;
95 }
96 
97 //_________________________________________________________
castToNumber(void)98 _THyPhyNumber* _THyPhyReturnObject::castToNumber(void)
99 {
100     if (myType() == THYPHY_TYPE_NUMBER) {
101         return (_THyPhyNumber*)this;
102     }
103     return NULL;
104 }
105 
106 //_________________________________________________________
castToMatrix(void)107 _THyPhyMatrix* _THyPhyReturnObject::castToMatrix(void)
108 {
109     if (myType() == THYPHY_TYPE_MATRIX) {
110         return (_THyPhyMatrix*)this;
111     }
112     return NULL;
113 }
114 
115 
116 //_________________________________________________________
_THyPhyString(const char * characters,long length)117 _THyPhyString::_THyPhyString(const char* characters, long length)
118 {
119     if (characters) {
120         if (length == 0) {
121             while (characters[length++]) ;
122             length --;
123         }
124         checkPointer (sData = (char*)MemAllocate (length+1));
125         memcpy       (sData,characters,length+1);
126 
127     } else {
128         sData   = nil;
129     }
130     sLength = length;
131 }
132 
133 //_________________________________________________________
~_THyPhyString(void)134 _THyPhyString::~_THyPhyString(void)
135 {
136     if (sData) {
137         free (sData);
138     }
139 };
140 
141 //_________________________________________________________
_THyPhyNumber(double v)142 _THyPhyNumber::_THyPhyNumber(double v)
143 {
144     nValue = v;
145 }
146 
147 
148 //_________________________________________________________
_THyPhyMatrix(void)149 _THyPhyMatrix::_THyPhyMatrix(void)
150 {
151     mData = nil;
152     mRows = 0;
153     mCols = 0;
154 }
155 
156 //_________________________________________________________
_THyPhyMatrix(const long r,const long c,const double * d)157 _THyPhyMatrix::_THyPhyMatrix(const long r, const long c, const double* d)
158 {
159     checkPointer (mData = (double*)MemAllocate (r*c*sizeof(double)));
160     mRows = r;
161     mCols = c;
162     for (long i = 0; i < r*c; i++,d++) {
163         mData[i] = *d;
164     }
165 
166 }
167 
168 //_________________________________________________________
~_THyPhyMatrix(void)169 _THyPhyMatrix::~_THyPhyMatrix(void)
170 {
171     if (mData) {
172         free (mData);
173     }
174 };
175 
176 //_________________________________________________________
MatrixCell(long r,long c)177 double _THyPhyMatrix::MatrixCell(long r, long c)
178 {
179     return mData[mCols*r+c];
180 }
181 
182 //_________________________________________________________
183 // Begin _THyPhy definitions
184 //_________________________________________________________
185 
_THyPhy(_ProgressCancelHandler * mHandler,const char * baseDirPath,long cpuCount)186 _THyPhy::_THyPhy(_ProgressCancelHandler* mHandler, const char* baseDirPath, long cpuCount)
187 {
188     InitTHyPhy (mHandler, baseDirPath, cpuCount);
189 }
190 
191 //_________________________________________________________
192 
193 
_THyPhy(const char * baseDirPath,long cpuCount)194 _THyPhy::_THyPhy(const char* baseDirPath, long cpuCount)
195 {
196     InitTHyPhy (_tHyPhyDefaultHandler, baseDirPath, cpuCount);
197 }
198 
199 //_________________________________________________________
200 
~_THyPhy(void)201 _THyPhy::~_THyPhy           (void)
202 {
203     if (currentResultHolder) {
204         delete (_THyPhyReturnObject*)currentResultHolder;
205     }
206     if (baseDirectoryInstance) {
207         delete (baseDirectoryInstance);
208     }
209     ClearAll();
210     DeleteObject        ((_String*)errors);
211     DeleteObject        ((_String*)warnings);
212     DeleteObject        ((_String*)textout);
213     if (globalInterfaceInstance == this) {
214         globalInterfaceInstance = nil;
215     }
216 
217     PurgeAll(true);
218     GlobalShutdown();
219 }
220 
221 //_________________________________________________________
222 
InitTHyPhy(_ProgressCancelHandler * mHandler,const char * baseDirPath,long cpuCount)223 void _THyPhy::InitTHyPhy (_ProgressCancelHandler* mHandler, const char* baseDirPath, long cpuCount)
224 {
225     char dirSlash = GetPlatformDirectoryChar ();
226     systemCPUCount = cpuCount;
227     SetCallbackHandler (mHandler);
228     checkPointer (currentResultHolder = new _THyPhyString);
229     askFID = -1;
230     if (baseDirPath)
231         // set base directory
232     {
233         baseDirectory = baseDirPath;
234         if (baseDirectory.getChar(baseDirectory.sLength-1) != dirSlash) {
235             baseDirectory = baseDirectory & dirSlash;
236         }
237         baseDirectoryInstance = new _THyPhyString (baseDirectory.sData);
238         baseDirectory = baseDirectoryInstance->sData;
239         pathNames && &baseDirectory;
240         ReadPreferences ();
241     }
242 
243 #ifdef _HYPHY_LIBDIRECTORY_
244     libDirectory = _HYPHY_LIBDIRECTORY_;
245     if (libDirectory.getChar(libDirectory.sLength-1) != dirSlash) {
246         libDirectory = libDirectory & dirSlash;
247     }
248 #else
249     if (baseDirectory)
250         libDirectory = baseDirectory;
251 #endif
252 
253     pathNames && &libDirectory;
254     GlobalStartup();
255     errors   = nil;
256     warnings = nil;
257     textout  = nil;
258     globalInterfaceInstance = this;
259 
260 }
261 
262 //_________________________________________________________
263 
ExecuteBF(const char * buffer,bool doPurge)264 _THyPhyString * _THyPhy::ExecuteBF (const char * buffer, bool doPurge)
265 {
266     if (doPurge) {
267         PurgeAll            (true);    // cleanup results of previous analysis
268     }
269 
270     _String             dd (GetPlatformDirectoryChar());
271 
272     _FString            bp  (baseDirectory, false),
273                         lp  (libDirectory, false),
274                         ds  (dd),
275                         cfp (pathNames.lLength?*(_String*)pathNames(pathNames.lLength-1):empty),
276                         * stashed = (_FString*)FetchObjectFromVariableByType (&pathToCurrentBF, STRING);
277 
278     setParameter        (platformDirectorySeparator, &ds);
279     setParameter        (hyphyBaseDirectory, &bp);
280     setParameter        (hyphyLibDirectory, &lp);
281 
282     if (stashed) {
283         stashed = (_FString*)stashed->makeDynamic();
284     }
285     setParameter        (pathToCurrentBF,&cfp);
286 
287     _String             commandString (buffer);
288 
289     if (commandString.beginswith ("#NEXUS"),false) {
290         lastNexusDataMatrix = ReadDataSetFile (nil, 2, &commandString);
291         commandString = nexusBFBody;
292     }
293 
294     _ExecutionList      compiledCode  (commandString);
295 
296     if (doPurge) {
297       ApplyPreferences    ();
298     }
299 
300     DeleteObject        ((_String*)errors);
301     DeleteObject        ((_String*)warnings);
302     DeleteObject        ((_String*)textout);
303 
304     errors              = new _String (128L,true);
305     warnings            = new _String (128L,true);
306     textout             = new _String (128L,true);
307 
308     askFID              = compiledCode.ExecuteAndClean (0x7ffffff,&_tHYPHYAskFor);
309     _PMathObj bfReturn  = compiledCode.GetResult ();
310 
311     ((_String*)errors)->Finalize();
312     ((_String*)warnings)->Finalize();
313     ((_String*)textout)->Finalize();
314 
315     if (currentResultHolder->sData) {
316         free (currentResultHolder->sData);
317         currentResultHolder->sData = nil;
318     }
319     if (bfReturn) {
320         _String * serializedReturn   = (_String*) bfReturn->toStr();
321         currentResultHolder->sData   = serializedReturn->sData;
322         serializedReturn->sData      = nil;
323         currentResultHolder->sLength = serializedReturn->sLength;
324     }
325     return currentResultHolder;
326 }
327 
328 //_________________________________________________________
329 
ClearAll(void)330 void _THyPhy::ClearAll (void)
331 {
332     PurgeAll(true);
333 }
334 
335 //_________________________________________________________
336 
AskFor(const char * resultID)337 void* _THyPhy::AskFor (const char* resultID)
338 {
339     if (resultID && askFID >= 0) {
340         _String theCommand (128L,true);
341         theCommand << "return ";
342         theCommand <<  _tHYPHYAskFor;
343         theCommand << "(\"";
344         theCommand.EscapeAndAppend (resultID);
345         theCommand << "\");";
346         theCommand.Finalize();
347         _ExecutionList      compiledCode  (theCommand);
348         compiledCode.ExecuteAndClean (0x7ffffff);
349         _PMathObj retResult = compiledCode.GetResult ();
350         if (retResult && retResult->ObjectClass() == STRING) {
351             _FString * checkHandled = (_FString*)retResult;
352             if (checkHandled->theString->Equal (&_tHYPHYNotHandled)) {
353                 return nil;
354             }
355         }
356         return retResult->makeDynamic();
357     }
358     return nil;
359 }
360 
361 //_________________________________________________________
362 
DumpResult(void * aResult)363 void _THyPhy::DumpResult (void* aResult)
364 {
365     if (aResult) {
366         DeleteObject ((BaseRef)aResult);
367     }
368 }
369 
370 //_________________________________________________________
371 
SetCallbackHandler(_ProgressCancelHandler * newHandler)372 void _THyPhy::SetCallbackHandler (_ProgressCancelHandler* newHandler)
373 {
374     theHandler = newHandler;
375 }
376 
377 //_________________________________________________________
378 
GetCallbackHandler(void)379 _ProgressCancelHandler* _THyPhy::GetCallbackHandler (void)
380 {
381     return theHandler;
382 }
383 
384 //_________________________________________________________
385 
PushWarning(void * o)386 void        _THyPhy::PushWarning (void * o)
387 {
388     if (warnings) {
389         *((_String*)warnings) << *(_String*)o;
390     }
391 }
392 
393 //_________________________________________________________
394 
PushError(void * o)395 void        _THyPhy::PushError (void * o)
396 {
397     if (errors) {
398         *((_String*)errors) << *(_String*)o;
399     }
400 }
401 
402 //_________________________________________________________
403 
PushOutString(void * o)404 void        _THyPhy::PushOutString (void * o)
405 {
406     if (textout) {
407         *((_String*)textout) << *(_String*)o;
408     }
409 }
410 
411 //_________________________________________________________
412 
ConvertHyPhyString(void * o)413 _THyPhyString   * _THyPhy::ConvertHyPhyString (void * o)
414 {
415     return new _THyPhyString (((_String*)o)->sData,((_String*)o)->sLength);
416 }
417 
418 //_________________________________________________________
419 
CanCast(const void * theObject,const int requestedType)420 bool _THyPhy::CanCast (const void* theObject, const int requestedType)
421 {
422     if (theObject) {
423         switch (((_PMathObj)theObject)->ObjectClass()) {
424         case NUMBER:
425             return true;
426             // can cast a number to everything
427         case STRING:
428             return requestedType!=THYPHY_TYPE_MATRIX;
429             // can cast anything to a string
430         case MATRIX:
431             return requestedType!=THYPHY_TYPE_NUMBER;
432             // can not cast matrix to number
433 
434         case TREE:
435         case TOPOLOGY:
436             return requestedType==THYPHY_TYPE_STRING;
437 
438         }
439     }
440     return false;
441 }
442 
443 //_________________________________________________________
444 
CastResult(const void * theObject,const int requestedType)445 _THyPhyReturnObject* _THyPhy::CastResult (const void* theObject, const int requestedType)
446 {
447     _THyPhyReturnObject * convertedObject = nil;
448     if (CanCast(theObject,requestedType)) {
449         int hyphyObjClass = ((_PMathObj)theObject)->ObjectClass();
450         switch (hyphyObjClass) {
451         case NUMBER: {
452             if (hyphyObjClass == NUMBER) {
453                 return new _THyPhyNumber (((_PMathObj)theObject)->Compute()->Value());
454             }
455             if (hyphyObjClass == STRING) {
456                 _String sV ((_String*)((_FString*)theObject)->toStr());
457                 return new _THyPhyNumber (sV.toNum());
458             }
459         }
460         case STRING: {
461             _String sV ((_String*)((_PMathObj)theObject)->toStr());
462             return new _THyPhyString (sV.sData,sV.sLength);
463         }
464         case MATRIX: {
465             if (hyphyObjClass == NUMBER) {
466                 double evaluate = ((_PMathObj)theObject)->Compute()->Value();
467                 return new _THyPhyMatrix (1,1,&evaluate);
468             }
469 
470             if (hyphyObjClass == MATRIX) {
471                 _Matrix * evalutedNumeric =  (_Matrix*)((_Matrix*)(((_PMathObj)theObject)->Compute()))
472                                              ->ComputeNumeric();
473 
474                 return new _THyPhyMatrix (evalutedNumeric->GetHDim(),evalutedNumeric->GetVDim(),evalutedNumeric->theData);
475             }
476         }
477         }
478     }
479 
480     return convertedObject;
481 }
482 
483 //_________________________________________________________________________
484 
SetStatusLine(_String arg)485 void    SetStatusLine (_String arg)
486 {
487     _tHYPHYCurrentStatus = arg;
488     yieldCPUTime();
489 }
490 
491 //_________________________________________________________________________
492 
SetStatusBarValue(long l,_Parameter max,_Parameter rate)493 void    SetStatusBarValue (long l,_Parameter max, _Parameter rate)
494 {
495     _tHYPHYDone = l;
496     _tHYPHYCurrentStatus   = _String ("LF Optimization. Value=") & _String (max) &", "&_String (rate) & " evals/sec.";
497     _tHYPHYValue = max;
498     yieldCPUTime();
499 }
500 
501 //_________________________________________________________________________
502 
_THyPhyGetLongStatus(void)503 long    _THyPhyGetLongStatus        (void)
504 {
505     return _tHYPHYDone;
506 }
507 
508 //_________________________________________________________________________
509 
_THyPhyGetDoubleStatus(void)510 double  _THyPhyGetDoubleStatus      (void)
511 {
512     return _tHYPHYValue;
513 }
514 
515 //_________________________________________________________________________
516 
_THyPhyGetStringStatus(void)517 const char*   _THyPhyGetStringStatus      (void)
518 {
519     return _tHYPHYCurrentStatus.getStr();
520 }
521