001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.nbio.structure.align.multiple; 022 023import java.io.Serializable; 024import java.util.ArrayList; 025import java.util.List; 026 027import javax.vecmath.Matrix4d; 028 029/** 030 * A general implementation of a BlockSet to store a flexible part of a multiple 031 * alignment. 032 * 033 * @author Aleix Lafita 034 * @since 4.1.0 035 * 036 */ 037public class BlockSetImpl extends AbstractScoresCache implements Serializable, 038 BlockSet, Cloneable { 039 040 private static final long serialVersionUID = -1015791986000076089L; 041 042 // Member variables 043 private MultipleAlignment parent; 044 private List<Block> blocks; 045 046 // Cache variables (can be updated) 047 private List<Matrix4d> pose; // Transformation matrices 048 private int length; 049 private int coreLength; 050 private List<Integer> alignResCounts; 051 052 /** 053 * Constructor. Links also the parent to this instance by adding the 054 * BlockSet to the parent's List. 055 * 056 * @param alignment 057 * MultipleAlignment parent of the BlockSet. 058 * @return BlockSet an instance linked to the parent alignment. 059 */ 060 public BlockSetImpl(MultipleAlignment alignment) { 061 062 parent = alignment; 063 if (parent != null) 064 parent.getBlockSets().add(this); 065 blocks = null; 066 067 pose = null; 068 length = -1; // Value -1 reserved to indicate that has to be calculated 069 coreLength = -1; 070 alignResCounts = null; // Value null means not yet calculated 071 } 072 073 /** 074 * Copy constructor. Makes also a deep copy of all constituent {@link Block} 075 * s. 076 * 077 * @param bs 078 * BlockSet object to be copied. 079 * @return BlockSet an identical copy of the input object. 080 */ 081 public BlockSetImpl(BlockSetImpl bs) { 082 083 super(bs); // This copies the cached scores 084 this.parent = bs.parent; 085 this.length = bs.length; 086 this.coreLength = bs.coreLength; 087 088 this.pose = null; 089 if (bs.pose != null) { 090 // Make a deep copy of everything 091 this.pose = new ArrayList<Matrix4d>(); 092 for (Matrix4d trans : bs.pose) { 093 Matrix4d newTrans = (Matrix4d) trans.clone(); 094 pose.add(newTrans); 095 } 096 } 097 098 blocks = null; 099 if (bs.blocks != null) { 100 // Make a deep copy of everything 101 this.blocks = new ArrayList<Block>(); 102 for (Block b : bs.blocks) { 103 Block newB = b.clone(); 104 newB.setBlockSet(this); 105 this.blocks.add(newB); 106 } 107 } 108 } 109 110 @Override 111 public void clear() { 112 super.clear(); 113 length = -1; 114 coreLength = -1; 115 alignResCounts = null; 116 pose = null; 117 for (Block a : getBlocks()) { 118 a.clear(); 119 } 120 } 121 122 @Override 123 public BlockSetImpl clone() { 124 return new BlockSetImpl(this); 125 } 126 127 @Override 128 public String toString() { 129 return "BlockSetImpl [blocks=" + blocks + ", pose=" + pose 130 + ", length=" + length + ", coreLength=" + coreLength + "]"; 131 } 132 133 @Override 134 public MultipleAlignment getMultipleAlignment() { 135 return parent; 136 } 137 138 @Override 139 public void setMultipleAlignment(MultipleAlignment parent) { 140 this.parent = parent; 141 } 142 143 @Override 144 public List<Block> getBlocks() { 145 if (blocks == null) 146 blocks = new ArrayList<Block>(); 147 return blocks; 148 } 149 150 @Override 151 public void setBlocks(List<Block> blocks) { 152 this.blocks = blocks; 153 for (Block b : blocks) { 154 b.setBlockSet(this); 155 } 156 } 157 158 @Override 159 public List<Matrix4d> getTransformations() { 160 return pose; 161 } 162 163 @Override 164 public void setTransformations(List<Matrix4d> transformations) { 165 if (size() != transformations.size()) { 166 throw new IllegalArgumentException( 167 "Wrong number of structures for this alignment"); 168 } 169 pose = transformations; 170 } 171 172 @Override 173 public int length() { 174 if (length == -1) 175 updateLength(); 176 return length; 177 } 178 179 @Override 180 public int size() { 181 // Get the size from the variables that can contain the information 182 if (parent != null) 183 return parent.size(); 184 else if (getBlocks().size() == 0) { 185 throw new IndexOutOfBoundsException( 186 "Empty BlockSet: number of Blocks == 0."); 187 } else 188 return blocks.get(0).size(); 189 } 190 191 @Override 192 public int getCoreLength() { 193 if (coreLength == -1) 194 updateCoreLength(); 195 return coreLength; 196 } 197 198 protected void updateLength() { 199 if (getBlocks().size() == 0) { 200 throw new IndexOutOfBoundsException( 201 "Empty BlockSet: number of Blocks == 0."); 202 } 203 // Try to calculate it from the Block information 204 else { 205 length = 0; 206 for (Block block : blocks) 207 length += block.length(); 208 } 209 } 210 211 protected void updateCoreLength() { 212 if (getBlocks().size() == 0) { 213 throw new IndexOutOfBoundsException( 214 "Empty BlockSet: number of Blocks == 0."); 215 } 216 // Try to calculate it from the Block information 217 else { 218 coreLength = 0; 219 for (Block block : blocks) 220 coreLength += block.getCoreLength(); 221 } 222 } 223 224 protected void updateCache() { 225 updateCoreLength(); 226 updateLength(); 227 } 228 229 @Override 230 public List<Integer> getAlignResCounts() { 231 232 if (alignResCounts != null) 233 return alignResCounts; 234 235 alignResCounts = new ArrayList<Integer>(size()); 236 for (int s = 0; s < size(); s++) 237 alignResCounts.add(0); 238 239 for (Block b : blocks) { 240 List<Integer> bcounts = b.getAlignResCounts(); 241 for (int s = 0; s < size(); s++) 242 alignResCounts.set(s, alignResCounts.get(s) + bcounts.get(s)); 243 } 244 return alignResCounts; 245 } 246 247}