//******************************************************************************
//
// File: DnaSequence.java
// Package: edu.rit.compbio.phyl
// Unit: Class edu.rit.compbio.phyl.DnaSequence
//
// This Java source file is copyright (C) 2008 by Alan Kaminsky. All rights
// reserved. For further information, contact the author, Alan Kaminsky, at
// ark@cs.rit.edu.
//
// This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
// software; you can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// PJ is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// A copy of the GNU General Public License is provided in the file gpl.txt. You
// may also obtain a copy of the GNU General Public License on the World Wide
// Web at http://www.gnu.org/licenses/gpl.html.
//
//******************************************************************************
package edu.rit.compbio.phyl;
/**
* Class DnaSequence encapsulates a DNA sequence. The DNA sequence consists of a
* sequence of sites. Each site has a state, which is a set of
* bases. The four bases are adenine, cytosine, guanine, and thymine. For
* textual I/O, each state is represented by a single character as follows:
*
*
* Char.
* Meaning
* Set
* A
* Adenine
* (A)
* C
* Cytosine
* (C)
* G
* Guanine
* (G)
* T
* Thymine
* (T)
* Y
* pYrimidine
* (C or T)
* R
* puRine
* (A or G)
* W
* "Weak"
* (A or T)
* S
* "Strong"
* (C or G)
* K
* "Keto"
* (G or T)
* M
* "aMino"
* (A or C)
* B
* not A
* (C or G or T)
* D
* not C
* (A or G or T)
* H
* not G
* (A or C or T)
* V
* not T
* (A or C or G)
* X
* unknown
* (A or C or G or T)
* -
* deletion
* ()
*
*
* The DNA sequence has an associated score, an integer. The score can be
* set to anything and later retrieved.
*
* The DNA sequence has a name, a string. The name can be set to anything
* and later retrieved.
*
* @author Alan Kaminsky
* @version 23-Jul-2008
*/
public class DnaSequence
{
// Hidden constants.
// Amount of extra padding in byte array.
private static final int PAD = 128;
// Mapping from the state of a site to the corresponding output character.
// A=1, C=2, G=4, T=8.
static final char[] state2char = new char[]
{/*----*/ '-',
/*---A*/ 'A',
/*--C-*/ 'C',
/*--CA*/ 'M',
/*-G--*/ 'G',
/*-G-A*/ 'R',
/*-GC-*/ 'S',
/*-GCA*/ 'V',
/*T---*/ 'T',
/*T--A*/ 'W',
/*T-C-*/ 'Y',
/*T-CA*/ 'H',
/*TG--*/ 'K',
/*TG-A*/ 'D',
/*TGC-*/ 'B',
/*TGCA*/ 'X'};
// Mapping from the state of a site to the number of bits turned on at that
// site. A=1, C=2, G=4, T=8.
static final int[] state2bitCount = new int[]
{/*----*/ 0,
/*---A*/ 1,
/*--C-*/ 1,
/*--CA*/ 2,
/*-G--*/ 1,
/*-G-A*/ 2,
/*-GC-*/ 2,
/*-GCA*/ 3,
/*T---*/ 1,
/*T--A*/ 2,
/*T-C-*/ 2,
/*T-CA*/ 3,
/*TG--*/ 2,
/*TG-A*/ 3,
/*TGC-*/ 3,
/*TGCA*/ 4};
// Hidden data members.
// Sequence data. Each site's set of bases is stored as a bitmap in one
// byte. A=1, C=2, G=4, T=8. PAD bytes of padding are added to avert cache
// interference.
byte[] mySites;
// Length.
int myLength;
// Score.
int myScore;
// Name.
String myName;
// 128 bytes of extra padding to avert cache interference.
private transient long p0, p1, p2, p3, p4, p5, p6, p7;
private transient long p8, p9, pa, pb, pc, pd, pe, pf;
// Exported constructors.
/**
* Construct a new zero-length DNA sequence. The score is initially 0. The
* name is initially null.
*/
public DnaSequence()
{
this (0, 0, null);
}
/**
* Construct a new DNA sequence with the given length. The score is
* initially 0. The name is initially null.
*
* @param N Length (number of sites).
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if N < 0.
*/
public DnaSequence
(int N)
{
this (N, 0, null);
}
/**
* Construct a new DNA sequence with the given length and score. The name is
* initially null.
*
* @param N Length (number of sites).
* @param score Score.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if N < 0.
*/
public DnaSequence
(int N,
int score)
{
this (N, score, null);
}
/**
* Construct a new DNA sequence with the given length, score, and name.
*
* @param N Length (number of sites).
* @param score Score.
* @param name Name. May be null.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if N < 0.
*/
public DnaSequence
(int N,
int score,
String name)
{
if (N < 0)
{
throw new IllegalArgumentException
("DnaSequence(): N (= "+N+") < 0, illegal)");
}
this.mySites = new byte [N+PAD];
this.myLength = N;
this.myScore = score;
this.myName = name;
}
/**
* Construct a new DNA sequence that is a copy of the given DNA sequence.
*
* @param seq DNA sequence to copy.
*
* @exception NullPointerException
* (unchecked exception) Thrown if seq is null.
*/
public DnaSequence
(DnaSequence seq)
{
this.mySites = (byte[]) seq.mySites.clone();
this.myLength = seq.myLength;
this.myScore = seq.myScore;
this.myName = seq.myName;
}
// Exported operations.
/**
* Get this DNA sequence's length.
*
* @return Length (number of sites).
*/
public int length()
{
return myLength;
}
/**
* Get this DNA sequence's score.
*
* @return Score.
*/
public int score()
{
return myScore;
}
/**
* Set this DNA sequence's score.
*
* @param score Score.
*/
public void score
(int score)
{
myScore = score;
}
/**
* Get this DNA sequence's name.
*
* @return Name. May be null.
*/
public String name()
{
return myName;
}
/**
* Set this DNA sequence's name.
*
* @param name Name. May be null.
*/
public void name
(String name)
{
myName = name;
}
/**
* Make this DNA sequence's sites be the same as the given DNA sequence. It
* is assumed that this DNA sequence and the given DNA sequence are the same
* length. This DNA sequence's score and name are unchanged.
*
* @param seq DNA sequence to copy.
*
* @exception NullPointerException
* (unchecked exception) Thrown if seq is null.
*/
public void copySites
(DnaSequence seq)
{
System.arraycopy (seq.mySites, 0, this.mySites, 0, myLength);
}
/**
* Compute the distance between this DNA sequence and the given DNA
* sequence. It is assumed that this DNA sequence and the given DNA sequence
* are the same length. The distance is the number of differing sites
* between the two sequences (the Hamming distance).
*
* @param seq DNA sequence.
*
* @return Distance.
*/
public double distance
(DnaSequence seq)
{
byte[] site1 = this.mySites;
byte[] site2 = seq.mySites;
int diff = 0;
int N = myLength;
for (int i = 0; i < N; ++ i)
{
if (site1[i] != site2[i]) ++ diff;
}
return diff;
}
/**
* Make this DNA sequence be the ancestor of the two given DNA sequences in
* the Fitch parsimony score algorithm. This DNA sequence's sites are set
* based on seq1's and seq2's sites. It is assumed that
* this DNA sequence and the given DNA sequences are the same length. This
* DNA sequence's score is set to the sum of seq1's score,
* seq2's score, and the number of state changes at the ancestor.
* This DNA sequence's name is unchanged.
*
* @param seq1 First child DNA sequence.
* @param seq2 Second child DNA sequence.
*/
public void setFitchAncestor
(DnaSequence seq1,
DnaSequence seq2)
{
// Get references to sites.
byte[] ancestor = this.mySites;
byte[] descendent1 = seq1.mySites;
byte[] descendent2 = seq2.mySites;
int N = myLength;
// Process all sites. Count state changes.
int nChanges = 0;
for (int i = 0; i < N; ++ i)
{
// Compute intersection of states.
int state1 = descendent1[i];
int state2 = descendent2[i];
int state3 = state1 & state2;
// If intersection is not empty, record intersection, otherwise
// record union and note one state change.
if (state3 == 0)
{
state3 = state1 | state2;
++ nChanges;
}
// Update site.
ancestor[i] = (byte) state3;
}
// Record number of state changes.
this.myScore = seq1.myScore + seq2.myScore + nChanges;
}
/**
* Returns a string version of this DNA sequence. The string consists of
* just the sequence of states (the score and name are not included).
*/
public String toString()
{
StringBuilder buf = new StringBuilder();
byte[] site = mySites;
int N = myLength;
for (int i = 0; i < N; ++ i)
{
buf.append (state2char [site[i]]);
}
return buf.toString();
}
}
Ads help maintain this website.