1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright 2015 M. Rizky Luthfianto.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use ndarray;

lazy_static! {
    // taken from https://github.com/seqan/seqan/blob/master/include%2Fseqan%2Fscore%2
    // Fscore_matrix_data.h#L614
    // Copyright (c) 2006-2015, Knut Reinert, FU Berlin
    static ref MAT: ndarray::Array2<i32> = ndarray::Array::from_shape_vec((27, 27), vec![
         3,  0, -3,  0,  0, -4,  1, -3, -1, -2, -2, -3, -2, -1, -1,  1, -1, -3,  1,  1, -1,  0,
        -7, -4, -1, -1, -8,
         0,  4, -6,  4,  3, -5,  0,  1, -3, -4,  0, -4, -4,  3, -1, -2,  0, -2,  0,  0, -1, -3,
        -6, -3,  2, -1, -8,
        -3, -6,  9, -7, -7, -6, -4, -4, -3, -5, -7, -7, -6, -5, -4, -4, -7, -4,  0, -3, -4, -3,
        -8, -1, -7, -4, -8,
         0,  4, -7,  5,  3, -7,  0,  0, -3, -4, -1, -5, -4,  2, -2, -3,  1, -3,  0, -1, -2, -3,
        -8, -5,  3, -2, -8,
         0,  3, -7,  3,  5, -7, -1, -1, -3, -4, -1, -4, -3,  1, -1, -2,  2, -3, -1, -2, -1, -3,
        -8, -5,  4, -1, -8,
        -4, -5, -6, -7, -7,  8, -5, -3,  0,  0, -7,  0, -1, -4, -3, -5, -6, -5, -3, -4, -3, -3,
        -1,  4, -6, -3, -8,
         1,  0, -4,  0, -1, -5,  5, -4, -4, -5, -3, -5, -4,  0, -2, -2, -3, -4,  1, -1, -2, -2,
        -8, -6, -2, -2, -8,
        -3,  1, -4,  0, -1, -3, -4,  7, -4, -4, -2, -3, -4,  2, -2, -1,  3,  1, -2, -3, -2, -3,
        -3, -1,  1, -2, -8,
        -1, -3, -3, -3, -3,  0, -4, -4,  6,  4, -3,  1,  1, -2, -1, -3, -3, -2, -2,  0, -1,  3,
        -6, -2, -3, -1, -8,
        -2, -4, -5, -4, -4,  0, -5, -4,  4,  4, -4,  3,  2, -3, -2, -3, -3, -3, -3, -2, -2,  2,
        -5, -2, -3, -2, -8,
        -2,  0, -7, -1, -1, -7, -3, -2, -3, -4,  5, -4,  0,  1, -2, -2,  0,  2, -1, -1, -2, -4,
        -5, -5, -1, -2, -8,
        -3, -4, -7, -5, -4,  0, -5, -3,  1,  3, -4,  5,  3, -4, -2, -3, -2, -4, -4, -3, -2,  1,
        -3, -2, -3, -2, -8,
        -2, -4, -6, -4, -3, -1, -4, -4,  1,  2,  0,  3,  8, -3, -2, -3, -1, -1, -2, -1, -2,  1,
        -6, -4, -2, -2, -8,
        -1,  3, -5,  2,  1, -4,  0,  2, -2, -3,  1, -4, -3,  4, -1, -2,  0, -1,  1,  0, -1, -3,
        -4, -2,  0, -1, -8,
        -1, -1, -4, -2, -1, -3, -2, -2, -1, -2, -2, -2, -2, -1, -2, -2, -1, -2, -1, -1, -2, -1,
        -5, -3, -1, -2, -8,
         1, -2, -4, -3, -2, -5, -2, -1, -3, -3, -2, -3, -3, -2, -2,  6,  0, -1,  1, -1, -2, -2,
        -7, -6, -1, -2, -8,
        -1,  0, -7,  1,  2, -6, -3,  3, -3, -3,  0, -2, -1,  0, -1,  0,  6,  1, -2, -2, -1, -3,
        -6, -5,  4, -1, -8,
        -3, -2, -4, -3, -3, -5, -4,  1, -2, -3,  2, -4, -1, -1, -2, -1,  1,  6, -1, -2, -2, -3,
         1, -5, -1, -2, -8,
         1,  0,  0,  0, -1, -3,  1, -2, -2, -3, -1, -4, -2,  1, -1,  1, -2, -1,  3,  2, -1, -2,
        -2, -3, -1, -1, -8,
         1,  0, -3, -1, -2, -4, -1, -3,  0, -2, -1, -3, -1,  0, -1, -1, -2, -2,  2,  4, -1,  0,
        -6, -3, -2, -1, -8,
        -1, -1, -4, -2, -1, -3, -2, -2, -1, -2, -2, -2, -2, -1, -2, -2, -1, -2, -1, -1, -2, -1,
        -5, -3, -1, -2, -8,
         0, -3, -3, -3, -3, -3, -2, -3,  3,  2, -4,  1,  1, -3, -1, -2, -3, -3, -2,  0, -1,  5,
        -8, -3, -3, -1, -8,
        -7, -6, -8, -8, -8, -1, -8, -3, -6, -5, -5, -3, -6, -4, -5, -7, -6,  1, -2, -6, -5, -8,
        12, -2, -7, -5, -8,
        -4, -3, -1, -5, -5,  4, -6, -1, -2, -2, -5, -2, -4, -2, -3, -6, -5, -5, -3, -3, -3, -3,
        -2,  8, -5, -3, -8,
        -1,  2, -7,  3,  4, -6, -2,  1, -3, -3, -1, -3, -2,  0, -1, -1,  4, -1, -1, -2, -1, -3,
        -7, -5,  4, -1, -8,
        -1, -1, -4, -2, -1, -3, -2, -2, -1, -2, -2, -2, -2, -1, -2, -2, -1, -2, -1, -1, -2, -1,
        -5, -3, -1, -2, -8,
        -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, -8,
        -8, -8, -8, -8,  1
    ]).unwrap();
}

#[inline]
fn lookup(a: u8) -> usize {
    if a == b'Y' {
        23 as usize
    } else if a == b'Z' {
        24 as usize
    } else if a == b'X' {
        25 as usize
    } else if a == b'*' {
        26 as usize
    } else {
        (a - 65) as usize
    }
}

pub fn pam120(a: u8, b: u8) -> i32 {
    let a = lookup(a);
    let b = lookup(b);

    MAT[(a, b)]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_pam120() {
        let score1 = pam120(b'A', b'A');
        assert_eq!(score1, 3);
        let score2 = pam120(b'*', b'*');
        assert_eq!(score2, 1);
        let score3 = pam120(b'A', b'*');
        assert_eq!(score3, -8);
        let score4 = pam120(b'*', b'*');
        assert_eq!(score4, 1);
        let score5 = pam120(b'X', b'X');
        assert_eq!(score5, -2);
        let score6 = pam120(b'X', b'Z');
        assert_eq!(score6, -1);
    }
}