source: branches/stable/GDE/PHYLIP/factor.c

Last change on this file was 2175, checked in by westram, 20 years ago

upgrade to PHYLIP 3.6

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1
2#include "phylip.h"
3
4/* version 3.6. (c) Copyright 1988-2002 by the University of Washington.
5   A program to factor multistate character trees.
6   Originally version 29 May 1983 by C. A. Meacham, Botany Department,
7     University of Georgia
8   Additional code by Joe Felsenstein, 1988-1991
9   C version code by Akiko Fuseki, Sean Lamont, and Andrew Keeffe.
10   Permission is granted to copy and use this program provided no fee is
11   charged for it and provided that this copyright notice is not removed. */
12
13#define maxstates       20   /* Maximum number of states in multi chars      */
14#define maxoutput       80   /* Maximum length of output line                */
15#define sizearray       5000 /* Size of symbarray; must be >= the sum of     */
16                             /* squares of the number of states in each multi*/
17                             /* char to be factored                          */
18#define factchar        ':'  /* character to indicate state connections      */
19#define unkchar         '?'  /* input character to indicate state unknown    */
20
21typedef struct statenode {     /* Node of multifurcating tree */
22  struct statenode *ancstr, *sibling, *descendant;
23  Char state;             /* Symbol of character state   */
24  long edge;             /* Number of subtending edge   */
25} statenode;
26
27#ifndef OLDC
28/* function prototypes */
29void   getoptions(void);
30void   nextch(Char *ch);
31void   readtree(void);
32void   attachnodes(statenode *, Char *);
33void   maketree(statenode *, Char *);
34void   construct(void);
35void   numberedges(statenode *, long *);
36void   factortree(void);
37void   dotrees(void);
38void   writech(Char ch, long *);
39void   writefactors(long *);
40void   writeancestor(long *);
41void   doeu(long *, long);
42void   dodatamatrix(void);
43/* function prototypes */
44#endif
45
46
47Char infilename[FNMLNGTH], outfilename[FNMLNGTH];
48long neus, nchars, charindex, lastindex;
49Char ch;
50boolean ancstrrequest, factorrequest, rooted, progress;
51Char symbarray[sizearray];
52 /* Holds multi symbols and their factored equivs        */
53long *charnum;     /* Multis           */
54long *chstart;     /* Position of each */
55long *numstates;   /* Number of states */
56Char  *ancsymbol;   /* Ancestral state  */
57
58/*  local variables for dotrees, propagated to global level. */
59  long npairs, offset, charnumber, nstates;
60  statenode *root;
61  Char pair[maxstates][2];
62  statenode *nodes[maxstates];
63
64
65void getoptions()
66{
67  /* interactively set options */
68  Char ch;
69
70  ibmpc = IBMCRT;
71  ansi = ANSICRT;
72  progress = true;
73  factorrequest = false;
74  ancstrrequest = false;
75  putchar('\n');
76  for (;;){
77    printf(ansi ? "\033[2J\033[H" : "\n");
78    printf("\nFactor -- multistate to binary recoding program, version %s\n\n"
79           ,VERSION);
80    printf("Settings for this run:\n");
81    printf("  A      put ancestral states in output file?  %s\n",
82           ancstrrequest ? "Yes" : "No");
83    printf("  F   put factors information in output file?  %s\n",
84           factorrequest ? "Yes" : "No");
85    printf("  0       Terminal type (IBM PC, ANSI, none)?  %s\n",
86           ibmpc ? "IBM PC" : ansi  ? "ANSI" : "(none)");
87    printf("  1      Print indications of progress of run  %s\n",
88           (progress ? "Yes" : "No"));
89    printf("\nAre these settings correct? (type Y or the letter for one to change)\n");
90#ifdef WIN32
91    phyFillScreenColor();
92#endif
93    scanf("%c%*[^\n]", &ch);
94    getchar();
95    uppercase(&ch);
96    if (ch == 'Y')
97      break;
98    if (strchr("AF01", ch) != NULL) {
99      switch (ch) {
100       
101      case 'A':
102        ancstrrequest = !ancstrrequest;
103        break;
104       
105      case 'F':
106        factorrequest = !factorrequest;
107        break;
108       
109      case '0':
110        initterminal(&ibmpc, &ansi);
111        break;
112
113      case '1':
114        progress = !progress;
115      break;
116      }
117    } else
118      printf("Not a possible option!\n");
119  }
120}  /* getoptions */
121
122
123void nextch(Char *ch)
124{
125  *ch = ' ';
126  while (*ch == ' ' && !eoln(infile))
127    *ch = gettc(infile);
128}  /* nextch */
129
130
131void readtree()
132{
133  /* Reads a single character-state tree; puts adjacent symbol
134     pairs into array 'pairs' */
135
136  npairs = 0;
137  while (!eoln(infile)) {
138    nextch(&ch);
139    if (eoln(infile))
140      break;
141    npairs++;
142    pair[npairs - 1][0] = ch;
143    nextch(&ch);
144    if (eoln(infile) || (ch != factchar)) {
145      printf("\n\nERROR: Character %ld:  bad character state tree format\n\n",
146             charnumber);
147      exxit(-1);}
148
149    nextch(&pair[npairs - 1][1]);
150    if (eoln(infile) && pair[npairs - 1][1] == ' '){
151      printf("\n\nERROR: Character %ld:  bad character state tree format\n\n",
152             charnumber);
153      exxit(-1);}
154  }
155  scan_eoln(infile);
156}  /* readtree */
157
158
159void attachnodes(statenode *poynter, Char *otherone)
160{
161  /* Makes linked list of all nodes to which passed node is
162     ancestral.  First such node is 'descendant'; second
163     such node is 'sibling' of first; third such node is
164     sibling of second; etc.  */
165  statenode *linker, *ptr;
166  long i, j, k;
167
168  linker = poynter;
169  for (i = 0; i < (npairs); i++) {
170    for (j = 1; j <= 2; j++) {
171      if (poynter->state == pair[i][j - 1]) {
172            if (j == 1)
173              *otherone = pair[i][1];
174            else
175              *otherone = pair[i][0];
176            if (*otherone != '.' && *otherone != poynter->ancstr->state) {
177              k = offset + 1;
178              while (*otherone != symbarray[k - 1])
179                k++;
180              if (nodes[k - offset - 1] != NULL)
181                exxit(-1);
182              ptr = (statenode *)Malloc(sizeof(statenode));
183              ptr->ancstr = poynter;
184              ptr->descendant = NULL;
185              ptr->sibling = NULL;
186              ptr->state = *otherone;
187              if (linker == poynter)   /* If not first */
188                poynter->descendant = ptr;   /* If first */
189              else
190                linker->sibling = ptr;
191              nodes[k - offset - 1] = ptr;
192              /* Save pntr to node */
193              linker = ptr;
194            }
195      }
196    }
197  }
198}  /* attachnodes */
199
200
201void maketree(statenode *poynter, Char *otherone)
202{
203  /* Recursively attach nodes */
204  if (poynter == NULL)
205    return;
206  attachnodes(poynter, otherone);
207  maketree(poynter->descendant, otherone);
208  maketree(poynter->sibling, otherone);
209}  /* maketree */
210
211
212void construct()
213{
214  /* Puts tree together from array 'pairs' */
215  Char rootstate;
216  long i, j, k;
217  boolean done;
218  statenode *poynter;
219  char otherone;
220
221  rooted = false;
222  ancsymbol[charindex - 1] = '?';
223  rootstate = pair[0][0];
224  nstates = 0;
225  for (i = 0; i < (npairs); i++) {
226    for (j = 1; j <= 2; j++) {
227      k = 1;
228      done = false;
229      while (!done) {
230        if (k > nstates) {
231          done = true;
232          break;
233        }
234        if (pair[i][j - 1] == symbarray[offset + k - 1])
235          done = true;
236        else
237          k++;
238      }
239      if (k > nstates) {
240        if (pair[i][j - 1] == '.') {
241          if (rooted)
242            exxit(-1);
243          rooted = true;
244          ancsymbol[charindex - 1] = '0';
245          if (j == 1)
246            rootstate = pair[i][1];
247          else
248            rootstate = pair[i][0];
249        } else {
250          nstates++;
251          symbarray[offset + nstates - 1] = pair[i][j - 1];
252        }
253      }
254    }
255  }
256  if ((rooted && nstates != npairs) ||
257      (!rooted && nstates != npairs + 1))
258    exxit(-1);
259  root = (statenode *)Malloc(sizeof(statenode));
260  root->state = ' ';
261  root->descendant = (statenode *)Malloc(sizeof(statenode));
262  root->descendant->ancstr = root;
263  root = root->descendant;
264  root->descendant = NULL;
265  root->sibling = NULL;
266  root->state = rootstate;
267  for (i = 0; i < (nstates); i++)
268    nodes[i] = NULL;
269  i = 1;
270  while (symbarray[offset + i - 1] != rootstate)
271    i++;
272  nodes[i - 1] = root;
273  maketree(root, &otherone);
274  for (i = 0; i < (nstates); i++) {
275    if (nodes[i] != root) {
276      if (nodes[i] == NULL){
277        printf(
278        "\n\nERROR: Character %ld: invalid character state tree description\n",
279               charnumber);
280        exxit(-1);}
281      else {
282        poynter = nodes[i]->ancstr;
283        while (poynter != root && poynter != nodes[i])
284          poynter = poynter->ancstr;
285        if (poynter != root){
286          printf(
287          "ERROR: Character %ld: invalid character state tree description\n\n",
288                 charnumber);
289          exxit(-1);}
290      }
291    }
292  }
293}  /* construct */
294
295
296void numberedges(statenode *poynter, long *edgenum)
297{
298  /* Assign to each node a number for the edge below it.
299     The root is zero */
300  if (poynter == NULL)
301    return;
302  poynter->edge = *edgenum;
303  (*edgenum)++;
304  numberedges(poynter->descendant, edgenum);
305  numberedges(poynter->sibling, edgenum);
306}  /* numberedges */
307
308
309void factortree()
310{
311  /* Generate the string of 0's and 1's that will be
312     substituted for each symbol of the multistate char. */
313  long i, j, place, factoroffset;
314  statenode *poynter;
315  long edgenum=0;
316
317  numberedges(root, &edgenum);
318  factoroffset = offset + nstates;
319  for (i = 0; i < (nstates); i++) {
320    place = factoroffset + (nstates - 1) * i;
321    for (j = place; j <= (place + nstates - 2); j++)
322      symbarray[j] = '0';
323    poynter = nodes[i];
324    while (poynter != root) {
325      symbarray[place + poynter->edge - 1] = '1';
326      poynter = poynter->ancstr;
327    }
328  }
329}  /* factortree */
330
331
332void dotrees()
333{
334  /* Process character-state trees */
335  long lastchar;
336
337  charindex = 0;
338  lastchar = 0;
339  offset = 0;
340  charnumber = 0;
341  fscanf(infile, "%ld", &charnumber);
342  while (charnumber < 999) {
343    if (charnumber < lastchar) {
344      printf("\n\nERROR: Character state tree");
345      printf(" for character %ld: out of order\n\n", charnumber);
346      exxit(-1);
347    }
348    charindex++;
349    lastindex = charindex;
350    readtree();   /* Process character-state tree  */
351    if (npairs > 0) {
352      construct();   /* Link tree together  */
353      factortree();
354    } else {
355      nstates = 0;
356      ancsymbol[charindex - 1] = '?';
357    }
358    lastchar = charnumber;
359    charnum[charindex - 1] = charnumber;
360    chstart[charindex - 1] = offset;
361    numstates[charindex - 1] = nstates;
362    offset += nstates * nstates;
363    fscanf(infile, "%ld", &charnumber);
364  }
365  scan_eoln(infile);
366  /*    each multistate character */
367  /*    symbol  */
368}  /* dotrees */
369
370
371void writech(Char ch, long *chposition)
372{
373  /* Writes a single character to output */
374  if (*chposition > maxoutput) {
375    putc('\n', outfile);
376    *chposition = 1;
377  }
378  putc(ch, outfile);
379  (*chposition)++;
380}  /* writech */
381
382
383void writefactors(long *chposition)
384{  /* Writes 'FACTORS' line */
385
386  long i, charindex;
387  Char symbol;
388
389  fprintf(outfile, "FACTORS   ");
390  *chposition = 11;
391  symbol = '-';
392  for (charindex = 0; charindex < (lastindex); charindex++) {
393    if (symbol == '-')
394      symbol = '+';
395    else
396      symbol = '-';
397    if (numstates[charindex] == 0)
398      writech(symbol, chposition);
399    else {
400      for (i = 1; i < (numstates[charindex]); i++)
401        writech(symbol, chposition);
402    }
403  }
404  putc('\n', outfile);
405}  /* writefactors */
406
407
408void writeancestor(long *chposition)
409{
410  /* Writes 'ANCESTOR' line */
411  long i, charindex;
412
413  charindex = 1;
414  while (ancsymbol[charindex - 1] == '?')
415    charindex++;
416  if (charindex > lastindex)
417    return;
418  fprintf(outfile, "ANCESTOR  ");
419  *chposition = 11;
420  for (charindex = 0; charindex < (lastindex); charindex++) {
421    if (numstates[charindex] == 0)
422      writech(ancsymbol[charindex], chposition);
423    else {
424      for (i = 1; i < (numstates[charindex]); i++)
425        writech(ancsymbol[charindex], chposition);
426    }
427  }
428  putc('\n', outfile);
429}  /* writeancestor */
430
431
432void doeu(long *chposition, long eu)
433{
434  /* Writes factored data for a single species  */
435  long i, charindex, place;
436  Char *multichar;
437
438  for (i = 1; i <= nmlngth; i++) {
439    ch = gettc(infile);
440    putc(ch, outfile);
441    if ((ch == '(') || (ch == ')') || (ch == ':')
442        || (ch == ',') || (ch == ';') || (ch == '[')
443        || (ch == ']')) {
444      printf(
445        "\n\nERROR: Species name may not contain characters ( ) : ; , [ ] \n");
446      printf("       In name of species number %ld there is character %c\n\n",
447              i+1, ch);
448      exxit(-1);
449    }
450  }
451  multichar = (Char *)Malloc(nchars*sizeof(Char));
452  *chposition = 11;
453  for (i = 0; i < (nchars); i++) {
454    do {
455      if (eoln(infile))
456        scan_eoln(infile);
457      ch = gettc(infile);
458    } while (ch == ' ');
459    multichar[i] = ch;
460  }
461  scan_eoln(infile);
462  for (charindex = 0; charindex < (lastindex); charindex++) {
463    if (numstates[charindex] == 0)
464      writech(multichar[charnum[charindex] - 1], chposition);
465    else {
466      i = 1;
467      while (symbarray[chstart[charindex] + i - 1] !=
468             multichar[charnum[charindex] - 1] && i <= numstates[charindex])
469        i++;
470      if (i > numstates[charindex]) {
471        if( multichar[charnum[charindex] - 1] == unkchar){
472          for (i = 1; i < (numstates[charindex]); i++)
473            writech('?', chposition);
474        } else {
475          putc('\n', outfile);
476          printf("\n\nERROR: In species %ld, multistate character %ld:  ",
477                 eu, charnum[charindex]);
478          printf("'%c' is not a documented state\n\n",
479                 multichar[charnum[charindex] - 1]);
480          exxit(-1);
481        }
482      } else {
483        place = chstart[charindex] + numstates[charindex] +
484                (numstates[charindex] - 1) * (i - 1);
485        for (i = 0; i <= (numstates[charindex] - 2); i++)
486          writech(symbarray[place + i], chposition);
487      }
488    }
489  }
490  putc('\n', outfile);
491  free(multichar);
492}  /* doeu */
493
494
495void dodatamatrix()
496{
497  /* Reads species information and write factored data set */
498  long charindex, totalfactors, eu, chposition;
499
500  totalfactors = 0;
501  for (charindex = 0; charindex < (lastindex); charindex++) {
502    if (numstates[charindex] == 0)
503      totalfactors++;
504    else
505      totalfactors += numstates[charindex] - 1;
506  }
507  if (rooted && ancstrrequest)
508    fprintf(outfile, "%5ld %4ld    A\n", neus + 1, totalfactors);
509  else
510    fprintf(outfile, "%5ld %4ld\n", neus, totalfactors);
511  if (factorrequest)
512    writefactors(&chposition);
513  if (ancstrrequest)
514    writeancestor(&chposition);
515  eu = 1;
516  while (eu <= neus) {
517    eu++;
518    doeu(&chposition, eu);
519  }
520  if (progress)
521    printf("\nData matrix written on file \"%s\"\n\n", outfilename);
522}  /* dodatamatrix */
523
524
525int main(int argc, Char *argv[])
526{
527#ifdef MAC
528  argc = 1;                /* macsetup("Factor","");        */
529  argv[0] = "Factor";
530#endif
531  init(argc,argv);
532  openfile(&infile,INFILE,"input file", "r",argv[0],infilename);
533  openfile(&outfile,OUTFILE,"output file", "w",argv[0],outfilename);
534
535  getoptions();
536  fscanf(infile, "%ld%ld%*[^\n]", &neus, &nchars);
537  gettc(infile);
538  charnum = (long *)Malloc(nchars*sizeof(long));
539  chstart = (long *)Malloc(nchars*sizeof(long));
540  numstates = (long *)Malloc(nchars*sizeof(long));
541  ancsymbol = (Char *)Malloc(nchars*sizeof(Char));
542  dotrees();   /* Read and factor character-state trees */
543  dodatamatrix();
544  FClose(infile);
545  FClose(outfile);
546#ifdef MAC
547  fixmacfile(outfilename);
548#endif
549  printf("Done.\n\n");
550#ifdef WIN32
551  phyRestoreConsoleAttributes();
552#endif
553  return 0;
554}  /* factor */
Note: See TracBrowser for help on using the repository browser.