1// 2// BCSequence.m 3// BioCocoa 4// 5// Created by Koen van der Drift on 12/14/2004. 6// Copyright (c) 2003-2009 The BioCocoa Project. 7// All rights reserved. 8// 9// Redistribution and use in source and binary forms, with or without 10// modification, are permitted provided that the following conditions 11// are met: 12// 1. Redistributions of source code must retain the above copyright 13// notice, this list of conditions and the following disclaimer. 14// 2. Redistributions in binary form must reproduce the above copyright 15// notice, this list of conditions and the following disclaimer in the 16// documentation and/or other materials provided with the distribution. 17// 3. The name of the author may not be used to endorse or promote products 18// derived from this software without specific prior written permission. 19// 20// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31#import "BCSequence.h" 32#import "BCAnnotation.h" 33#import "BCFoundationDefines.h" 34#import "BCSymbol.h" 35#import "BCAminoAcid.h" 36#import "BCSymbolSet.h" 37#import "BCToolSequenceFinder.h" 38#import "BCToolComplement.h" 39#import "BCUtilData.h" 40 41#import "BCInternal.h" 42 43@implementation BCSequence 44 45// TODO: 46 47// MOVE MUTABLE METHODS TO ... 48 49// UPDATE THE REVERSE METHOD - SHOULD THIS BE DONE STRING-BASED? 50 51// UPDATE MORE HEADERDOC INFORMATION 52 53// LOOK AGAIN AT SYMBOLATINDEX METHOD 54 55// ADD METHODS FOR NSDATA <-> NSSTRING CONVERSIONS, PROBABLY NOT IN THIS CLASS 56 57// FIX COMPILER WARNINGS 58 59// .... 60 61//////////////////////////////////////////////////////////////////////////// 62#if 0 63#pragma mark � 64#pragma mark � INITIALIZATION METHODS 65#endif 66// 67// INITIALIZATION METHODS 68//////////////////////////////////////////////////////////////////////////// 69 70// designated initializer 71- (id)initWithString:(NSString *)aString symbolSet:(BCSymbolSet *)aSet 72{ 73 if ( (self = [super init]) ) 74 { 75 if ( aString != nil ) 76 { 77 if ( aSet == nil ) 78 { 79 aSet = [BCSymbolSet symbolSetForSequenceType: [self sequenceTypeForString: aString]]; 80 } 81 82 //let the set check the chars 83 NSString *finalString = [aSet stringByRemovingUnknownCharsFromString: aString]; 84 85 // fill the NSData buffer with the contents of the NSString 86 sequenceData = [[finalString dataUsingEncoding: NSUTF8StringEncoding] retain]; 87 } 88 else 89 { 90 sequenceData = nil; 91 } 92 93 symbolSet = [aSet retain]; 94 sequenceType = [aSet sequenceType]; 95 96 annotations = nil; 97 symbolArray = nil; 98 } 99 100 return self; 101} 102 103- (id)initWithData:(NSData *)aData symbolSet:(BCSymbolSet *)aSet 104{ 105 if ( (self = [super init]) ) { 106 if ( aData != nil ) { 107 if ( aSet == nil ) { 108 aSet = [BCSymbolSet symbolSetForSequenceType: [self sequenceTypeForData: aData]]; 109 } 110 111 // let the set check the chars 112 sequenceData = [aSet dataByRemovingUnknownCharsFromData: aData]; 113 [sequenceData retain]; 114 } else { 115 sequenceData = nil; 116 } 117 118 symbolSet = [aSet retain]; 119 sequenceType = [aSet sequenceType]; 120 121 annotations = nil; 122 symbolArray = nil; 123 } 124 125 return self; 126} 127 128- (id)initWithSymbolArray:(NSArray *)anArray symbolSet:(BCSymbolSet *)aSet 129{ 130 if ( (self = [super init]) ) 131 { 132 if ( aSet==nil ) 133 { 134 aSet = [BCSymbolSet symbolSetForSequenceType: [self sequenceTypeForSymbolArray: anArray]]; 135 } 136 137 //let the set check the symbols 138 139 NSArray *finalArray=[aSet arrayByRemovingUnknownSymbolsFromArray:anArray]; 140 symbolArray=[[NSMutableArray alloc] initWithArray:finalArray]; 141 142 // fill the NSData buffer with the contents of the array of symbols 143 sequenceData = [[[self sequenceStringFromSymbolArray: symbolArray] 144 dataUsingEncoding: NSUTF8StringEncoding] retain]; 145 146 symbolSet=[aSet retain]; 147 annotations=nil; 148 sequenceType = [symbolSet sequenceType]; 149 } 150 151 return self; 152} 153 154- (id)initWithSymbolArray:(NSArray *)anArray 155{ 156 return [self initWithSymbolArray:anArray symbolSet: nil]; 157} 158 159// returns an empty sequence by calling the designated initializer 160- (id)init 161{ 162 return [self initWithString:[NSString string] symbolSet:[BCSymbolSet unknownSymbolSet]]; 163} 164 165- (id)initWithString:(NSString*)aString 166{ 167 return [self initWithString:aString symbolSet: nil]; 168} 169 170- (id)initWithString:(NSString*)aString range:(NSRange)aRange 171{ 172 return [self initWithString:[aString substringWithRange:aRange]]; 173} 174 175- (id)initWithString:(NSString*)aString range:(NSRange)aRange symbolSet:(BCSymbolSet *)aSet 176{ 177 return [self initWithString:[aString substringWithRange:aRange] symbolSet: aSet]; 178} 179 180- (id)initWithThreeLetterString:(NSString*)aString symbolSet:(BCSymbolSet *)aSet 181{ 182 return [self initWithString: 183 [self convertThreeLetterStringToOneLetterString: aString symbolSet: aSet] symbolSet: aSet]; 184} 185 186+ (BCSequence *)sequenceWithString: (NSString *)aString 187{ 188 return [[[BCSequence alloc] initWithString:aString] autorelease]; 189} 190 191+ (BCSequence *)sequenceWithString:(NSString *)aString symbolSet:(BCSymbolSet *)aSet 192{ 193 return [[[BCSequence alloc] initWithString:aString symbolSet:aSet] autorelease]; 194} 195 196+ (BCSequence *)sequenceWithThreeLetterString:(NSString *)aString symbolSet:(BCSymbolSet *)aSet 197{ 198 return [[[BCSequence alloc] initWithThreeLetterString: aString symbolSet:aSet] autorelease]; 199} 200 201+ (BCSequence *)sequenceWithSymbolArray:(NSArray *)entry 202{ 203 return [[[BCSequence alloc] initWithSymbolArray:entry] autorelease]; 204} 205 206+ (BCSequence *)sequenceWithSymbolArray:(NSArray *)entry symbolSet: (BCSymbolSet *)aSet; 207{ 208 return [[[BCSequence alloc] initWithSymbolArray:entry symbolSet: aSet] autorelease]; 209} 210 211+ (BCSequence *) objectForSavedRepresentation: (NSString *)aSequence 212{ 213 return [[[BCSequence alloc] initWithString: aSequence] autorelease]; 214} 215 216- (NSString *)convertThreeLetterStringToOneLetterString:(NSString *)aString symbolSet: (BCSymbolSet *)aSet 217{ 218 int i; 219 NSArray *anArray = [aString componentsSeparatedByString:@" "]; 220 NSString *oneLetterCode, *threeLetterCode; 221 NSMutableString *convertedString = [[NSMutableString alloc] initWithString: @""]; 222 223 // build a temporary dictionary with the one-letter code as objects and the three-letter code as keys 224 // the easiest seems to use a symbolset and iterate over all the symbols 225 // for now only works for amino acids. However, if 3-letter codes are also available 226 // for nucleotides, the code can be extended to use BCSymbol. That means that the ivar threeLetterCode 227 // should be moved to BCSymbol from BCAminoAcid 228 229 NSArray *symArray = [[BCSymbolSet proteinSymbolSet] allSymbols]; 230 BCAminoAcid *symbol; 231 232 NSMutableDictionary *symbolDict = [NSMutableDictionary dictionaryWithCapacity: [symArray count]]; 233 234 for (i = 0; i < [symArray count]; i++) 235 { 236 symbol = [symArray objectAtIndex: i]; 237 [symbolDict setObject: [symbol symbolString] forKey: [symbol threeLetterCode]]; 238 } 239 240 // now we have the temp symbolDict, iterate over the sequence (in 3-letter code) 241 // and create a new string using the 1-letter code 242 243 for (i = 0; i < [anArray count]; i++) 244 { 245 threeLetterCode = [anArray objectAtIndex: i]; 246 oneLetterCode = [symbolDict objectForKey: [threeLetterCode capitalizedString]]; 247 248 if ( oneLetterCode ) 249 { 250 [convertedString appendString: oneLetterCode]; 251 } 252 } 253 254 return [convertedString autorelease]; 255} 256 257 258// BCSequence is immutable, no need to copy anything just retain and return self 259- (id)copyWithZone:(NSZone *)zone 260{ 261 return [self retain]; 262} 263 264- (void)dealloc 265{ 266 [sequenceData release]; 267 [symbolSet release]; 268 [annotations release]; 269 270 [self clearSymbolArray]; 271 [super dealloc]; 272} 273 274 275//////////////////////////////////////////////////////////////////////////// 276#if 0 277#pragma mark � 278#pragma mark � SEQUENCE TYPE DETERMINATION 279#endif 280// 281// INFORMATIONAL METHODS 282//////////////////////////////////////////////////////////////////////////// 283 284// This method guesses the sequence type based on a string. 285// The method creates new sequences of the different types 286// and checks which one results in the longer sequence, 287// which is also the one having the lowest number of unknown symbols. 288- (BCSequenceType)sequenceTypeForString:(NSString *)string 289{ 290 // bestSequenceType = best sequence type so far 291 // bestSymbolCount = the length of the best sequence type so far 292 BCSequence *testSequence; 293 BCSequenceType bestSequenceType; 294 unsigned int bestSymbolCount; 295 296 // use a DNA sequence to initialize the values of bestSequenceType and bestSymbolCount 297 testSequence=[BCSequence sequenceWithString:string symbolSet: [BCSymbolSet dnaSymbolSet]]; 298 bestSequenceType=BCSequenceTypeDNA; 299 bestSymbolCount=[testSequence length]; 300 301 // test RNA sequence 302 testSequence=[BCSequence sequenceWithString:string symbolSet: [BCSymbolSet rnaSymbolSet]]; 303 if ([testSequence length]>bestSymbolCount) { 304 bestSequenceType=BCSequenceTypeRNA; 305 bestSymbolCount=[testSequence length]; 306 } 307 308 // test Protein sequence 309 testSequence=[BCSequence sequenceWithString:string symbolSet: [BCSymbolSet proteinSymbolSet]]; 310 if ([testSequence length]>bestSymbolCount) { 311 bestSequenceType=BCSequenceTypeProtein; 312 bestSymbolCount=[testSequence length]; 313 } 314 315 //TO DO: is it a BCSequenceCodon? 316 // * symbols = DNA or RNA > protein 317 // * length = multiple of three 318 // * first 3 letters = ATG / AUG 319 // * no stop codon, except at the end 320 321 return bestSequenceType; 322} 323 324// This method guesses the sequence type for data 325- (BCSequenceType)sequenceTypeForData:(NSData *)aData 326{ 327 unsigned char *seqData = (unsigned char *)[aData bytes]; 328 unsigned i, len = [aData length]; 329 330 // hopefully can determine in first 10,000 symbols 331 if (len > 10000) len = 10000; 332 333 BCSymbolSet *dna = [BCSymbolSet dnaSymbolSet]; 334 BCSymbolSet *rna = [BCSymbolSet rnaSymbolSet]; 335 BCSymbolSet *prot = [BCSymbolSet proteinSymbolSet]; 336 unsigned dnaCount = 0, rnaCount = 0, protCount = 0; 337 338 // bestSequenceType = best sequence type so far 339 // bestSymbolCount = the length of the best sequence type so far 340 BCSequenceType bestSequenceType; 341 342 // use a DNA sequence to initialize the values of bestSequenceType and bestSymbolCount 343 for (i = 0; i < len; ++i) { 344 if ([dna symbolForChar: seqData[i]]) ++dnaCount; 345 if ([rna symbolForChar: seqData[i]]) ++rnaCount; 346 if ([prot symbolForChar: seqData[i]]) ++protCount; 347 } 348 349 // Note that the DNA and RNA symbols is a subset of protein symbols 350 // so assume DNA/RNA and only use protein if count is higher 351 if (dnaCount > rnaCount) { 352 if (protCount > dnaCount) { 353 bestSequenceType = BCSequenceTypeProtein; 354 } else { 355 bestSequenceType = BCSequenceTypeDNA; 356 } 357 } else { 358 if (protCount > rnaCount) { 359 bestSequenceType = BCSequenceTypeProtein; 360 } else { 361 bestSequenceType = BCSequenceTypeRNA; 362 } 363 } 364 365 //TO DO: is it a BCSequenceCodon? 366 // * symbols = DNA or RNA > protein 367 // * length = multiple of three 368 // * first 3 letters = ATG / AUG 369 // * no stop codon, except at the end 370 371 return bestSequenceType; 372} 373 374 375// This method guesses the sequence type based on an NSArray of BCSymbol. 376// The method creates new sequences of the different types 377// and checks which one results in the longer sequence, 378// which is also the one having the lowest number of unknown symbols. 379- (BCSequenceType)sequenceTypeForSymbolArray:(NSArray *)anArray; 380{ 381 // bestSequenceType = best sequence type so far 382 // bestSymbolCount = the length of the best sequence type so far 383 BCSequence *testSequence; 384 BCSequenceType bestSequenceType; 385 unsigned int bestSymbolCount; 386 387 // use DNA sequence to initialize the values of bestSequenceType and bestSymbolCount 388 testSequence=[BCSequence sequenceWithSymbolArray:anArray symbolSet: [BCSymbolSet dnaSymbolSet]]; 389 bestSequenceType=BCSequenceTypeDNA; 390 bestSymbolCount=[testSequence length]; 391 392 // test RNA sequence 393 testSequence=[BCSequence sequenceWithSymbolArray:anArray symbolSet: [BCSymbolSet rnaSymbolSet]]; 394 if ([testSequence length]>bestSymbolCount) { 395 bestSequenceType=BCSequenceTypeRNA; 396 bestSymbolCount=[testSequence length]; 397 } 398 399 // test protein sequence 400 testSequence=[BCSequence sequenceWithSymbolArray:anArray symbolSet: [BCSymbolSet proteinSymbolSet]]; 401 if ([testSequence length]>bestSymbolCount) { 402 bestSequenceType=BCSequenceTypeProtein; 403 bestSymbolCount=[testSequence length]; 404 } 405 406 //TO DO: is it a BCSequenceCodon? 407 // * symbols = DNA or RNA > protein 408 // * length = multiple of three 409 // * first 3 letters = ATG / AUG 410 // * no stop codon, except at the end 411 412 return bestSequenceType; 413} 414 415 416//////////////////////////////////////////////////////////////////////////// 417#if 0 418#pragma mark � 419#pragma mark � OBTAINING SEQUENCE INFORMATION 420#endif 421// 422// INFORMATIONAL METHODS 423//////////////////////////////////////////////////////////////////////////// 424 425- (NSData *) sequenceData 426{ 427 return sequenceData; 428} 429 430- (const unsigned char *) bytes 431{ 432 return (const unsigned char *)[[self sequenceData] bytes]; 433} 434 435 436- (BCSymbolSet *)symbolSet 437{ 438 return symbolSet; 439} 440 441 442// we can now allow to modify a symbolset, eg from strict -> non strict 443 444- (void)setSymbolSet:(BCSymbolSet *)set 445{ 446 [set retain]; 447 [symbolSet release]; 448 symbolSet = set; 449} 450 451 452- (BCSequenceType)sequenceType 453{ 454 return sequenceType; 455} 456 457// should this be commented out? 458/* 459- (void) setSequenceType:(BCSequenceType)aType 460{ 461 sequenceType = aType; 462} 463*/ 464 465- (unsigned int) length 466{ 467 return [[self sequenceData] length]; 468} 469 470 471- (BCSymbol *)symbolAtIndex: (int)theIndex 472{ 473 if ( theIndex < [self length] ) 474 { 475 BCSymbol *aSymbol; 476 477#if 1 478 unsigned char c = [[self sequenceData] charAtIndex: theIndex]; 479 aSymbol = [[self symbolSet] symbolForChar: c]; 480#else 481 // or maybe use getBytes - not faster according to reply on CocoaDev-list 482 483 unsigned char buffer; 484 485 [[self sequenceData] getBytes: &buffer range: NSMakeRange( theIndex, 1 )]; 486 aSymbol = [[self symbolSet] symbolForChar: buffer]; 487 488#endif 489 return aSymbol; 490 } 491 492 return nil; 493} 494 495 496- (BOOL) containsAmbiguousSymbols { 497 BCSymbol *aSymbol; 498 DECLARE_INDEX(loopCounter); 499 int theLimit = [symbolArray count]; 500 501 for ( loopCounter = 0 ; loopCounter < theLimit ; loopCounter++ ) { 502 aSymbol = (BCSymbol *)ARRAY_GET_VALUE_AT_INDEX(symbolArray, loopCounter); 503 if ( [aSymbol isCompoundSymbol] ) 504 return YES; 505 } 506 507 return NO; 508} 509 510- (NSArray *)symbolArray 511{ 512 if ( sequenceData == nil ) 513 { 514 return nil; 515 } 516 517 if ( symbolArray == nil ) 518 { 519 // creates a symbol array from the NSData sequence 520 521 const unsigned char *data; 522 unsigned int i, len; 523 BCSymbol *aSymbol; 524 525 data = [self bytes]; 526 len = strlen((char *)data); 527 528 NSMutableArray *anArray = [NSMutableArray array]; 529 530 for (i = 0; i < len; i++) 531 { 532 if ( (aSymbol = [[self symbolSet] symbolForChar: data[i]]) ) 533 { 534 [anArray addObject: aSymbol]; 535 } 536 } 537 538 symbolArray = [[NSArray alloc] initWithArray: anArray]; 539 } 540 541 return symbolArray; 542} 543 544 545- (void)clearSymbolArray 546{ 547 [symbolArray release]; 548 symbolArray = nil; 549} 550 551 552// TO DO : use BCSymbolSet for filtering 553// DO WE STILL NEED THIS METHOD ?? 554 555- (void) setSymbolArray: (NSArray *) anArray 556{ 557 [symbolArray release]; 558 symbolArray = [[NSMutableArray alloc] init]; 559 560 id aSymbol; 561 DECLARE_INDEX(loopCounter); 562 int theLimit = [anArray count]; 563 564 for ( loopCounter = 0 ; loopCounter < theLimit ; loopCounter++ ) { 565 aSymbol = (id)ARRAY_GET_VALUE_AT_INDEX(anArray, loopCounter); 566 ARRAY_APPEND_VALUE((NSMutableArray *)symbolArray, aSymbol); 567 } 568} 569 570 571- (NSArray *)subSymbolArrayInRange:(NSRange)aRange 572{ 573 if ( aRange.location + aRange.length > [symbolArray count] ) 574 return nil; 575 576 return [symbolArray subarrayWithRange: aRange]; 577} 578 579 580- (NSString*)sequenceString 581{ 582 unsigned int length = [self length]; 583 584 if ( length ) 585 return [self subSequenceStringInRange: NSMakeRange( 0, length ) ]; 586 else 587 return @""; // return empty string, not nil. 588} 589 590 591- (NSString *)subSequenceStringInRange:(NSRange)aRange 592{ 593 if ( aRange.location + aRange.length > [self length] ) 594 return nil; 595 596 NSData *data = [[self sequenceData] subdataWithRange: aRange]; // Man, I love Cocoa !! 597 NSString *theReturn = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; 598 599 return theReturn; 600} 601 602 603- (NSString *)sequenceStringFromSymbolArray:(NSArray *)anArray 604{ 605 NSMutableString *symbols = [NSMutableString string]; 606 BCSymbol *symbol; 607 int i; 608 609 for ( i = 0; i < [anArray count]; i++) 610 { 611 symbol = [anArray objectAtIndex: i]; 612 [symbols appendString: [symbol symbolString]]; 613 } 614 615 return symbols; 616} 617 618- (BCSequence *)subSequenceInRange:(NSRange)aRange { 619 if ( aRange.location + aRange.length > [symbolArray count] ) 620 return nil; 621 622 return [BCSequence sequenceWithSymbolArray: [symbolArray subarrayWithRange: aRange]]; 623} 624 625 626- (NSString *) savableRepresentation { 627 return [self sequenceString]; 628} 629 630 631- (NSString *) description { 632 return [self sequenceString]; 633} 634 635- (void) addAnnotation:(BCAnnotation *)annotation 636{ 637 [self addAnnotation: (id)[annotation content] forKey: [annotation name]]; 638} 639 640 641- (void) addAnnotation:(NSString *)annotation forKey: (NSString *) key 642{ 643 NSMutableString *oldValue; 644 BCAnnotation *oldAnnotation, *newAnnotation; 645 646 if ( annotations == nil ) 647 { 648 annotations = [[NSMutableDictionary alloc] init]; 649 } 650 651 // If key already exists, then we need to append the value, instead of replacing it. 652 // This will happen when annotations are in the entry in multiple lanes. 653 654 oldAnnotation = (BCAnnotation *) [[self annotations] valueForKey: key]; 655 656 if ( oldAnnotation ) 657 { 658 oldValue = [[oldAnnotation content] mutableCopy]; 659 660 [oldValue appendString: @"\n"]; 661 [oldValue appendString: annotation]; 662 663 newAnnotation = [[BCAnnotation alloc] initWithName: key content: oldValue]; 664 } 665 else 666 { 667 newAnnotation = [[BCAnnotation alloc] initWithName: key content: annotation]; 668 } 669 670 [[self annotations] setObject: newAnnotation forKey: key]; 671} 672 673 674- (id) annotationForKey: (NSString *) key 675{ 676 return [[self annotations] objectForKey: key]; 677} 678 679 680- (NSMutableDictionary *) annotations 681{ 682 return annotations; 683} 684 685 686//- (void) setAnnotations:(NSMutableDictionary *)aDict 687//{ 688// [aDict retain]; 689// [annotations release]; 690// annotations=aDict; 691//} 692 693 694 695//////////////////////////////////////////////////////////////////////////// 696#if 0 697#pragma mark � 698#pragma mark � DERIVING RELATED SEQUENCES 699#endif 700// DERIVING OTHER SEQUENCES 701//////////////////////////////////////////////////////////////////////////// 702 703- (BCSequence *) reverse 704{ 705#if 1 706 NSMutableArray *theReverse = [NSMutableArray array]; 707 BCSymbol *aSymbol; 708 DECLARE_INDEX(loopCounter); 709 int theLimit = [[self symbolArray] count]; // or use [self length] ??? 710 711 for ( loopCounter = 0 ; loopCounter < theLimit ; loopCounter++ ) { 712 aSymbol = (id)ARRAY_GET_VALUE_AT_INDEX(symbolArray, loopCounter); 713 ARRAY_INSERT_VALUE_AT_INDEX(theReverse, 0, aSymbol); 714 } 715 716 return [BCSequence sequenceWithSymbolArray: theReverse symbolSet: [self symbolSet]]; 717 718#else 719 720 NSMutableData *reverseSequence = [[NSMutableData alloc] initWithLength: [self length]]; 721 722 const unsigned char *normal = [self bytes]; 723 unsigned char *reverse = [reverseSequence mutableBytes]; 724 725 unsigned int len = strlen( (char *)normal ); 726 727 unsigned i, j; 728 j = 0; 729 730 for(i = len; i >= 0; --i) 731 { 732 reverse[j] = normal[i]; 733 j++; 734 } 735 736 NSString *reverseString = [[NSString alloc] initWithData: reverseSequence encoding: NSUTF8StringEncoding]; 737 738 return [[BCSequence alloc] initWithString: [reverseString autorelease] symbolSet: [self symbolSet]]; 739 740#endif 741 742} 743 744- (BCSequence *)complement 745{ 746 BCToolComplement *complementTool = [BCToolComplement complementToolWithSequence: self]; 747 748 return [complementTool sequenceComplement]; 749} 750 751- (BCSequence *) reverseComplement 752{ 753 BCToolComplement *complementTool = [BCToolComplement complementToolWithSequence: self]; 754 755 [complementTool setReverse: YES]; 756 757 return [complementTool sequenceComplement]; 758} 759 760 761//////////////////////////////////////////////////////////////////////////// 762//////////////////////////////////////////////////////////////////////////// 763#if 0 764#pragma mark � 765#pragma mark � MANIPULATING SEQUENCE CONTENTS 766#endif 767// 768// INFORMATIONAL METHODS 769//////////////////////////////////////////////////////////////////////////// 770 771// THIS SHOULD ALL GO INTO THE MUTABLE SEQUENCE CLASS 772- (void)removeSymbolsInRange:(NSRange)aRange 773{ 774 if ( aRange.location + aRange.length > [symbolArray count] ) 775 return; 776 // [symbolArray removeObjectsInRange: aRange]; 777} 778 779- (void)removeSymbolAtIndex:(int)index 780{ 781 if ( index > [symbolArray count] - 1 ) 782 return; 783 // [symbolArray removeObjectAtIndex:index]; 784} 785 786// TO DO : use BCSymbolSet for filtering // 787- (void)insertSymbolsFromSequence:(BCSequence *)entry atIndex:(int)index 788{ 789 if ( index > [symbolArray count] - 1 ) 790 return; 791 // [symbolArray replaceObjectsInRange:NSMakeRange(index,0) withObjectsFromArray:[entry symbolArray]]; 792} 793 794 795//////////////////////////////////////////////////////////////////////////// 796#if 0 797#pragma mark � 798#pragma mark � FINDING SUBSEQUENCES 799#endif 800// FINDING SUBSEQUENCES 801//////////////////////////////////////////////////////////////////////////// 802 803 804- (NSArray *) findSequence: (BCSequence *) entry 805{ 806 return [self findSequence: entry usingStrict: NO]; 807} 808 809- (NSArray *) findSequence: (BCSequence *) entry usingStrict: (BOOL) strict 810{ 811 return [self findSequence: entry usingStrict: strict firstOnly: NO]; 812} 813 814- (NSArray *) findSequence: (BCSequence *) entry usingStrict: (BOOL) strict firstOnly: (BOOL) firstOnly 815{ 816 return [self findSequence: entry usingStrict: strict 817 firstOnly: NO usingSearchRange: NSMakeRange(0, [self length])]; 818} 819 820- (NSArray *) findSequence: (BCSequence *) entry usingStrict: (BOOL) strict 821 firstOnly: (BOOL) firstOnly usingSearchRange: (NSRange) range 822{ 823 BCToolSequenceFinder *sequenceFinder = [BCToolSequenceFinder sequenceFinderWithSequence: self]; 824 825 [sequenceFinder setStrict: strict]; 826 [sequenceFinder setFirstOnly: firstOnly]; 827 [sequenceFinder setSearchRange: range]; 828 829 return [sequenceFinder findSequence: entry]; 830} 831 832 833 834@end 835