Foldit Wiki
Advertisement

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
Advertisement