Lua Script Library[]
Even a beginner programmer quickly learns the value of a library of common routines one can include in one's recipes. There are multiple ways of doing the same thing so if you have a way you think better just include it as an alternative. There's no point in arguing style. On the other hand, it's better to not to have multiple definitions for the very same named object. I, Gary Forbis, would like to propose the following guideline: Always define your functions and supporting global fields with at least two nodes. The first node is a table name idenifying a name space and the second either refines the name space or names the function. For example:
math={} -- Return the absolute value of x function math.abs(x) if x < 0 then return -x else return x end end
Also, include sample calls one can use to demonstrate the function:
print(math.abs(-5)) -- will print 5 print(math.abs(5)) -- will also print 5
Include attribution and copyright notice comments given in the code when you copy the code. Finally, reserve a namespace early. We can agree upon common library names. Where they already exist, such as math, please implement the semantics already identified for the members. Extensions to the standard libraries should be clearly identified as such. Well, that'smy introduction. Have fun and good scripting.
Reserved Name Spaces[]
Reserve your name space here. If you want to include one of the routines you need to define the table first. Just include the line from the following for the specific function.
base={} -- the lua standard library luaopen_base debug={} -- the lua standard library luaopen_debug fsl={} -- Foldit special library game={} -- game specific information for current run of script games={} -- game specific information saved in the script gary={} -- Gary Forbis routines or modifications of others' routines math={} -- the lua standard library luaopen_math io={} -- the lua standard library luaopen_io package={} -- the lua standard library luaopen_package string={} -- the lua standard library luaopen_string table={} -- the lua standard library luaopen_table bit={} -- bit manipulation and assignment methods tbit={} -- bit manipulation and assignment methods for truth tables hash={} -- key/value pair manipulation and assignment methods for hash tables
base -- the lua standard library luaopen_base[]
Except where identified these routines are in the standard lua library luaopen_base. Please be as faithful as possible to their definitions. The implementation here differs from lua in that they are buried down one layer from global. In standard lua these functions would not be prefaced by base.
base.assert -- test for false or nil[]
Issues an error when the value of its argument v is false (i.e., nil or false); otherwise, returns all its arguments. message is an error message; when absent, it defaults to "assertion failed!"
function base.assert(v, message) if (v == nil) or (v == false) then if message == nil then print ("assertion failed!") else print(message) end assertion_failue=nil -- cause the script to fail after printing message assertion_failure() else return v end end
I don't have access to any normal implementation of lua so am relyiing upon a best guess here. If lua returns on error then please correct. Use this routine when you want simple error checking without a bunch of fuss.
-- example call to test band length in range base.assert((length >= 0 and length <= 20), "Band length out of range")
fsl -- Foldit Special Library[]
You can find (or add) functions here that are of a general nature.
fsl.Aminos -- A table of useful information about the residues.[]
This table and the for loop support other functions such as fsl.IsHydrophobe and fsl.IsHydrophile. However, there is the foldit boolean function is_hydrophobe so the implementation given below is just extra code. Maybe this table can be put to actual use by someone. Maybe someone wants it to provide fancier recipe output.
-- commented out residues not in Foldit (as of Nov 15, 2010) fsl.aminosLetterIndex=1 fsl.aminosShortIndex=2 fsl.aminosLongIndex=3 fsl.aminosPolarityIndex=4 fsl.aminosAcidityIndex=5 fsl.aminosHydropathyIndex=6 fsl.aminos = { {'a','Ala','Alanine', 'nonpolar','neutral', 1.8}, -- {'b','Asx','Asparagine or Aspartic acid' }, {'c','Cys','Cysteine', 'nonpolar','neutral', 2.5}, {'d','Asp','Aspartic acid', 'polar','negative', -3.5}, {'e','Glu','Glutamic acid', 'polar','negative', -3.5}, {'f','Phe','Phenylalanine','nonpolar','neutral', 2.8}, {'g','Gly','Glycine', 'nonpolar','neutral', -0.4}, {'h','His','Histidine', 'polar','neutral', -3.2}, {'i','Ile','Isoleucine', 'nonpolar','neutral', 4.5}, -- {'j','Xle','Leucine or Isoleucine' }, {'k','Lys','Lysine', 'polar','positive', -3.9}, {'l','Leu','Leucine', 'nonpolar','neutral', 3.8}, {'m','Met','Methionine ', 'nonpolar','neutral', 1.9}, {'n','Asn','Asparagine', 'polar','neutral', -3.5}, -- {'o','Pyl','Pyrrolysine' }, {'p','Pro','Proline', 'nonpolar','neutral', -1.6}, {'q','Gln','Glutamine', 'polar','neutral', -3.5}, {'r','Arg','Arginine', 'polar','positive', -4.5}, {'s','Ser','Serine', 'polar','neutral', -0.8}, {'t','Thr','Threonine', 'polar','neutral', -0.7}, -- {'u','Sec','Selenocysteine' }, {'v','Val','Valine', 'nonpolar','neutral', 4.2}, {'w','Trp','Tryptophan', 'nonpolar','neutral', -0.9}, -- {'x','Xaa','Unspecified or unknown amino acid' }, {'y','Tyr','Tyrosine', 'polar','neutral', -1.3}, -- {'z','Glx','Glutamine or glutamic acid' } } -- turn letter into alternative direct index for i=1,#fsl.aminos do fsl.aminos[fsl.aminos[i][fsl.aminosLetterIndex]] = fsl.aminos[i] end
..and also an advanced table which includes aa codons and van der waals volume:
--[[------------------------------------------------------------------------------------------------ -- ST - mini rosetta energy model v1.0.0.0. -- v1.3 Included codon bases -- Quickly scores a fold based on compactness, hiding, clashing, and disulfide bridges. recommended for Puzzles ( Exploration, Design, Multi-start, Freestyle ) + combinations, thereof. Rosetta 3 is a library based object-oriented software suite which provides a robust system for predicting and designing protein structures, protein folding mechanisms, and protein-protein interactions. The library contains the various tools that Rosetta uses, such as Atom, ResidueType, Residue, Conformation, Pose, ScoreFunction, ScoreType, and so forth. These components provide the data and services Rosetta uses to carry out its computations.[1] REFERENCES 1. Rosetta 3.0 User-guide - http://www.rosettacommons.org/manuals/rosetta3_user_guide/index.html Copyright (C) 2011 Seagat2011 <http://fold.it/port/user/1992490> Copyright (C) 2011 thom001 <http://fold.it/port/user/172510> This program 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. This program 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. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. $Id$ ----------------------------------------------------------------------------- -- Amino Acid library local amino_segs local amino_part local amino_table amino_segs = {'a', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'y'} amino_part = { short = 1, abbrev = 2, longname = 3, hydro = 4, scale = 5, pref = 6, mol = 7, pl = 8, vdw_vol = 9, } amino_part.codon = { ['GCU'] = 1, ['GCC'] = 2, ['GCA'] = 3, ['GCG'] = 4, ['UGU'] = 1, ['UGC'] = 2, ['GAU'] = 1, ['GAC'] = 2, ['GAA'] = 1, ['GAG'] = 2, ['UUU'] = 1, ['UUC'] = 2, ['GGU'] = 1, ['GGC'] = 2, ['GGA'] = 3, ['GGG'] = 4, ['CAU'] = 1, ['CAC'] = 2, ['AUU'] = 1, ['AUC'] = 2, ['AUA'] = 3, ['AAA'] = 1, ['AAG'] = 2, ['UUA'] = 1, ['UUG'] = 2, ['CUU'] = 3, ['CUC'] = 4, ['CUA'] = 5, ['CUG'] = 6, ['AUG'] = 1, ['AAU'] = 1, ['AAC'] = 2, ['CCU'] = 1, ['CCC'] = 2, ['CCA'] = 3, ['CCG'] = 4, ['CAA'] = 1, ['CAG'] = 2, ['CGU'] = 1, ['CGC'] = 2, ['CGA'] = 3, ['CGG'] = 4, ['AGA'] = 5, ['AGG'] = 6, ['UCU'] = 1, ['UCC'] = 2, ['UCA'] = 3, ['UCG'] = 4, ['AGU'] = 5, ['AGC'] = 6, ['ACU'] = 1, ['ACC'] = 2, ['ACA'] = 3, ['ACG'] = 4, ['GUU'] = 1, ['GUC'] = 2, ['GUA'] = 3, ['GUG'] = 4, ['UGG'] = 1, ['UAU'] = 1, ['UAC'] = 2, -- ['UAG'] = 1, -- ['UGA'] = 1, -- Stop codon: ['UAA'] = 1, ['UAG'] = 2, ['UGA'] = 3, } amino_table = { -- {short, abbrev, longname, hydro, scale, pref, mol wt, isoelectric point (pl), van der waals volume, codon} ['a'] = {'a', 'Ala', 'Alanine', 'phobic', -1.6, 'H', 89.09404, 6.01, 67, codon = { [1] = 'GCU', [2] = 'GCC', [3] = 'GCA', [4] = 'GCG', }, }, ['c'] = {'c', 'Cys', 'Cysteine', 'phobic', -17, 'E', 121.15404, 5.05, 86, codon = { [1] = 'UGU', [2] = 'UGC', }, }, ['d'] = {'d', 'Asp', 'Aspartic acid', 'philic', 6.7, 'L', 133.10384, 2.85, 91, codon = { [1] = 'GAU', [2] = 'GAC', }, }, ['e'] = {'e', 'Glu', 'Glutamic acid', 'philic', 8.1, 'H', 147.13074, 3.15, 109, codon = { [1] = 'GAA', [2] = 'GAG', }, }, ['f'] = {'f', 'Phe', 'Phenylalanine', 'phobic', -6.3, 'E', 165.19184, 5.49, 135, codon = { [1] = 'UUU', [2] = 'UUC', }, }, ['g'] = {'g', 'Gly', 'Glycine', 'phobic', 1.7, 'L', 75.06714, 6.06, 48, codon = { [1] = 'GGU', [2] = 'GGC', [3] = 'GGA', [4] = 'GGG', }, }, ['h'] = {'h', 'His', 'Histidine', 'philic', -5.6, 'L', 155.15634, 7.60, 118, codon = { [1] = 'CAU', [2] = 'CAC', }, },--Note: Histidine has no conformational 'pref' ['i'] = {'i', 'Ile', 'Isoleucine', 'phobic', -2.4, 'E', 131.17464, 6.05, 124, codon = { [1] = 'AUU', [2] = 'AUC', [3] = 'AUA', }, }, ['k'] = {'k', 'Lys', 'Lysine', 'philic', 6.5, 'H', 146.18934, 9.60, 135, codon = { [1] = 'AAA', [2] = 'AAG', }, }, ['l'] = {'l', 'Leu', 'Leucine', 'phobic', 1, 'H', 131.17464, 6.01, 124, codon = { [1] = 'UUA', [2] = 'UUG', [3] = 'CUU', [4] = 'CUC', [5] = 'CUA', [6] = 'CUG', }, }, ['m'] = {'m', 'Met', 'Methionine', 'phobic', 3.4, 'H', 149.20784, 5.74, 124, codon = { [1] = 'AUG', }, }, ['n'] = {'n', 'Asn', 'Asparagine', 'philic', 8.9, 'L', 132.11904, 5.41, 96, codon = { [1] = 'AAU', [2] = 'AAC', }, }, ['p'] = {'p', 'Pro', 'Proline', 'phobic', -0.2, 'L', 115.13194, 6.30, 90, codon = { [1] = 'CCU', [2] = 'CCC', [3] = 'CCA', [4] = 'CCG', }, }, ['q'] = {'q', 'Gln', 'Glutamine', 'philic', 9.7, 'H', 146.14594, 5.65, 114, codon = { [1] = 'CAA', [2] = 'CAG', }, }, ['r'] = {'r', 'Arg', 'Arginine', 'philic', 9.8, 'H', 174.20274, 10.76, 148, codon = { [1] = 'CGU', [2] = 'CGC', [3] = 'CGA', [4] = 'CGG', [5] = 'AGA', [6] = 'AGG', }, }, ['s'] = {'s', 'Ser', 'Serine', 'philic', 3.7, 'L', 105.09344, 5.68, 73, codon = { [1] = 'UCU', [2] = 'UCC', [3] = 'UCA', [4] = 'UCG', [5] = 'AGU', [6] = 'AGC', }, }, ['t'] = {'t', 'Thr', 'Threonine', 'philic', 2.7, 'E', 119.12034, 5.60, 93, codon = { [1] = 'ACU', [2] = 'ACC', [3] = 'ACA', [4] = 'ACG', }, }, ['v'] = {'v', 'Val', 'Valine', 'phobic', -2.9, 'E', 117.14784, 6.00, 105, codon = { [1] = 'GUU', [2] = 'GUC', [3] = 'GUA', [4] = 'GUG', }, }, ['w'] = {'w', 'Trp', 'Tryptophan', 'phobic', -9.1, 'E', 204.22844, 5.89, 163, codon = { [1] = 'UGG', }, }, ['y'] = {'y', 'Tyr', 'Tyrosine', 'phobic', -5.1, 'E', 181.19124, 5.64, 141, codon = { [1] = 'UAU', [2] = 'UAC', }, }, --[[ ['b'] = {'b', 'Asx', 'Asparagine or Aspartic acid'}, ['j'] = {'j', 'Xle', 'Leucine or Isoleucine'}, ['o'] = {'o', 'Pyl', 'Pyrrolysine'}, ['u'] = {'u', 'Sec', 'Selenocysteine'}, ['x'] = {'x', 'Xaa', 'Unspecified or unknown amino acid'}, ['z'] = {'z', 'Glx', 'Glutamine or glutamic acid'}, ]]-- } -- Note: * UAG is normally the amber stop codon, but encodes pyrrolysine if a PYLIS element is present. -- Note: ** UGA is normally the opal (or umber) stop codon, but encodes selenocysteine if a SECIS element is present. --[[ Amino Acid Abbrev. Remarks ------------------------------------------------------------------------------ Alanine A Ala Very abundant, very versatile. More stiff than glycine, but small enough to pose only small steric limits for the protein conformation. It behaves fairly neutrally, and can be located in both hydrophilic regions on the protein outside and the hydrophobic areas inside. Asparagine or aspartic acid B Asx A placeholder when either amino acid may occupy a position. Cysteine C Cys The sulfur atom bonds readily to heavy metal ions. Under oxidizing conditions, two cysteines can join together in a disulfide bond to form the amino acid cystine. When cystines are part of a protein, insulin for example, the tertiary structure is stabilized, which makes the protein more resistant to denaturation; therefore, disulfide bonds are common in proteins that have to function in harsh environments including digestive enzymes (e.g., pepsin and chymotrypsin) and structural proteins (e.g., keratin). Disulfides are also found in peptides too small to hold a stable shape on their own (eg. insulin). Aspartic acid D Asp Behaves similarly to glutamic acid. Carries a hydrophilic acidic group with strong negative charge. Usually is located on the outer surface of the protein, making it water-soluble. Binds to positively-charged molecules and ions, often used in enzymes to fix the metal ion. When located inside of the protein, aspartate and glutamate are usually paired with arginine and lysine. Glutamic acid E Glu Behaves similar to aspartic acid. Has longer, slightly more flexible side chain. Phenylalanine F Phe Essential for humans. Phenylalanine, tyrosine, and tryptophan contain large rigid aromatic group on the side-chain. These are the biggest amino acids. Like isoleucine, leucine and valine, these are hydrophobic and tend to orient towards the interior of the folded protein molecule. Phenylalanine can be converted into Tyrosine. Glycine G Gly Because of the two hydrogen atoms at the alpha carbon, glycine is not optically active. It is the smallest amino acid, rotates easily, adds flexibility to the protein chain. It is able to fit into the tightest spaces, e.g., the triple helix of collagen. As too much flexibility is usually not desired, as a structural component it is less common than alanine. Histidine H His In even slightly acidic conditions protonation of the nitrogen occurs, changing the properties of histidine and the polypeptide as a whole. It is used by many proteins as a regulatory mechanism, changing the conformation and behavior of the polypeptide in acidic regions such as the late endosome or lysosome, enforcing conformation change in enzymes. However only a few histidines are needed for this, so it is comparatively scarce. Isoleucine I Ile Essential for humans. Isoleucine, leucine and valine have large aliphatic hydrophobic side chains. Their molecules are rigid, and their mutual hydrophobic interactions are important for the correct folding of proteins, as these chains tend to be located inside of the protein molecule. Leucine or isoleucine J Xle A placeholder when either amino acid may occupy a position Lysine K Lys Essential for humans. Behaves similarly to arginine. Contains a long flexible side-chain with a positively-charged end. The flexibility of the chain makes lysine and arginine suitable for binding to molecules with many negative charges on their surfaces. E.g., DNA-binding proteins have their active regions rich with arginine and lysine. The strong charge makes these two amino acids prone to be located on the outer hydrophilic surfaces of the proteins; when they are found inside, they are usually paired with a corresponding negatively-charged amino acid, e.g., aspartate or glutamate. Leucine L Leu Essential for humans. Behaves similar to isoleucine and valine. See isoleucine. Methionine M Met Essential for humans. Always the first amino acid to be incorporated into a protein; sometimes removed after translation. Like cysteine, contains sulfur, but with a methyl group instead of hydrogen. This methyl group can be activated, and is used in many reactions where a new carbon atom is being added to another molecule. Asparagine N Asn Similar to aspartic acid. Asn contains an amide group where Asp has a carboxyl. Pyrrolysine O Pyl Similar to lysine, with a pyrroline ring attached. Proline P Pro Contains an unusual ring to the N-end amine group, which forces the CO-NH amide sequence into a fixed conformation. Can disrupt protein folding structures like alpha helix or beta sheet, forcing the desired kink in the protein chain. Common in collagen, where it often undergoes a posttranslational modification to hydroxyproline. Glutamine Q Gln Similar to glutamic acid. Gln contains an amide group where Glu has a carboxyl. Used in proteins and as a storage for ammonia. The most abundant Amino Acid in the body. Arginine R Arg Functionally similar to lysine. Serine S Ser Serine and threonine have a short group ended with a hydroxyl group. Its hydrogen is easy to remove, so serine and threonine often act as hydrogen donors in enzymes. Both are very hydrophilic, therefore the outer regions of soluble proteins tend to be rich with them. Threonine T Thr Essential for humans. Behaves similarly to serine. Selenocysteine U Sec Selenated form of cysteine, which replaces sulfur. Valine V Val Essential for humans. Behaves similarly to isoleucine and leucine. See isoleucine. Tryptophan W Trp Essential for humans. Behaves similarly to phenylalanine and tyrosine (see phenylalanine). Precursor of serotonin. Naturally fluorescent. Unknown X Xaa Placeholder when the amino acid is unknown or unimportant. Tyrosine Y Tyr Behaves similarly to phenylalanine (precursor to Tyrosine) and tryptophan (see phenylalanine). Precursor of melanin, epinephrine, and thyroid hormones. Naturally fluorescent, although fluorescence is usually quenched by energy transfer to tryptophans. Glutamic acid or glutamine Z Glx A placeholder when either amino acid may occupy a position. REFERENCES http://en.wikipedia.org/wiki/List_of_standard_amino_acids ]]-- local amino = {} function amino.abbrev_to_short(abbrev) end -- function amino.abbrev_to_short function amino.longname_to_short(longname) end -- function amino.longname_to_short function amino.abbrev(seg) return amino_table[seg][amino_part.abbrev] end -- function _abbrev function amino.long(seg) return amino_table[seg][amino_part.longname] end -- function _long function amino.h(seg) return amino_table[seg][amino_part.hydro] end -- function _h function amino.hscale(seg) return amino_table[seg][amino_part.scale] end -- function _hscale function amino.pref(seg) return amino_table[seg][amino_part.pref] end -- function _pref function amino.size(seg) return amino_table[seg][amino_part.mol] end -- function _mol function amino.charge(seg) return amino_table[seg][amino_part.pl] end -- function _pl function amino.vdw_vol (seg) return amino_table[seg][amino_part.vdw_vol] end -- _vdw_vol function amino.codon(_cdn) return amino_table[seg].codon[amino_part.codon [ _cdn ] ] end -- function _codon
See fsl.IsHydrophobe for an example but use the foldit function is_hydrophobe in one's scripts.
fsl.Default -- Return value or default Edit[]
Rather than coding the same if over and over this function lets you use a single line
function fsl.Default(value,default) if value==nil then return default else return value end end
Very useful function
function myfunction(optionalparam) print(fsl.Default(optionalparam,"<nil>")) end myfunction() -- prints <nil> myfunction("passed") -- prints passed
fsl.FindMutableSegments -- get a list of mutable segments[]
Many foldit puzzles involve mutable segments. This routine gets a list of the mutable segments. It is substantially faster than individually setting and testing segments.
function fsl.FindMutableSegments () print("Finding Mutable Segments -- don't kill during this routine") local slot=fsl.RequestSaveSlot() -- get a save slot for original puzzle quicksave(slot) local mutable={} local isG={} local i select_all() if game.isLigand then deselect_index(game.segCount) end replace_aa('g') -- all mutable segments are set to 'g' for i=1,game.segCount do if get_aa(i) == 'g' then -- find the 'g' segments isG[#isG + 1] = i end end replace_aa('q') -- all mutable segments are set to 'q' for j=1,#isG do i=isG[j] if get_aa(i) == 'q' then -- this segment is mutable mutable[#mutable + 1] = i end end quickload(slot) fsl.ReleaseSaveSlot(slot) print("Mutables found -- OK to kill if desired") return mutable end
A very useful routine.
fsl.GetSegCount() -- set game.segCount and game.isLigand game.mutable = fsl.FindMutableSegments() -- get the list of mutable segments for i=1,#game.mutable do print(game.mutable[i]," is mutable") end
fsl.GetSegCount -- get segment count and adjust for ligand puzzle[]
Some functions blow up when applied to ligands. Rather than using get_segment_count throughout one's script one will be well served to call this function then use the variables game.isLigand and game.segCount.
function fsl.GetSegCount () game.segCount = get_segment_count() game.isLigand =(get_ss(game.segCount) == 'M') -- ligands have ss of 'M' if game.isLigand then game.segCount = game.segCount - 1 end end
this function will save you a lot of grief.
fsl.GetSegCount()
fsl.GetSphere -- get a list of segments within a given distance of a segment[]
Sometimes one wants to get a list of segments within a given distance of a segment. This routine produces such a list.
function fsl.GetSphere(seg, radius) sphere={} for i=1, game.segCount do if get_segment_distance(seg,i) <= radius then sphere[#sphere + 1]=i end end return sphere end
Good way to get a list of segments one wants to track or select
local sphered=fsl.GetSphere(40,10) fsl.SelectSegments(sphered) -- select only the segments within 10fu (foldit units) of 40. do_global_wiggle_all() -- wiggle the selected segments
fsl.IsHydrophile -- test segment as a hydrophile[]
Return true if segment is a hydrophile. Hydrophiles are typically on the outside of a protein.
function fsl.IsHydrophile (segment) return fsl.aminos[get_aa(segment)][fsl.aminosHydropathyIndex] < 1.6 end --better implementation, if desired, maybe just code inline. function fsl.IsHydrophile (segment) return not is_hydrophobe(segment) end
Hydrophiles are typically on the outside of a protein
for x=1,get_segment_count() do if fsl.IsHydrophile(x) then for y=1,get_segment_count() do local d = get_segment_distance(x,y) if fsl.IsHydrophile(y) and d < 18 then band_add_segment_segment(x,y) band_set_length(get_band_count(),d+2) -- push hydrophiles apart end end end end select_all() do_global_wiggle_all(1)
fsl.IsHydrophobe -- test segment as a hydrophobe[]
Return true if segment is a hydrophobe. Hydrophobes are typically on the inside of a protein. Use the foldit function is_hydrophobic that does the same thing. There isn't an equivalent function is_hydrophilic but (not is_hydrophobe) works since all segments are in one group or the other. If you want strong and week versions then use the table and appropriate functions.
function fsl.IsHydrophobe (segment) return fsl.aminos[get_aa(segment)][fsl.aminosHydropathyIndex] > -1.7 end
Hydrophobes are typically on the inside of a protein
for x=1,get_segment_count() do if fsl.IsHydrophobe(x) then for y=1,get_segment_count() do local d = get_segment_distance(x,y) if fsl.IsHydropobe(y) and d < 22 then band_add_segment_segment(x,y) band_set_length(get_band_count(),d-2) -- pull hydrophobes together end end end end select_all() do_global_wiggle_all(1)
fsl.ReleaseSaveSlot -- release a save slot[]
The variable fsl.SaveSlots and the two functions fsl.ReleaseSaveSlot and fsl.RequestSaveSlot make it easy to add new functions without worrying about which save slots are being used by which routines and keeping them separate. These routines assume one won't release a slot not requested. This is an acceptable risk.
-- This code was originally developed by Greg Reddick (aka Tlaloc) fsl.saveSlots={1, 2, 3, 4, 5, 6, 7, 8, 9, 10} -- there are only 10 save slots function fsl.ReleaseSaveSlot(slot) fsl.saveSlots[#fsl.saveSlots + 1] = slot end
This set of functions makes developing new routines easier
local slot=fsl.RequestSaveSlot() -- get a save slot for original puzzle quicksave(slot) -- save original puzzle do_global_wiggle_sidechains(1) local wsScore=get_score(true) local wsSlot=fsl.RequestSaveSlot() -- get a save slot for wiggle sidechains quicksave(wsSlot) -- save puzzle after wiggle sidechains quickload(slot) -- restore original puzzle do_global_wiggle_backbone(1) if wsScore > get_score(true) then print ("sidechains did bettter") quickload(wsSlot) else print ("backbone did better") end fsl.ReleaseSaveSlot(slot) -- release the two requested save slots fsl.ReleaseSaveSlot(wsSlot)
fsl.RequestSaveSlot -- request a save slot[]
The variable fsl.SaveSlots and the two functions fsl.ReleaseSaveSlot and fsl.RequestSaveSlot make it easy to add new functions without worrying about which save slots are being used by which routines and keeping them separate. These routines assume all requested save slots will be released. This is an acceptable risk.
-- This code was originally developed by Greg Reddick (aka Tlaloc) function fsl.RequestSaveSlot() base.assert(#fsl.saveSlots > 0, 'Out of save slots') local saveSlot = fsl.saveSlots[#fsl.saveSlots] fsl.saveSlots[#fsl.saveSlots] = nil return saveSlot end
See fsl.ReleaseSaveSlot for an example
fsl.SelectSegments -- select segments in a list[]
When one want to restrict an action to a specific set of segments one can use this routine to select them. If you have multiple sets of segments then you can add to a given selection by passing true in the second parameter.
-- select a list of segments -- set more to true to add to existing selection function fsl.SelectSegments (list,more) if not more then deselect_all() end for i=1, #list do select_index(list[i]) end end
This limits the do actions to a specific set of segments rather than to all segments
for i=1 to game.segCount do if get_segment_scoure(i) < 0 then -- for segments with negative scores fsl.SelectSegments(fsl.GetSphere(i)) set_behavior_clash_importance(.05) -- relax the nearby sidechains do_shake() set_behavior_clash_importance(1) -- wiggle all into place do_select_all() do_global_wiggle_all() end end
fsl.SelectSphere -- select segments within a given distance of a segment[]
Sometimes one wants to select segments within a given distance of a segment.
function fsl.SelectSphere(seg, radius, more) if not more then deselect_all() end for i=1, game.segCount do if get_segment_distance(seg,i) <= radius then select_index(i) end end end
This is a good way to relax sidechains near a segment while keeping the over all structure.
fsl.SelectSphere(x,10) -- select segments within 10 units of x fsl.SelectSphere(y,10,true) -- add segments within 10 units of y set_behavior_clash_importance(.05) -- ignore most of clashing do_shake(1) -- shake sidechain, relaxing them select_all() -- select the whole protein set_behavior_clash_importance(1) -- make sure clashing is considered do_global_wiggle_all(1) -- wiggle the whole protein restore_recent_best() -- restore to the best position.
gary -- Gary Forbis routines you might like[]
I use another table, game, to contain all my game specific stuff. Rather than doing a lot of work checking for the existance of the table, anyone using these routines should include at a minimum these headers:
base={} -- the table containing the lua base routines fsl={} -- the foldit Special Library game={} -- the table containing data about this game games={} -- the table containing data about known games gary={} -- the table containing the gary forbis routines math={} -- the table containing the lua math routines table={} -- the table containing the lua table routines
gary.BandAdd -- add a band between two segments[]
Adding a band is pretty simple but rather than recoding the same stuff over and over I use this routine.
function gary.BandAdd(seg1,seg2,length,strength) local index if (math.abs(seg1,seg2) < 2) then print("can't add band less than 2 segs apart") return nil else band_add_segment_segment(seg1,seg2) index = get_band_count() if length ~= nil then band_set_length(index,math.max(math.min(length,20),0)) end if strength ~= nil then if strength <= 0 then band_disable(idx) else band_set_strength(index,math.min(strength,10)) end end return index end end
If you want the defaults then you don't need this routine
bands={} band=gary.BandAdd(1,120,3.5,10) -- create a new band if band ~= nil then bands[#bands+1]={band,1,120,true,3.5,10} -- save for future reference endif
gary.BandsAdjust -- adjust the bands in a table[]
Enable, disable, adjust length or strength of a band. If you want to control your bands then you need to keep information about them in a table. First one fixes the table then calls BandAdjust to make things right. This routine is also useful to reset bands after a quickload provided you don't reload to a point where the bands didn't exist.
-- bands is a table of tables with -- index, seg1, seg2, enable, length, strength function gary.BandsAdjust(bands, enable, length, strength) local bandT for x=1,#bands do if enable ~= nil then bands[i][4] = enable end if length ~= nil then bands[i][5] = length -- tables are passed by reference so this end -- modifies the table being passed if strength ~= nil then bands[i][6] = strength end band = bands[x] local index = band[1] if (band[4] == false) or (band[6] <= 0) then band_disable(index) else band_enable(index) band_set_length(index,math.max(math.min(band[5],20),0)) band_set_strength(index,math.min(band[6],10)) end end end
OK, this isn't a tested routine. I've used something like it but not this one.
-- given a table of bands as indicated in gary.BandAdd gary.BandsAdjust(bands,nil,nil,10) -- set all bands to strength 10 gary.BandsAdjust(bands) -- set all bands based upon the table. gary.BandsAdjust(bands,false) -- disable all bands in the table
gary.BandsDelete -- delete bands at and above an index[]
I don't think scriipts that run to completion should leave bands lying around except when that's the point. On the other hand I don't think scripts should remove bands it didn't add. There isn't a way to get the state of bands so one can't restore bands the scripts didn't add. I use this to get rid of the bands the script created
function gary.BandsDelete(index) if fsl.Default(index,1) < 2 then band_delete() -- this deletes all bands else while index<=get_band_count() do -- band indexes are shifted band_delete(get_band_count()) -- so deleted from the end end end end
use when you want to drop bands
gary.BandsDelete(5) -- deletes bands at index 5 and above gary.BandsDelete() -- you might as well use band_delete()
gary.Fuze -- Do blue or pink fuze[]
I don't know the history of blue and pink fuze. The routine I'm using as the basis for my implementation come from Rav3n's repeat BF 1.1.1. The idea is that by lowering the clashing importance the sidechains relax into a more natural position by doing a shake. Then after setting the clashing importance the stresses are distributed into backbone and sidechain movement. I'm not sure if there is a direct natural counterpart. It seems like there could be because the various chemicals can influence the bonds.
gary.LoadSS -- Load the games secondary structure[]
You cannot reload the structure if you didn't save it. Rebuild has greater freedom on loops so many routines convert the segments to loops right up front.
function gary.LoadSS(sSeg,eSeg, ssTable) local x=fsl.Default(sSeg,1) local y=fsl.Default(get_segment_count()) x,y=math.min(x,y), math.max(x,y) x,y=math.max(x,1), math.min(y,get_segment_count()) t=fsl.Default(ssTable,game.ss) i=1 while t[i][3] < x do -- find the triplet with the start segment i = i+1 end repeat if t[i][1] ~= 'M' then deselect_all() for j=math.max(t[i][2],x),math.min(t[i][3],y) do select_index(i) end replace_ss(t[i][1]) end i=i+1 until (i==#t) or (t[i][3] <= y) select_all() -- avoid potential problems down the road end
Normal normal secondary structures are E, L, and H. As far as I know M is being used on ligands. Trying to replace the secondary structure on ligands will cause a failure
gary.SaveSS() -- save the secondary structure select_all() gary.SetSS('L') -- set the proteins secondary structure to loops gary.LoadSS() -- restore the secondary structure to where it was originally ss={ -- an arbitrary secondary structure list {'L',1,1}, -- loop {'H',2,5}, -- helix {'L',6,10}, {'E',11,20} -- sheet } gary.SetSS(,,ss) -- set secondary based upon ss
gary.Reband -- Rebuild the bands, dropping disabled bands[]
Foldit doesn't have band information functions so one has to maintain a table of bands one is using. If you delete a band the index on the bands above the one deleted are moved down. This routine deletes all the bands at or above the minimum band index in the table, deletes the disabled bands from the table, creates new bands, and adjusts them.
-- bands is a table of tables with -- index, seg1, seg2, enable, length, strength function gary.Reband (bands) gary.BandsDelete(math.minT(bands,1) band=gary.BandAdd(1,120,3.5,10) for i=#bands,1,-1 do if bands[i][4] then local band=bands[i] bands[i][1]=gary.BandAdd(band[2],band[3],band[5],band[6]) else if i<#bands then bands[i]=bands[#bands] end bands[#bands]=nil end end end
Not much to say
--given myBands gary.Reband(myBands)
gary.SaveSS -- Save the games secondary structure[]
Rebuild has the greatest freedom on loops. When one want to change to loops then later restore use this routine to save the secondary structure.
function gary.SaveSS() game.ss={} local i=1 -- index into game.ss local oldSS=get_ss(1) local sSeg=1 for j=2,get_segment_count() do local newSS=get_ss(j) if oldSS ~= newSS then game.ss[i]={oldSS, sSeg, j-1} sSeg=j oldSS=newSS i=i+1 end end game.ss[i]={oldSS, sSeg, get_segment_count()} end
this routine uses no parameters and returns none
gary.SaveSS() -- save the games secondary structure in game.ss
gary.SetSS -- Set the games secondary structure[]
Rebuild has the greatest freedom on loops. I use this routine to convert to loops. I could also use it to set the secondary structure based upon some model of structures and segment ranges.
function gary.SetSS(ss,sSeg,eSeg) deselect_all() local x = fsl.Default(sSeg,1) local y = fsl.Default(eSeg,game.segCount) for i=math.max(1,math.min(x,y)), math.min(math.max(x,y),game.segCount) do select_index(i) end replace_ss(ss) select_all() end
Common to set the structure to all loops.
gary.SetSS{'L') -- set the whole protein to loops. gary.SetSS('L',10,20) -- segments 10 through 20 to loops.
math -- the lua standard library luaopen_math[]
Except where identified these routines are in the standard lua library luaopen_math. Please be as faithful as possible to their definitions.
math.abs -- get the absolute value[]
Returns the absolute value of x.
-- Return the absolute value of x function math.abs(x) if x < 0 then return -x else return x end end
There's not much to say here. You should know when you want this function.
print(math.abs(-5)) -- will print 5 print(math.abs(5)) -- will also print 5
math.ceil -- get the smallest integer at or above a value[]
Returns the smallest integer larger than or equal to x
-- Return the smallest integer at or above x function math.ceil(x) if x == x%1 then return x else return x + 1 - (x%1) end end
Again, there's not much to say here.
print(math.ceil(-1)) -- will print -1 print(math.ceil(-.999)) -- will print 0 print(math.ceil(1.00001)) -- will print 2
math.floor -- get the largest integer at or below a value[]
Returns the largest integer smaller than or equal to x.
-- Return the smallest integer at or below x function math.floor(x) return x - (x%1) end
Again, there's not much to say here.
print(math.floor(-1)) -- will print -1 print(math.floor(-.999)) -- will print -1 print(math.floor(1.00001)) -- will print 1
math.floor (any precision) -- get the largest integer at or below a value[]
function math.floor(x,p) return x - (x%p) end
print(math.floor( -1, 0.001 )) -- will print -1.001 print(math.floor( -.999, 0.001 )) -- will print -.999 print(math.floor( 1.00001, 0.001 )) -- will print 1.000
math.frexp -- get m and e where x = m2e[]
Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).
function math.frexp(x) local m=x local e=0 local s=1 if m < 0 then s=-1 m = -m end while m>1 do e=e+1 m=m/2 end while m<=.5 do e=e-1 m=m*2 end return m*s, e end
I'm not sure how useful this will be.
x, y = math.frexp(5) print(5,"=",x,"*(2^",y,")")
math.ldexp -- return m2e []
Returns m2e (e should be an integer).
function math.ldexp(m,e) return m*(2^e) end
I'm not sure how useful this will be in foldit.
x, y = math.frexp(-20) print(math.ldexp(x,y),"=",x,"*(2^",y,")")
math.log10 (Approximation )[]
Return the logarithm base 10 of x
NOTE: the Foldit embedded function math.log10() works much better than this
function math.log10(x) --only works for big numbers local e=10 if x<=0 then print("ERROR, trying to calculate log of a negative number") elseif x<e then print ("Not implemented for numbers <"..e) else local result=0 local residue=x/e while residue>1 do residue=residue/e result=result+1 end result=result+residue --rough estimation !! return result end end
math.log (Taylor Series Approximation )[]
Return the natural logarithm ln(x)
see http://en.wikipedia.org/wiki/Natural_logarithm
NOTE: the Foldit embedded function math.log() works better than this
function math.log(x)--only works for numbers>1 local e=2.718281828 if x<=0 then print("ERROR, trying to calculate log of a negative number") else if x<e then print("Rough estimate !") end local result=0 local residue=x/e while residue>1 do residue=residue/e result=result+1 end local y=residue-1 residue=1+y-y^2/2+y^3/3-y^4/4+y^5/5-y^6/6+y^7/7-y^8/8 --etc for more precision result=result+residue return result end end
math.max -- get the largest of a set of numbers[]
Return the maximum value among its numeric arguments.
function math.max(x,...) local max=x local args={...} for i=1,#args do if args[i]>max then max=args[i] end end return max end
Sometimes you want to get the largest from a set of values. max is a good function for this when one isn't dealing with an array of values.
print(math.max(1,4,2)) -- will print 4
math.maxL -- get the largest number in a list[]
This is a non-standard function useful in foldit. It works like max except that it uses a table of numbers as a parameter.
function math.maxL(x) local max=x[1] for i=2,#x do if x[i]>max then max=x[i] end end return max end
You can use this when you want to get the maximum value from a table of values.
x=[1, 4, 2} print(math.maxL((x)) -- will print 4
math.maxT -- get the entry from a table of tables with the largest value at a given position[]
This is a non-standard function useful in foldit. It works like max except that it returns the table with the largest value in a particular position. The embedded table must have numeric indicies.
function math.maxT(x,col) local maxC=x[1][col] local maxI=1 for i=2,#x do if x[i][col]>maxC then maxI=i maxC=x[i][col] end end local maxT={} for i=1,#x[maxI] do maxT[i]=x[maxI][i] end return maxT end
This is a very useful routine when one wants to get the segment index with the best segment score:
oldScores={} for x = 1,get_segment_count() do -- this doesn't work on ligand puzzles. oldScores[#oldScores+1]={x, get_segment_score(x)} end print("max seg score at ",math.maxT(oldScores,2)[1])
math.min -- get the smallest of a set of numbers[]
Return the minimum value among its numeric arguments.
function math.min(x,...) local min=x local args={...} for i=1,#args do if args[i]<min then min=args[i] end end return min end
Sometimes you want to get the smallest from a set of values. min is a good function for this when one isn't dealing with an array of values.
print(math.min(1,4,2)) -- will print 1
math.minL -- get the smallest number in a list[]
This is a non-standard function useful in foldit. It works like min except that it uses a table of numbers as a parameter.
function math.minL(x) local min=x[1] for i=2,#x do if x[i]<min then min=x[i] end end return min end
You can use this when you want to get the minimum value from a table of values.
x=[1, 4, 2} print(math.minL{(x)) -- will print 1
math.minT -- get the entry from a table of tables with the smallest value at a given position[]
This is a non-standard function useful in foldit. It works like min except that it returns the table with the smallest value in a particular position. The embedded table must have numeric indicies.
function math.minT(x,col) local minC=x[1][col] local minI=1 for i=2,#x do if x[i][col]<minC then minI=i minC=x[i][col] end end local minT={} for i=1,#x[minI] do minT[i]=x[minI][i] end return minT end
This is a very useful routine when one wants to get the segment index with the worst segment score:
oldScores={} for x = 1,get_segment_count() do -- this doesn't work on ligand puzzles. oldScores[#oldScores+1]={x, get_segment_score(x)} end print("min seg score at ",math.minT(oldScores,2)[1])
math.pi -- the value of pi[]
As the trig functions get added this could be useful
math.pi=3.141592653589793238462643383279
math.pow -- raise a value to a power[]
Returns x raised to the power y(You can also use the expression x^y to compute this value. In fact that's how its implemented here
function math.pow(x,y) return x^y end
There's little reason for this function. Who knows there may be a need
print(math.pow(2,4)) -- prints 16
math.random -- get a random number[]
When called without arguments, returns a uniform pseudo-random real number in the range [0,1). When called with an integer number m, math.random returns a uniform pseudo-random integer in the range [1, m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer in the range [m, n].
math.randLngX = 1000 -- nonstandard variable needed by math.random math.randLngC = 48313 -- nonstandard variable needed by math.random function math.random(m,n) ----------------------------------------- -- The original random script this was ported from has the following notices: -- -- Copyright (c) 2007 Richard L. Mueller -- Hilltop Lab web site - http://www.rlmueller.net -- Version 1.0 - January 2, 2007 -- -- You have a royalty-free right to use, modify, reproduce, and -- distribute this script file in any way you find useful, provided -- that you agree that the copyright owner above has no warranty, -- obligations, or liability for such use. ----------------------------------------- local MWC = function() local A_Hi = 63551 local A_Lo = 25354 local M = 4294967296 local H = 65536 local S_Hi = math.floor(math.randLngX / H) local S_Lo = math.randLngX - (S_Hi * H) local C_Hi = math.floor(math.randLngC / H) local C_Lo = math.randLngC - (C_Hi * H) local F1 = A_Hi * S_Hi local F2 = (A_Hi * S_Lo) + (A_Lo * S_Hi) + C_Hi local F3 = (A_Lo * S_Lo) + C_Lo local T1 = math.floor(F2 / H) local T2 = F2 - (T1 * H) math.randLngX = (T2 * H) + F3 local T3 = math.floor(math.randLngX / M) math.randLngX = math.randLngX - (T3 * M) math.randLngC = math.floor((F2 / H) + F1) return math.randLngX end if n == nil and m ~= nil then n = m m = 1 end if (m == nil) and (n == nil) then return MWC() / 4294967296 else m, n = math.min(m,n),math.max(m,n) return math.floor((MWC() / 4294967296) * (n - m + 1)) + m end end
Random numbers are important to foldit.
x={} for i=1,10 do x[i]=0 end for i=1,1000 do j=math.random(10) x[j]=x[j]+1 end print ("distribution") for i=1,10 do print (i, " - ",x[i]) end
math.randomseed -- set the seed value for math.random[]
Sets x as the "seed" for the pseudo-random generator: equal seeds produce equal sequences of numbers. This is a non-standard implementation because it defaults the seed based upon the foldit score when called. The seed should be a number on the order of 10^7. Even a do_global_wiggle(1) is sufficient to make a change in the high order digit in the seed.
function math.randomseed(seed) if seed == nil then -- use the game score to generate a large number math.randLngX=1/((math.abs(get_score(true)%0.0001)*1000)%0.001) while math.randLngX < 10000000 do math.randLngX = math.randLngX * 10 end math.randLngX = math.floor(math.randLngX) -- is an integer required? else math.randLngX = seed end math.randLngC = 48313 -- restore to original end
Normally you don't want the same set of random numbers so a version of the time is used as a seed. Foldit doesn't have access to the time so current score is used.
select_all() do_global_wiggle_all(1) -- change the score sufficiently for a different seed math.randomseed() -- use a function of get_score(true) as seed
math.merge -- (part of merge sort) - merges two sorted arrays[]
function math.merge (left,right) local result local l -- L local r -- R local i local j i = 1 j = 1 l = #left r = #right result = {} while (( i <= l ) or ( j <= r )) do if (( i <= l ) and ( j <= r )) then if ( left [ i ] <= right [ j ] ) then result [ #result +1 ] = left [ i ] i = i + 1 else result [ #result +1 ] = right [ j ] j = j + 1 end elseif ( i <= l ) then result [ #result +1 ] = left [ i ] i = i + 1 elseif ( j <= r ) then result [ #result +1 ] = right [ j ] j = j + 1 end end -- while return result end
math.split -- (part of merge sort) - splits an array Left[]
function math.split (m,middle) -- split left local v v = {} for x = 1,middle do v [ x ] = m [ x ] end return math.msort(v) end
math.split2 -- (part of merge sort) - splits an array Right[]
function math.split2 (m,middle,k) -- split right local v v = {} for x = 1,k do v [ x ] = m [ x + middle ] end return math.msort(v) end
math.msort -- merge sort - returns a sorted array[]
The primary motivation for writing this patch was to produce a stable sort (needed for deterministic operation across multiple hosts). The speedup came as a bonus.
Performance
- Best Case: ( n log n )
- Worst Case: ( n log n )
- Avg Case: ( n log n )
Advantages
- 1. it's a stable sort
- 2. it's faster (see the results)
- 3. it's safer (modifying the original table during sorting has no effect)
Disadvantages
- 1. it uses more memory (but cleans up after itself immediately)
Here are some results:
garbage collection enabled: http://dscontracting.ca/trepan/lua/speedlog-gc.html
garbage collection disabled: http://dscontracting.ca/trepan/lua/speedlog-nogc.html
function math.msort (m) if #m <= 1 then return m end local k local left local right local result local middle middle = math.floor ((#m / 2),1) -- round to the nearest integer k = #m - middle left = math.split(m,middle) -- math.msort(left) right = math.split2(m,middle,k) -- math.msort(right) result = math.merge(left, right) return result end
Example 1
-- Given p is an unsorted array.. p = math.msort (p) local c = #p for i = 1,c do print ( p[i] ) end
math.c_sort -- Counting sort - returns a sorted array of integers in O(n + k) time.[]
Because this type of sort uses Reals (integers >= 0) as key-value indexes into an array, it is not a comparison sort, and the O(n log n) lower bound for performance is exceeded, versus comparison sorts, such as merge sort. The algorithm uses simple for loops, without recursion or subroutine calls, so it is straightforward to analyze:
The initialization of the Count array, plus the second for loop which performs a prefix sum on the count array, each iterate at most k + 1 times and therefore takes O(k) time. The other two (2) for loops, and the initialization of the output array, also each only take O(n) time. Therefore the time for the whole algorithm is the sum of the times for these steps, is O(n + k).
function math.c_sort ( p ) -- for Integers only! -- profiles: 876ps; 849ps; 1012ps local max local i local k local output local count max = 2e4+1 -- set this to the highest score you ever expect to encounter output = {} count = {} k = #p + 1 -- define the spectrum (Range of element values) i = 1 while( i < max ) do count[i] = 0 i = i + 1 end -- find all elements == x i = 1 while ( i < k ) do local n = math.floor(p[i],1) -- Round to the nearest Integer count[n] = count[n] + 1 -- Allow for duplicates i = i + 1 end -- find all elements <= x i = 2 while ( i < max ) do count[i] = count[i] + count[i-1] i = i + 1 end -- Output[rank] = value, where rank = count[value], and value = p[i] i = 1 while ( i < k ) do local value local rank value = p[i] rank = count[p[i]] output[rank] = value count[value] = rank - 1 -- sort duplicates i = i + 1 end return output end -- function math.c_sort
Example 1
local p = { 10,1,9,2,8,3,7,4,7,5,6 } -- must be integers >= 0 p = math.c_sort(p) -- return a sorted integer array
math.sqrt -- get the square root of a value[]
Returns the square root of a number. Many people are used to this function even though it's a simple power expression.
function math.sqrt(x) return x^0.5 end
example call:
print(math.sqrt(2)) -- prints 1.4142135623731 print(math.sqrt(-2)) -- should be an imaginary number but prints a negative
math.find_prime -- returns the nth prime[]
Sometimes you may need to find the unique conformations for a residue; these are best represented by primes.
local r = { [1] = 2, [2] = 3, [3] = 5, [4] = 7, [5] = 11, [6] = 13, [7] = 17, [8] = 19, [9] = 23, [10] = 29, last_mult = { [2] = 14, [3] = 9, [5] = 5, [7] = 4, [11] = 2, [13] = 2, [17] = 1, [19] = 1, [23] = 1, [29] = 1, }, range = 1e3, min = 1, max = 29, lastPrime = 10, } -- array r
local function find_new_primes ( r ) local tmp tmp = {} r.min = r.max + 1 r.max = r.max + r.range + 1-- expand by 100 -- populate potential list for idx = r.min,r.max do tmp [ idx ] = idx -- populate nave list end -- eliminate multiples of current primes over the new range for idx = 1, r.lastPrime do local x x = r.last_mult [ r[idx] ]--1 while ( 1 ) do local n n = x * r [idx] -- new multiple if ( n < r.min ) then x = x + 1 -- skip elseif ( n <= r.max ) then tmp [ n ] = 0 -- remove value from nave list x = x + 1 else break end end r.last_mult [ idx ] = x -- save value end -- find new primes for idx = r.min, r.max do if ( tmp [idx] ~= 0 ) then local x x = 1 r.last_mult [ idx ] = 1 -- set value r.lastPrime = r.lastPrime + 1 -- add prime r [r.lastPrime] = idx -- welcome prime -- eliminate any new multiples while ( 1 ) do local n n = x * idx -- found new multiple if ( n <= r.min ) then x = x + 1 -- skip elseif ( n <= r.max ) then tmp [ n ] = 0 -- remove value from nave list x = x + 1 else break end end r.last_mult [ idx ] = x -- save last end end return r end -- find_new_primes
function math.find_prime ( n ) while ( n > r.lastPrime ) do -- explore when required r = find_new_primes ( r ) end return r [ n ] end
example call:
print(math.find_prime(20)) -- prints 71
math.factorial -- computes n![]
Factorials are useful for Talyor series approximations, as you will see, for calculating sine and cosine.
function math.factorial (n) local t t = n for i = n,2,-1 do t = t * (i-1) end return t end
math.cosine ( Taylor Series Approximation )[]
Cosines are very useful in fold.it to help determine bonding angles and relative position of the backbone. For cosine, we will use a non-converging Talyor series approximation ( n = 15 terms ) - http://en.wikipedia.org/wiki/Taylor_series, cosine (x) = sum [ ((-1 ^ n) / math.factorial (2 * n)) * x ^ (2* n) ]
function math.cosine (x) local nterms nterms = 15 -- calculate first term x = ((-1 ^ 0) / math.factorial (2 * 0)) * ( x ^ (2 * 0) ) -- i.e. equals one (1) -- calculate other terms.. for n = 1,nterms do x = x + ((-1 ^ n) / math.factorial (2 * n)) * ( x ^ (2 * n) ) end return x end
math.sine ( Taylor Series Approximation )[]
Sines are very useful in fold.it to help determine bonding angles and relative position of the backbone. For sine, we will use a non-converging Talyor series approximation ( n = 15 terms ) - http://en.wikipedia.org/wiki/Taylor_series, sine (x) = sum [ ((-1 ^ n) / math.factorial (2 * n + 1)) * x ^ (2* n + 1) ]
function math.sine (x) local nterms nterms = 15 -- calculate first term x = ((-1 ^ 0) / math.factorial (2 * 0 + 1)) * ( x ^ (2 * 0 + 1) ) -- i.e. equals (x) -- calculate other terms.. for n = 1,nterms do x = x + ((-1 ^ n) / math.factorial (2 * n + 1)) * ( x ^ (2 * n + 1) ) end return x end
Bit - A fold.it! version of bit manipulation for the standard library[]
The standard version of Lua does not include bitwise operators. However, there are Lua libraries for this as well as some patched versions of Lua
bit.bits -- Create a bit-field[]
local bit = {} -- a forward declaration DO NOT TOUCH ! local _n = {} -- a forward declaration DO NOT TOUCH ! local _token = {}-- a forward declaration DO NOT TOUCH ! function bit.bits (s) for idx = 1,s do -- 1-based index _n[idx] = 0 end return _n end
bit.hasBit -- Test for resolution []
function bit.hasBit (n, b) return n[b] ~= nil end
bit.setBit -- Set a bit []
function bit.setBit (b) if ( bit.hasBit (_n,b) ) then _n [b] = 1 end end
bit.clearBit -- Clear a bit []
function bit.clearBit (b) if ( bit.hasBit (_n,b) ) then _n [b] = 0 end end
bit.isSet -- Test a bit []
function bit.isSet (b) if ( bit.hasBit (_n,b) ) then return _n [b] == 1 end end
bit.clear_all_bits -- Clear bit-field[]
function bit.clear_all_bits () local j local k local m j = #_n k = #_token m = j if (k > j) then m = k end for idx = 1,m do if (idx <= j) then _n [idx] = 0 end if (idx <= k) then _n [_token[idx]] = 0 end end end
bit.set_all_bits -- Initialize bit-field[]
function bit.set_all_bits () local j local k local m j = #_n k = #_token m = j if (k > j) then m = k end for idx = 1,m do if (idx <= j) then _n [idx] = 1 end if (idx <= k) then _n [_token[idx]] = 1 end end end
bit.getBit -- Get a bit []
function bit.getBit (b) if ( bit.hasBit (_n,b) ) then return _n [b] end end
Example 1
local k local _obj k = get_segment_count () bit.bits (4) -- number of bits (Initialized to 0) -- bit 4: band to loops/coils: default (false) -- bit 3: band to helices: default (true) -- bit 2: band to sheets: default (false) -- bit 1: band to ligand(s): default (false) bit.setBit (3) _obj = { ['L'] = bit.getBit (4), ['H'] = bit.getBit (3),-- this bit has been set to 1 ['E'] = bit.getBit (2), ['M'] = bit.getBit (1), } for sg1 = 1,k do if ( _obj [ get_ss (sg1) ] == 1 ) then print ( "An operation is permitted on this segment - ", sg1 ) end end
Example 2 ( band_helices = false )
function some_work ( sg1,sg2 ) local _obj local ss local ss2 bit.bits (4) bit.set_all_bits () -- (Initialized to 1) -- bit 4: band to loops/coils: default (true) -- bit 3: band to helices: default (false) -- bit 2: band to sheets: default (true) -- bit 1: band to ligand(s): default (true) bit.clearBit (3) _obj = { ['L'] = bit.getBit (4), ['H'] = bit.getBit (3), -- this bit has been set to 0 ['E'] = bit.getBit (2), ['M'] = bit.getBit (1), } ss = get_ss ( sg1 ) ss2 = get_ss ( sg2 ) if (( _obj [ ss ] == 1 ) and ( _obj [ ss2 ] == 1 )) then print ( "An operation is permitted between these segments - ( ", sg1, ", ", sg2" )" ) end end
bit.map_bit -- maps a variable or 'string 'to a bit[]
function bit.map_bit (b) _token [#_token +1] = b -- save token _n [b] = 0 -- Initialize it's value end
Example 1
bit.map_bit ( band_enable ) bit.setBit ( band_enable ) if ( bit.isSet ( band_enable ) ) then print ( "An operation can be performed on this band." ) end
bit.map -- maps one or more variables or 'strings 'to a bit-field[]
function bit.map (...) local max max = #arg for idx = 1,max do local s = max-idx+1 bit.map_bit (arg[s]) end return _n end
Example 1
local function some_work ( sg1,sg2 ) local ss local ss2 bit.map ( 'L', 'H', 'E', 'M' ) -- 0x0000 bit.setBit ('H') -- 'H' now equals 1 ss = get_ss ( sg1 ) ss2 = get_ss ( sg2 ) if (( bit.isSet ( ss )) and ( bit.isSet ( ss2 ))) then print ( "An operation is permitted between these segments - ( ", sg1, "\, ", sg2, " )" ) end end
bit.bitAnd -- bitwise 'and ' operation on a bit-field[]
function bit.bitAnd (msb,...) local max = #arg local m = _n[msb] if ( m ~= 0 ) then for idx = 1,max do if (_n[arg[idx]] == 0) then m = 0 break end end end return m end
Example 1
bit.bits (4) -- 0x0000 bit.setBit (3) -- now set to 1 bit.bitAnd ( 2,3,1 ) -- returns: b(2) & b(3) & b(1) => 0
Example 2
local function some_work ( sg1,sg2 ) local ss local ss2 bit.map ( 'L', 'H', 'E', 'M' ) -- 0x0000 bit.setBit ('H') -- 'H' now equals 1 ss = get_ss ( sg1 ) ss2 = get_ss ( sg2 ) if ( bit.bitAnd( ss,ss2 ) == 1 ) then print ( "An operation is permitted between these segments - ( ", sg1, ", ", sg2" )" ) end end
bit.bitOr -- bitwise 'or ' operation on a bit-field[]
function bit.bitOr (msb,...) local max = #_token local m = _n[msb] if ( m ~= 1 ) then for idx = 1,max do if (_n [arg[idx]] == 1) then m = 1 break end end end return m end
Example 1
bit.bits (4) -- 0x0000 bit.setBit (3) -- now set to 1 print( bit.bitOr ( 2,3,1 ) ) -- returns: b(2) | b(3) | b(1) => 1
bit.empty -- empties a bit-field[]
function bit.empty () _n = {} return _n end
Bit (Truth tables)[]
tbit.bits -- maps bits to a truth table[]
local bit = {} -- a forward declaration DO NOT TOUCH ! local _t = {} -- a forward declaration DO NOT TOUCH ! local _truthtoken = {}-- a forward declaration DO NOT TOUCH !
function tbit.bits (s) for idx = 1,s do -- 1-based index _t[idx] = false end return _t end
tbit.hasBit -- Test for resolution []
function tbit.hasBit (n, b) return n[b] ~= nil end
tbit.setBit -- sets a bit to TRUE[]
function tbit.setBit (b) if ( tbit.hasBit (_t,b) ) then _t [b] = true end end
tbit.isSet -- tests a bit[]
function tbit.isSet (b) if ( tbit.hasBit (_t,b) ) then return _t [b] == true end end
tbit.clearBit -- sets a bit to FALSE[]
function tbit.clearBit (b) if ( tbit.hasBit (_t,b) ) then _t [b] = false end end
tbit.getBit -- get a value[]
function tbit.getBit (b) if ( tbit.hasBit (_t,b) ) then return _t [b] end end
Example 1
local k local _obj k = get_segment_count () tbit.bits (4) -- number of bits (Initialized to FALSE) -- bit 4: band to loops/coils: default (false) -- bit 3: band to helices: default (true) -- bit 2: band to sheets: default (false) -- bit 1: band to ligand(s): default (false) tbit.setBit (3) _obj = { ['L'] = bit.getBit (4), ['H'] = bit.getBit (3),-- this bit has been set to TRUE ['E'] = bit.getBit (2), ['M'] = bit.getBit (1), } for sg1 = 1,k do if ( _obj [ get_ss (sg1) ] ) then print ( "An operation is permitted on this segment - ", sg1 ) end end
tbit.map_bit -- maps a variable or 'string 'to a truth table[]
function tbit.map_bit (b) _truthtoken [#_truthtoken +1] = b -- save token _t [b] = false -- Initialize it's value end
Example 1
tbit.map_bit ( band_enable ) tbit.setBit ( band_enable ) -- set to TRUE if ( tbit.getBit ( band_enable ) ) then print ( "An operation can be performed on this band." ) end
tbit.map -- maps one or more variables or 'strings ' to a truth table[]
function tbit.map(...) local max max = #arg for idx = 1,max do local s = max-idx+1 tbit.map_bit (arg[s]) end end
Example 1
local function some_work ( sg1,sg2 ) local ss local ss2 bit.map ( 'L', 'H', 'E', 'M' ) -- 0x0000 bit.setBit ('H') -- 'H' now equals 1 tbit.map ( 1,0 ) tbit.setBit ( 1 ) -- set 1 to TRUE ss = get_ss ( sg1 ) ss2 = get_ss ( sg2 ) if ( tbit.getBit( bit.bitAnd( ss,ss2 ) ) ) then print ( "An operation is permitted between these segments - ( ", sg1, ", ", sg2" )" ) end end
Example 2
local function some_work ( sg1,sg2 ) local ss local ss2 tbit.map ( 'L', 'H', 'E', 'M' ) tbit.setBit ('H') -- 'H' is set to TRUE ss = get_ss ( sg1 ) ss2 = get_ss ( sg2 ) if ( (tbit.getBit ( ss )) and (tbit.getBit ( ss2 )) ) then print ( "An operation is permitted between these segments - ( ", sg1, ", ", sg2" )" ) end end
tbit.set_all_bits -- initialize all bits to TRUE[]
function tbit.set_all_bits () local j local k local m j = #_t k = #_truthtoken m = j if (k > j) then m = k end for idx = 1,m do if (idx <= j) then _t [idx] = true end if (idx <= k) then _t [_truthtoken[idx]] = true end end end
tbit.clear_all_bits -- initialize all bits to FALSE[]
function tbit.clear_all_bits () local j local k local m j = #_t k = #_truthtoken m = j if (k > j) then m = k end for idx = 1,m do if (idx <= j) then _t [idx] = false end if (idx <= k) then _t [_truthtoken[idx]] = false end end end
tbit.empty -- empties a truth table[]
function tbit.empty () _t = {} return _t end
Hash -- initialize a hash table with key/value pairs[]
Hash_map is a Hashed Associative Container that associates objects of type Key with objects of type Data. Hash_map is a Pair Associative Container, meaning that its value type is pair<const Key, Data>. It is also a Unique Associative Container, meaning that no two elements have keys that compare equal using EqualKey. Looking up an element in a hash_map by its key is efficient, so hash_map is useful for "dictionaries" where the order of elements is irrelevant. If it is important for the elements to be in a particular order, however, then map (not shown) is more appropriate. [1]
REFERENCE
1. "map<Key, Data, Compare, Alloc> containers" - http://www.codeguru.com/cpp/stlguide/Map.shtml
hash.map -- maps a key/value pair into a hash table[]
local hash = {} -- forward declaration DO NOT TOUCH local _hash = {} -- forward declaration DO NOT TOUCH
function hash.map ( key,value ) _hash [ key ] = value return _hash end
hash.getValue -- given a KEY, returns its VALUE []
function hash.getValue ( key ) return _hash [ key ] end
Example 1
-- given that use.Loop is well-defined.. hash.map ( "L",use.Loop ) print ( hash.getValue ( "L" ) ) -- prints the current value of use.Loop
Example 2
local function some_work ( sg1,sg2 ) local ss local ss2 hash.map ( 'L', 0 ) hash.map ( 'H', 1 ) hash.map ( 'E', 0 ) hash.map ( 'M', 0 ) ss = get_ss ( sg1 ) ss2 = get_ss ( sg2 ) if ( (hash.getValue ( ss ) == 1) and (hash.getValue ( ss2 ) == 1) ) then print ( "An operation is permitted between these segments - ( ", sg1, ", ", sg2" )" ) end end
Example 3
local function some_work ( sg1,sg2 ) local ss local ss2 hash.map ( 'L', false ) hash.map ( 'H', true ) hash.map ( 'E', false ) hash.map ( 'M', false ) ss = get_ss ( sg1 ) ss2 = get_ss ( sg2 ) if ( hash.getValue ( ss ) and hash.getValue ( ss2 ) ) then print ( "An operation is permitted between these segments - ( ", sg1, ", ", sg2" )" ) end end
Example 4
local function do_shake_end ( n ) local a = get_ranked_score (true) if(hash.getValue ( a ) ~= a) then do_shake ( n ) hash.map ( a,a ) end end
for ( i = 1,2 ) do do_shake ( 1 ) do_global_wiggle_all ( 1 ) do_shake_end ( 1 ) -- shakes only if new score. (Improved performance) end
hash.empty -- empties a hash table []
function hash.empty () _hash = {} return _hash end -- hash.getValue
table -- the lua standard library luaopen_table[]
Except where identified these routines are in the standard lua library luaopen_math. Please be as faithful as possible to their definitions.
table.concat -- return a string from an array[]
Given an array of strings and numbers return them as a string. table.concat has optional parameters of separator, starting index, and ending index. The separator defaults to the empty string,"", the starting index defaults to 1, and the ending index defaults to the length of the table. An array is a table with integer indexes and none moving.
function table.concat(tab,sep,starti,endi) local def=function(x,y) if x then return x else return y end end local s=def(sep,"") local si=math.max(def(starti,1),1) local ei=math.min(def(endi,#tab),#tab) local ret=tab[si] for i=si+1,ei do ret=ret..s..tab[i] end return ret end
I'm not sure how useful this function is.
x={"this","and","that"} print(table.concat(x," ")) -- prints this and that
table.sort -- sort a compact table[]
Sort a compact table in place. Optionally pass a comparison function. The default sort order is from smallest number or string to largest based upon less than. Since lua defines the results on table a after the sort as not comp(a[i+1],a[i]) and it doesn't make sense to trade equal values an upside down insertion sort will be given here.
function table.sort(x,comp) local j local v if comp == nil then comp=function(x,y) return x<y end end for i = #x-1,1,-1 do v=x[i] j=i while (j<#x) and (comp(x[j+1],v)) do x[j]=x[j+1] j=j+1 end x[j]=v end end
Sort is a very useful routine. Here's a sort for a non-ligand puzzle that has segments ordered by worst score to best:
scores={} for x=1,get_segment_count() do scores[x]={x,get_segment_score(x)} end table.sort(scores,function(x,y) return x[2]<y[2] end) for x=1, #scores do print("segment#",scores[x][1]," has score ",scores[x][2]) end