SuffixArray* build(const DNASeqList& reads, size_t threads = 1) { assert(!reads.empty()); size_t num_strings = reads.size(); // In the multiple strings case, we need a 2D bit array // to hold the L/S types for the suffixes char** type_array = new char*[num_strings]; for (size_t i = 0; i < num_strings; ++i) { const DNASeq& read = reads[i]; size_t num_bytes = (read.seq.length() + 1) / 8 + 1; type_array[i] = new char[num_bytes]; memset(type_array[i], 0, num_bytes); } // Classify each suffix as being L or S type for (size_t i = 0; i < num_strings; ++i) { const DNASeq& read = reads[i]; size_t len = read.seq.length() + 1; // The empty suffix ($) for each string is defined to be S type // and hence the next suffix must be L type setBit(type_array, i, len - 1, 1); if (!read.seq.empty()) { setBit(type_array, i, len - 2, 0); for (size_t j = len - 2; j > 0; --j) { char curr = read.seq[j - 1], next = read.seq[j]; bool type = (curr < next || (curr == next && getBit(type_array, i, j) == 1)); setBit(type_array, i, j - 1, type); } } } // setup buckets size_t bucket_counts[DNAAlphabet::ALL_SIZE]; size_t buckets[DNAAlphabet::ALL_SIZE]; // find the ends of the buckets countBuckets(reads, bucket_counts, DNAAlphabet::ALL_SIZE); //getBuckets(bucket_counts, buckets, DNAAlphabet::ALL_SIZE, true); // Initialize the suffix array size_t num_suffixes = std::accumulate(&bucket_counts[0], &bucket_counts[0] + DNAAlphabet::ALL_SIZE, (size_t)0); LOG4CXX_DEBUG(logger, boost::format("initialize SA, strings: %d, suffixes: %d") % num_strings % num_suffixes); SuffixArray* sa = new SuffixArray(num_strings, num_suffixes); // Copy all the LMS substrings into the first n1 places in the SA size_t n1 = 0; for (size_t i = 0; i < num_strings; ++i) { const DNASeq& read = reads[i]; for (size_t j = 0; j < read.seq.length() + 1; ++j) { if (isLMS(type_array, i, j)) { SuffixArray::Elem& ele = (*sa)[n1++]; ele.i = i; ele.j = j; } } } // Call MKQS, first on the sequence and then on the index in the read table LOG4CXX_DEBUG(logger, boost::format("calling mkqs on %d of %d suffixes(%f), using %d threads") % n1 % num_suffixes % ((double)n1 / num_suffixes) % threads); { SuffixRadixCmp radixcmp(reads); SuffixIndexCmp indexcmp; if (threads <= 1) { mkqs2(&(*sa)[0], n1, 0, radixcmp, indexcmp); } else { mkqs2(&(*sa)[0], n1, 0, radixcmp, indexcmp); } } LOG4CXX_DEBUG(logger, "mkqs finished"); // Induction sort the remaining suffixes for (size_t i = n1; i < num_suffixes; ++i) { (*sa)[i] = SuffixArray::Elem(); } // Find the ends of the buckets getBuckets(bucket_counts, buckets, DNAAlphabet::ALL_SIZE, true); for (size_t i = n1; i > 0; --i) { SuffixArray::Elem elem = (*sa)[i - 1]; (*sa)[i - 1] = SuffixArray::Elem(); // empty const DNASeq& read = reads[elem.i]; char c = read.seq[elem.j]; (*sa)[--buckets[DNAAlphabet::torank(c)]] = elem; } induceSAl(reads, sa, type_array, bucket_counts, buckets, num_suffixes, DNAAlphabet::ALL_SIZE, false); induceSAs(reads, sa, type_array, bucket_counts, buckets, num_suffixes, DNAAlphabet::ALL_SIZE, true); // deallocate t array for (size_t i = 0; i < num_strings; ++i) { SAFE_DELETE_ARRAY(type_array[i]); } SAFE_DELETE_ARRAY(type_array); return sa; }
script SAMSARA_DECORATE (int choice, int arg1, int arg2) { int clipcount; int result; int i, j, k; int x, y, z; int armorIndex, armorToSet; int pln = PlayerNumber(); switch (choice) { case 1: result = GetActorProperty(0, APROP_Dropped); break; case 2: if (CheckInventory("WolfenMovement") == 1) { SetActorState(0, "Spawn"); } break; case 3: result = !(GetCVar("sv_itemrespawn") || GetCVar("sv_weaponstay")); break; case 4: result = isInvasion() || !(isCoop() || isSinglePlayer()); break; case 5: SetActivatorToTarget(0); result = CheckInventory("Cell"); if (arg1) { TakeInventory("Cell", result); } break; case 6: result = GetCVar("skulltag"); break; case 7: if (arg2 != 1) { GiveQuad(arg1); } else { if (isLMS()) { if (GetCvar("samsara_permaquad") == 1) { GiveInventory("QuadDamageItem", 1); } break; } GiveQuad(arg1); if (GetCvar("samsara_permaquad") == 1)//if (isCoop() || isSinglePlayer()) { GiveInventory("QuadDamageItem", 1); } } break; case 8: result = defaultCVar("samsara_cl_expparticles", 0); if (!result) { result = 100; } result = max(0, result); result *= max(arg1, 1); result /= max(arg2, 1); GiveInventory("QuakeExplosionCounter", result); break; case 9: clipcount = CheckInventory("Clip"); if (clipcount < 50) { GiveInventory("Clip", 50 - clipcount); TakeInventory("Clip", CheckInventory("Clip") - 50); result = 1; } break; case 10: TakeInventory("QuakeExplosionCounter", arg1); result = CheckInventory("QuakeExplosionCounter"); break; case 15: SetActorProperty(0, APROP_Speed, percFloat(arg1, arg2)); break; case 16: if (GameType () != GAME_SINGLE_PLAYER) { SetHudSize(400, 300, 0); Hudmessage(s:"Press any button to respawn."; HUDMSG_PLAIN,1,CR_LIGHTBLUE,200.4,9.1,1.75); delay(15); if (!CheckInventory("DukeBallgag")) { LocalAmbientSound("duke/mpdeath",127); GiveInventory("DukeTauntCooldown",5); ACS_ExecuteAlways(205,0,0); } } break; case 17: if (arg1) { result = GetCVar("samsara_permault"); } else { result = GetCVar("sv_weaponstay"); } break; case 18: if (MapArmors[0] == -1) { CheckMapArmors(); } SetArmorMode(); i = Timer() != 0; if (MapArmors[ARMOR_YELLOW] == 1) { i += 2; } SetActorState(0, ArmorModeStates[ArmorMode][i]); break; case 19: result = isLMS(); break; case 20: SetArmorMode(); armorIndex = -1; armorToSet = arg1; for (i = 0; i < ARMORCOUNT; i++) { if (GetArmorType(ArmorItems[ArmorMode][i][0], pln)) { armorIndex = i; break; } } arg1 = middle(0, arg1, ARMORCOUNT-1); i = CheckInventory("Armor"); j = ArmorItems[ArmorMode][arg1][1]; if (j == 0) { result = 0; break; } /* If we're adding armor, always follow through Else, if the ending armor count is lower than the current armor count and we're not upgrading our armor, give up now */ if (arg2 > 0) { if (arg1 <= armorIndex) { armorToSet = armorIndex; } } else if (((arg2 == 0 && i > j) || (arg2 < 0 && i > -arg2)) && (arg1 <= armorIndex)) { result = 0; break; } if (arg2 <= 0) { TakeInventory("BasicArmor", i); GiveInventory(ArmorItems[ArmorMode][armorToSet][0], 1); k = CheckInventory("Armor"); if (arg2 == 0) { break; } TakeInventory("BasicArmor", k-1); GiveInventory("InfiniteArmorBonus", -arg2 - 1); } else { TakeInventory("BasicArmor", i); GiveInventory(ArmorItems[ArmorMode][armorToSet][0], 1); k = CheckInventory("Armor"); TakeInventory("BasicArmor", k-1); GiveInventory("InfiniteArmorBonus", (i + arg2) - 1); } result = 1; break; case 21: i = CheckInventory("Armor"); if (i < arg1) { result = 0; break; } TakeInventory("BasicArmor", i-arg1); result = 1; break; case 22: result = GetCVar("samsara_nohealthcap"); break; case 23: GiveInventory("TimeBombPause", 1); Delay(arg1); TakeInventory("TimeBombPause", 1); break; case 24: result = GetCVar("samsara_noult"); break; case 25: if (GameType() == GAME_NET_COOPERATIVE) { AmbientSound("quake/invisannouncer",127); } else { LocalAmbientSound("quake/invisannouncer",127); } break; case 26: if (CheckInventory("PowerInvisibility") == 0) { GiveInventory("PowerInvisibility",1); } else { TakeInventory("PowerInvisibility",1); delay(1); GiveInventory("PowerShadow",1); delay(1); GiveInventory("PowerShadow",1); } break; case 27: result = GetCVar("samsara_nounique"); break; case 28: result = GetCVar("samsara_noinvuln"); break; case 29: result = GetCVar("instagib"); break; case 30: result = GetCVar("samsara_cl_bloodyhell"); break; case 31: result = GetCVar("samsara_cl_bloodypersistent"); break; case 32: result = GetCVar("samsara_nohealth"); break; case 33: result = GetCVar("samsara_vanillaquake"); break; }
// Implementation of induced copying algorithm by // Nong, Zhang, Chan // Follows implementation given as an appendix to their 2008 paper // '\0' is the sentinenl in this algorithm void saca_induced_copying(SuffixArray* pSA, const ReadTable* pRT, int numThreads) { // In the multiple strings case, we need a 2D bit array // to hold the L/S types for the suffixes size_t num_strings = pRT->getCount(); char** type_array = new char*[num_strings]; for(size_t i = 0; i < num_strings; ++i) { size_t s_len = pRT->getReadLength(i) + 1; size_t num_bytes = (s_len / 8) + 1; type_array[i] = new char[num_bytes]; assert(type_array[i] != 0); memset(type_array[i], 0, num_bytes); } // Classify each suffix as being L or S type for(size_t i = 0; i < num_strings; ++i) { size_t s_len = pRT->getReadLength(i) + 1; // The empty suffix ($) for each string is defined to be S type // and hence the next suffix must be L type setBit(type_array, i, s_len - 1, 1); setBit(type_array, i, s_len - 2, 0); for(int64_t j = s_len - 3; j >= 0; --j) { char curr_c = GET_CHAR(i, j); char next_c = GET_CHAR(i, j + 1); bool s_type = (curr_c < next_c || (curr_c == next_c && getBit(type_array, i, j + 1) == 1)); setBit(type_array, i, j, s_type); } } // setup buckets const int ALPHABET_SIZE = 5; int64_t bucket_counts[ALPHABET_SIZE]; int64_t buckets[ALPHABET_SIZE]; // find the ends of the buckets countBuckets(pRT, bucket_counts, ALPHABET_SIZE); getBuckets(bucket_counts, buckets, ALPHABET_SIZE, true); // Initialize the suffix array size_t num_suffixes = buckets[ALPHABET_SIZE - 1]; pSA->initialize(num_suffixes, pRT->getCount()); // Copy all the LMS substrings into the first n1 places in the SA size_t n1 = 0; for(size_t i = 0; i < num_strings; ++i) { size_t s_len = pRT->getReadLength(i) + 1; for(size_t j = 0; j < s_len; ++j) { if(isLMS(i,j)) pSA->set(n1++, SAElem(i, j)); } } /* //induceSAl(pRT, pSA, type_array, bucket_counts, buckets, num_suffixes, ALPHABET_SIZE, false); //induceSAs(pRT, pSA, type_array, bucket_counts, buckets, num_suffixes, ALPHABET_SIZE, true); // Compact all the sorted substrings into the first portion of the SA size_t n1 = 0; for(size_t i = 0; i < num_suffixes; ++i) { SAElem elem = pSA->get(i); if(!elem.isEmpty() && isLMS(elem.getID(), elem.getPos())) { pSA->set(n1++, elem); } } */ double ratio = (double)n1 / (double)num_suffixes; std::cout << "[saca] calling mkqs on " << n1 << " suffixes " << ratio << " using " << numThreads << " threads \n"; // Call MKQS, first on the sequence and then on the index in the read table SuffixCompareRadix radix_compare(pRT, 6); SuffixCompareIndex index_compare; //SuffixCompareID id_compare(pRT); if(numThreads <= 1) mkqs2(&pSA->m_data[0], n1, 0, radix_compare, index_compare); else parallel_mkqs(&pSA->m_data[0], n1, numThreads, radix_compare, index_compare); std::cout << "[saca] mkqs finished\n"; // Induction sort the remaining suffixes for(size_t i = n1; i < num_suffixes; ++i) pSA->set(i, SAElem()); // Find the ends of the buckets getBuckets(bucket_counts, buckets, ALPHABET_SIZE, true); for(int64_t i = n1 - 1; i >= 0; --i) { SAElem elem_i = pSA->get(i); pSA->set(i, SAElem()); // empty char c = GET_CHAR(elem_i.getID(), elem_i.getPos()); pSA->set(--buckets[GET_BKT(c)], elem_i); } induceSAl(pRT, pSA, type_array, bucket_counts, buckets, num_suffixes, ALPHABET_SIZE, false); induceSAs(pRT, pSA, type_array, bucket_counts, buckets, num_suffixes, ALPHABET_SIZE, true); // deallocate t array for(size_t i = 0; i < num_strings; ++i) { delete [] type_array[i]; } delete [] type_array; }