~ubuntu-branches/ubuntu/quantal/clustalo/quantal

« back to all changes in this revision

Viewing changes to src/clustal/symmatrix.c

  • Committer: Package Import Robot
  • Author(s): Olivier Sallou
  • Date: 2011-12-14 11:21:56 UTC
  • Revision ID: package-import@ubuntu.com-20111214112156-y3chwm0t4yn2nevm
Tags: upstream-1.0.3
ImportĀ upstreamĀ versionĀ 1.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; tab-width: 4; c-basic-offset: 4;  indent-tabs-mode: nil -*- */
 
2
 
 
3
/*********************************************************************
 
4
 * Clustal Omega - Multiple sequence alignment
 
5
 *
 
6
 * Copyright (C) 2010 University College Dublin
 
7
 *
 
8
 * Clustal-Omega is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License as
 
10
 * published by the Free Software Foundation; either version 2 of the
 
11
 * License, or (at your option) any later version.
 
12
 *
 
13
 * This file is part of Clustal-Omega.
 
14
 *
 
15
 ********************************************************************/
 
16
 
 
17
/*
 
18
 *  RCS $Id: symmatrix.c 230 2011-04-09 15:37:50Z andreas $
 
19
 *
 
20
 *
 
21
 * Functions for symmetric (square) matrices including diagonal.
 
22
 * supports the notion of non-square sub-matrices of a symmetric
 
23
 * matrix, i.e. where |rows|<|cols|.
 
24
 *
 
25
 * FIXME Allocating one big chunk of memory is probably
 
26
 * much faster and also easier to maintain.
 
27
 */
 
28
 
 
29
#ifdef HAVE_CONFIG_H
 
30
#include "config.h"
 
31
#endif
 
32
 
 
33
#include <stdlib.h>
 
34
#include <stdio.h>
 
35
#include <ctype.h>
 
36
#include <string.h>
 
37
#include <assert.h>
 
38
#include "symmatrix.h"
 
39
 
 
40
 
 
41
#if 0
 
42
#define DEBUG
 
43
#endif
 
44
 
 
45
#define MAX_BUF_SIZE 65536
 
46
 
 
47
/**
 
48
 * @brief Allocates symmat and its members and initialises them. Data
 
49
 * will be calloced, i.e. initialised with zeros.
 
50
 *
 
51
 * @param[out] symmat
 
52
 * newly allocated and initialised symmatrix instance
 
53
 * @param[in] nrows
 
54
 * number of rows
 
55
 * @param[in]
 
56
 * ncols number of columns
 
57
 *
 
58
 * @return: non-zero on error
 
59
 *
 
60
 * @see FreeSymMatrix()
 
61
 *
 
62
 * @note: symmat data will be of fake shape nrows x ncols
 
63
 *
 
64
 */
 
65
int
 
66
NewSymMatrix(symmatrix_t **symmat, int nrows, int ncols)
 
67
{
 
68
    int i; /* aux */
 
69
    
 
70
    assert(nrows>0 && ncols>0 && ncols>=nrows);
 
71
    assert(ncols>0 && ncols>=nrows);
 
72
 
 
73
    (*symmat) = (symmatrix_t *) malloc(1*sizeof(symmatrix_t));
 
74
    if (NULL == (*symmat)) {
 
75
        fprintf(stderr, "Couldn't allocate memory (%s|%s)\n",
 
76
                __FILE__, __FUNCTION__);
 
77
        return -1;
 
78
    }
 
79
    
 
80
    (*symmat)->data = (double **) malloc(nrows * sizeof(double *));
 
81
    if (NULL == (*symmat)->data) {
 
82
        fprintf(stderr, "Couldn't allocate memory (%s|%s)\n",
 
83
                __FILE__, __FUNCTION__);
 
84
        free(*symmat);
 
85
        *symmat = NULL;
 
86
        return -1;
 
87
    }
 
88
    for (i=0; i<nrows; i++) {
 
89
        (*symmat)->data[i] = (double *) calloc((ncols-i), sizeof(double));
 
90
        if (NULL == (*symmat)->data[i]) {
 
91
            fprintf(stderr, "Couldn't allocate memory (%s|%s)\n",
 
92
                    __FILE__, __FUNCTION__); 
 
93
            while (0!=--i) {
 
94
                free((*symmat)->data[i]);
 
95
            }           
 
96
            free((*symmat)->data);
 
97
            free(*symmat);
 
98
            *symmat = NULL;
 
99
            return -1;
 
100
        }
 
101
#ifdef TRACE
 
102
        fprintf(stderr, "DEBUG(%s|%s():%d) initialising symmat with the number of the beast\n",
 
103
                __FILE__, __FUNCTION__, __LINE__);
 
104
        {
 
105
            int j;
 
106
            for (j=0; j<ncols-i; j++) {
 
107
                (*symmat)->data[i][j] = -666.0;
 
108
            }
 
109
 
 
110
        }
 
111
#endif
 
112
    }
 
113
    
 
114
    (*symmat)->nrows = nrows;
 
115
    (*symmat)->ncols = ncols;
 
116
 
 
117
    return 0;
 
118
}
 
119
/***   end: new_symmatrix   ***/
 
120
 
 
121
 
 
122
/**
 
123
 * @brief Sets symmat data of given index to given value
 
124
 *
 
125
 * @param[in] symmat
 
126
 * symmatrix_t whose data is to be set
 
127
 * @param[in] i
 
128
 * first index 
 
129
 * @param[in] j
 
130
 * second index 
 
131
 * @param[in] value
 
132
 * value used to set data point
 
133
 *
 
134
 * @see SymMatrixGetValue()
 
135
 *
 
136
 * @note This is a convenience function that checks index order.
 
137
 *
 
138
 */
 
139
void
 
140
SymMatrixSetValue(symmatrix_t *symmat, const int i, const int j, const double value)
 
141
{
 
142
    assert(NULL != symmat);
 
143
 
 
144
    if (i<=j) {
 
145
        assert(i < symmat->nrows && j < symmat->ncols);
 
146
        symmat->data[i][j-i] = value;
 
147
    } else {
 
148
        assert(j < symmat->nrows && i < symmat->ncols);
 
149
        symmat->data[j][i-j] = value;
 
150
    }
 
151
}
 
152
/***   end: symmatrix_setvalue   ***/
 
153
 
 
154
 
 
155
 
 
156
/**
 
157
 * @brief Returns element of symmat corresponding to given indices
 
158
 *
 
159
 * @param[in] symmat
 
160
 * symmatrix_t of question
 
161
 * @param[in] i
 
162
 * index i
 
163
 * @param[in] j
 
164
 * index j
 
165
 *
 
166
 * @return requested value
 
167
 *
 
168
 * @see SymMatrixSetValue()
 
169
 *
 
170
 * @note This is a convenience function that checks index order.
 
171
 */
 
172
double
 
173
SymMatrixGetValue(symmatrix_t *symmat, const int i, const int j)
 
174
{
 
175
    assert(NULL != symmat);
 
176
 
 
177
    if (i<=j) {
 
178
        assert(i < symmat->nrows && j < symmat->ncols);
 
179
        return symmat->data[i][j-i];
 
180
    } else {
 
181
        assert(j < symmat->nrows && i < symmat->ncols);
 
182
        return symmat->data[j][i-j];
 
183
    }
 
184
}
 
185
/***   end: symmatrix_getvalue   ***/
 
186
 
 
187
 
 
188
 
 
189
 
 
190
 
 
191
/**
 
192
 * @brief Returns a pointer to an element of symmat corresponding to
 
193
 * given indices
 
194
 *
 
195
 * @param[out] val
 
196
 * Value to be set
 
197
 * @param[in] symmat
 
198
 * symmatrix_t of question
 
199
 * @param[in] i
 
200
 * index i
 
201
 * @param[in] j
 
202
 * index j
 
203
 *
 
204
 * @return pointer to value
 
205
 *
 
206
 * @see SymMatrixGetValue()
 
207
 *
 
208
 * @note This is a convenience function that checks index order.
 
209
 *
 
210
 */
 
211
void
 
212
SymMatrixGetValueP(double **val, symmatrix_t *symmat,
 
213
                   const int i, const int j)
 
214
{
 
215
    assert(NULL != symmat);
 
216
    
 
217
    if (i<=j) {
 
218
        assert(i < symmat->nrows && j < symmat->ncols);
 
219
        *val = &(symmat->data[i][j-i]);
 
220
    } else {
 
221
        assert(j < symmat->nrows && i < symmat->ncols);
 
222
        *val = &(symmat->data[j][i-j]);
 
223
    }
 
224
}
 
225
/***   end: symmatrix_getvaluep   ***/
 
226
 
 
227
 
 
228
/**
 
229
 * @brief Frees memory allocated by data members of symmat and symmat
 
230
 * itself. 
 
231
 *
 
232
 * @param[in] symmat
 
233
 * symmatrix_t to be freed
 
234
 *
 
235
 * @note Use in conjunction with NewSymMatrix()
 
236
 *
 
237
 * @see NewSymMatrix()
 
238
 *
 
239
 */
 
240
void
 
241
FreeSymMatrix(symmatrix_t **symmat)
 
242
{
 
243
    int i;
 
244
    if (NULL != (*symmat)) {
 
245
        if (NULL != (*symmat)->data) {
 
246
            for (i=0; i<(*symmat)->nrows; i++) {
 
247
                free((*symmat)->data[i]);
 
248
            }
 
249
            free((*symmat)->data);
 
250
        }
 
251
    }
 
252
    free(*symmat);
 
253
    *symmat = NULL;
 
254
}
 
255
/***   end: free_symmatrix   ***/
 
256
 
 
257
 
 
258
 
 
259
/**
 
260
 * @brief Print out a symmat in phylip style. Distances are printed on
 
261
 * one line per sequence/object. Since we also support matrices with
 
262
 * rows\<cols, the first line can also be nrows by ncolumns instead
 
263
 * of just nrows
 
264
 *
 
265
 * @param[in] symmat
 
266
 * the symmatrix_t to print
 
267
 * @param[in] labels
 
268
 * sequence/objects labels/names. must be at least of length symmat nrows
 
269
 * @param[in] path
 
270
 * filename or NULL. If NULL stdout will be used.
 
271
 *
 
272
 */
 
273
void
 
274
SymMatrixPrint(symmatrix_t *symmat, char **labels,  const char *path)
 
275
{
 
276
    FILE *fp = NULL;
 
277
    int i, j; /* aux */
 
278
    int max_label_len = 0;
 
279
    
 
280
    if (NULL==symmat || NULL==labels) {
 
281
        fprintf(stderr,
 
282
                "One of the provided arguments is empty or NULL (print_matrix)\n");
 
283
        return;
 
284
    }
 
285
    if (NULL==path) {
 
286
        fp = stdout;
 
287
    } else {
 
288
        if (NULL==(fp=fopen(path, "w"))) {
 
289
            fprintf(stderr, "Couldn't open %s for writing.", path);
 
290
            return;
 
291
        }
 
292
    }
 
293
 
 
294
    /* find maximum label length for pretty printing
 
295
     */
 
296
    for (i=0; i<symmat->nrows; i++) {
 
297
        int this_len;
 
298
        assert(NULL != labels[i]);
 
299
        this_len = strlen(labels[i]);
 
300
        if (this_len>max_label_len)
 
301
            max_label_len = this_len;
 
302
    }
 
303
 
 
304
    if (symmat->ncols==symmat->nrows) {
 
305
        fprintf(fp, "%u\n", symmat->ncols);
 
306
    } else {
 
307
        /* this is not standard phylip, but necessary to indicate
 
308
           seed matrices */
 
309
        fprintf(fp, "%u x %u\n", symmat->nrows, symmat->ncols);
 
310
    }
 
311
    for (i=0; i<symmat->nrows; i++) {
 
312
        /* phylip restriction is 10 characters. we don't care here
 
313
         */
 
314
        fprintf(fp, "%-*s", max_label_len, labels[i]);
 
315
        /* we are lazy and do it like fastdist: write all distances
 
316
         *  for one seq to one line
 
317
         */
 
318
        for (j=0; j<symmat->ncols; j++) {
 
319
            fprintf(fp, " %f", SymMatrixGetValue(symmat, i, j));
 
320
        }
 
321
        fprintf(fp, "%s", "\n");
 
322
    }
 
323
    if (NULL != path) {
 
324
        (void) fclose(fp);
 
325
    } else {
 
326
        (void) fflush(fp);
 
327
    }
 
328
}
 
329
/***   end: SymMatrixPrint   ***/
 
330
 
 
331
 
 
332
 
 
333
/**
 
334
 *
 
335
 * @brief Read a distance matrix in phylip format
 
336
 *
 
337
 * @param[in] pcFileIn
 
338
 * distance matrix filename 
 
339
 * @param[out] prSymMat_p
 
340
 * the symmatrix_t. will be allocated here.
 
341
 * @return:
 
342
 * non-zero on error
 
343
 *
 
344
 * @note:
 
345
 * FIXME untested code
 
346
 */
 
347
int
 
348
SymMatrixRead(char *pcFileIn, symmatrix_t **prSymMat_p)
 
349
{    
 
350
    FILE *prFilePointer;
 
351
    char *buf;
 
352
    /* number of parsed sequences */
 
353
    int iNParsedSeq = 0; 
 
354
    /* number of parsed distances per sequence */
 
355
    int iNParsedDists = 0;
 
356
    /* total number of sequences/objects */
 
357
    int iTotalNSeq = 0; 
 
358
    int iRetCode = 0;
 
359
 
 
360
    assert(NULL!=pcFileIn);
 
361
 
 
362
    /* FIXME: test correctness and implement label checking */
 
363
    fprintf(stderr, "WARNING: Reading of distance matrix from file not thoroughly tested!\n");
 
364
    fprintf(stderr, "WARNING: Assuming same order of sequences in sequence file and distance matrix file (matching of labels not implemented)\n");
 
365
 
 
366
    if (NULL == (buf = (char *) malloc(MAX_BUF_SIZE * sizeof(char)))) {
 
367
        fprintf(stderr, "ERROR: couldn't allocate memory at %s:%s:%d\n",
 
368
                __FILE__, __FUNCTION__, __LINE__);
 
369
        return -1;
 
370
    }
 
371
    
 
372
    if (NULL == (prFilePointer = fopen(pcFileIn, "r"))) {
 
373
        fprintf(stderr, "ERROR: Couldn't open %s for reading\n", pcFileIn);
 
374
        free(buf);
 
375
        return -1;
 
376
    }
 
377
    
 
378
    /* get number of sequences from first line and allocate memory for
 
379
     * distance matrix
 
380
     *
 
381
     */
 
382
    if (NULL == fgets(buf, MAX_BUF_SIZE, prFilePointer) ) {
 
383
        fprintf(stderr, "Couldn't read first line from %s\n", pcFileIn);
 
384
        iRetCode = -1;
 
385
        goto closefile_and_freebuf;
 
386
    }
 
387
    if (strlen(buf)==MAX_BUF_SIZE-1) {
 
388
        fprintf(stderr, "%s\n", "Looks like I couldn't read complete line. Wrong format (or too small MAX_BUF_SIZE)");
 
389
        iRetCode = -1;
 
390
        goto closefile_and_freebuf;
 
391
    }
 
392
    if (sscanf(buf, "%d", &iTotalNSeq)!=1) {
 
393
        fprintf(stderr, "ERROR: couldn't parse number of sequences from first line of %s\n", pcFileIn); 
 
394
        iRetCode = -1;
 
395
        goto closefile_and_freebuf;
 
396
    }
 
397
 
 
398
#if TRACE
 
399
    Log(&rLog, LOG_FORCED_DEBUG, "iTotalNSeq parsed from %s is %d\n", pcFileIn, iTotalNSeq);
 
400
#endif
 
401
    
 
402
    if (NewSymMatrix(prSymMat_p, iTotalNSeq, iTotalNSeq)) {
 
403
        fprintf(stderr, "FATAL %s", "Memory allocation for distance matrix failed");
 
404
        iRetCode = -1;
 
405
        goto closefile_and_freebuf;
 
406
    }
 
407
 
 
408
 
 
409
    /* parse file line by line
 
410
     *
 
411
     */
 
412
    while (NULL != fgets(buf, MAX_BUF_SIZE, prFilePointer)) {
 
413
        char *szToken;
 
414
        int is_newseq;
 
415
 
 
416
        if (MAX_BUF_SIZE-1 == strlen(buf)) {
 
417
            fprintf(stderr, "%s\n", "Looks like I couldn't read complete line. Wrong format (or too small MAX_BUF_SIZE)");
 
418
            iRetCode = -1;
 
419
            goto closefile_and_freebuf;
 
420
        }
 
421
 
 
422
#ifdef DEBUG
 
423
        Log(&rLog, LOG_FORCED_DEBUG, "Got line: %s\n", buf);
 
424
#endif
 
425
 
 
426
        /* new sequence label at beginning of line?
 
427
         */
 
428
        if (isblank(buf[0])) {
 
429
            is_newseq = 0;
 
430
        } else {
 
431
            is_newseq = 1;
 
432
        }
 
433
 
 
434
        /* tokenise line and treat new sequence specially
 
435
         */
 
436
        szToken = strtok(buf, " \t");
 
437
        if (is_newseq==1) {
 
438
            iNParsedSeq++;
 
439
            iNParsedDists=0;
 
440
 
 
441
            /* if format is lower dimensional matrix then first
 
442
             * sequence has no distances but might have newline
 
443
             * character at it's end.
 
444
             */
 
445
            while (isspace(szToken[strlen(szToken)-1])) {
 
446
                szToken[strlen(szToken)-1]='\0';
 
447
            }
 
448
            /* FIXME save label? */
 
449
            szToken = strtok(NULL, " \t");
 
450
        }
 
451
        /* from here on it's only parsing of distances */
 
452
        while (szToken != NULL) {
 
453
            double dist;
 
454
            iNParsedDists++;
 
455
 
 
456
            /* only parse what's needed */
 
457
            if (iNParsedDists!=iNParsedSeq) {
 
458
                /* parse and store distance
 
459
                 */
 
460
                if (sscanf(szToken, "%lf", &dist)!=1) {
 
461
                    fprintf(stderr, "Couldn't parse float from entry '%s'\n", szToken);
 
462
                    iRetCode = -1;
 
463
                    goto closefile_and_freebuf;
 
464
                }
 
465
#if TRACE
 
466
                Log(&rLog, LOG_FORCED_DEBUG, "Parsed distance %d for seq %d = %f\n", iNParsedDists-1, iNParsedSeq-1, dist);
 
467
#endif
 
468
                SymMatrixSetValue(*prSymMat_p, iNParsedSeq-1, iNParsedDists-1, dist);
 
469
                SymMatrixSetValue(*prSymMat_p, iNParsedDists-1, iNParsedSeq-1, dist);
 
470
            }
 
471
            szToken = strtok(NULL, " \t");
 
472
        }        
 
473
    }
 
474
 
 
475
    if (iTotalNSeq!=iNParsedSeq) {
 
476
        fprintf(stderr, "expected %d seqs, but only parsed %d\n", iTotalNSeq, iNParsedSeq);
 
477
        iRetCode = -1;
 
478
        goto closefile_and_freebuf;
 
479
    }
 
480
#if TRACE
 
481
    for (i=0; i<iNParsedSeq; i++) {
 
482
        int j;
 
483
        for (j=0; j<iNParsedSeq; j++) {
 
484
            Log(&rLog, LOG_FORCED_DEBUG, "prSymMat_p[%d][%d]=%f\n", i, j, (*prSymMat_p)[i][j]);
 
485
        }
 
486
    }
 
487
#endif
 
488
 
 
489
closefile_and_freebuf:
 
490
    fclose(prFilePointer);
 
491
    free(buf);
 
492
    
 
493
    return iRetCode;
 
494
}
 
495
/***   end: SymMatrixRead   ***/
 
496