Icon representing a recipe

Recipe: Mutate No Wiggle 1.2 -- Brow42

created by KarenCH

Profile


Name
Mutate No Wiggle 1.2 -- Brow42
ID
100511
Shared with
Public
Parent
Mutate No Wiggle 1.3.1 -- Brow42
Children
Created on
January 04, 2015 at 20:52 PM UTC
Updated on
January 04, 2015 at 20:52 PM UTC
Description

Brute Force Mutator, but doesn't wiggle, stabilize, or fuze. Keeps best AA for each spot. Good for slow design puzzles. Has options for restricting mutations. Tweaked so alanine is also in list

Best for


Code


--[[ * Mutate No Wiggle -- Brow42 * Original Author: Brow42 * Version 1.0 Sept 6 2014 * Brute-force mutator without the wiggle...for * puzzles where wiggle is too slow. * Also has options to restrict which amino acids * are mutated, and to what. For example, prolines * and glycines won't be added, and cysteines won't * be touched. * Automatically does all mutables from worst to best * scoring, but range can be set manually, or via * selection/freeze before you run the script. * This script uses strings instead of tables for AAs. * * Version 1.02 -- Republished under new id * * Version 1.1 Oct 31 2014 Brow42 * * Added pause to allow GUI to function. Added timing info * Added option to remove unwanted residues (from Googol30) * Added trap for User Cancel --]] NSeg = structure.GetCount() title = "Brute Force Mutate No-Wiggle 1.1" options = { cok=true, pok=true, gok=true, aok=true, keepc=false, keepp=false, keepg = false, keepa=false, keephydro=false, charged=true, rings=true, custom="", range="", removeaa=false} -- Gah. All the options have to be in the dialog, so these options are not in the options table guitext_template = "%0.2f seconds every %d mutations" pause = 5 delay = 0.1 options["gui"] = guitext_template:format(delay,pause) function Menu() local d = dialog.CreateDialog(title) d["label1"] = dialog.AddLabel("Include these as allowed AA") d["cok"] = dialog.AddCheckbox("cysteine",options.cok) d["pok"] = dialog.AddCheckbox("proline",options.pok) d["gok"] = dialog.AddCheckbox("glycine",options.gok) d["aok"] = dialog.AddCheckbox("alanine",options.aok) d["charged"] = dialog.AddCheckbox("charged AA",options.charged) d["rings"] = dialog.AddCheckbox("rings: phen, tryp, tyr",options.rings) d["label2"] = dialog.AddLabel("Or, specify AA (overrides above)") d["custom"] = dialog.AddTextbox("AAs",options.custom) d["lable2"] = dialog.AddLabel("Don't change these AA") d["keepc"] = dialog.AddCheckbox("cysteine",options.keepc) d["keepp"] = dialog.AddCheckbox("proline",options.keepp) d["keepg"] = dialog.AddCheckbox("glycine",options.keepg) d["keepa"] = dialog.AddCheckbox("alanine",options.keepa) d["range"] = dialog.AddTextbox("Where:",options.range) -- d["label3"] = dialog.AddLabel("") d["keephydro"] = dialog.AddCheckbox("Preserve Hydrophobicity",options.keephydro) d["removeaa"] = dialog.AddCheckbox("Remove AAs not in either list above (if possible)",options.removeaa) d["gui"] = dialog.AddTextbox("GUI Saver: Wait",options.gui) d["ok"] = dialog.AddButton("OK",1) d["cancel"] = dialog.AddButton("Cancel",0) d["where"] = dialog.AddButton("Select",2) d["help"] = dialog.AddButton("About",3) local rc = dialog.Show(d) for u,v in pairs(options) do options[u] = d[u].value end return rc end -- ================================== Begin New Dialog Library Functions -- Add a wall of text from a table function dialog.AddLabels(d,msg,nlabels) -- pass in # of existing autolabels local nlabels = nlabels or #(d._Order or {}) -- default, valid if never delete dialog elements if type(msg) == 'string' then msg = { msg } end for i = 1,#msg do d['autolabel'..tostring(i+nlabels)] = dialog.AddLabel(msg[i]) end end -- Create but don't display a wall of text and 1 or 2 buttons function dialog.CreateMessageBox(msg,title,buttontext1,buttontext0,buttontext2) title = title or '' local d = dialog.CreateDialog(title) dialog.AddLabels(d,msg) buttontext1 = buttontext1 or 'Ok' d.button = dialog.AddButton(buttontext1,1) if buttontext2 ~= nil then d.button2 = dialog.AddButton(buttontext2,2) end if buttontext0 ~= nil then d.button0 = dialog.AddButton(buttontext0,0) end return d end -- Display a dialog box function dialog.ShowMessageBox(msg,title,buttontext1,buttontext0,buttontext2) return dialog.Show(dialog.CreateMessageBox(msg,title,buttontext1,buttontext0,buttontext2)) end -- Display a box AND print to the output function ErrorMessage(msg,title) if type(msg) == 'string' then msg = { msg } end for i = 1,#msg do print(msg[i]) end return dialog.ShowMessageBox(msg,title) end -- ======================================= End Dialog Functions function About() local rc = dialog.ShowMessageBox( { "This recipe mutates all mutables to all amino acids", "keeping the best score for each segment. It does this", "from worst score to best score. NO WIGGLE IS DONE.", "", "Skipping wiggle allows this to work on puzzles with", "very slow wiggle, but probably won't find the same", "combination as one of the regular mutation scripts.", "", "You can control which segments are mutated, and to", "what types of amino acids. In particular, you can", "prevent prolines and glycines from being added. You", "can also prevent cysteines from being mutated to save", "bridges. You can restrict mutations to the same", "hydrophobicity.", "", "Frozen segments will still mutate, but locked segments", "should not." },title,"Back") if rc == 0 then return 0 end -- cancel script return 3 end -- Turn selection or frozen into ranges and range string function Where() local d = dialog.CreateDialog(title) dialog.AddLabels(d, {"Have you selected segments to muate with","the selection or freeze tool?"}) d.select = dialog.AddButton("Selection",1) d.freeze = dialog.AddButton("Freeze",2) d.nope = dialog.AddButton("Nope",3) -- 0 is window close (cancel script) local rc = dialog.Show(d) if rc == 0 or rc == 3 then return rc end local tmp = {selection.IsSelected, freeze.IsFrozen} UserSelect = tmp[rc] -- pretty name because it shows up in the GUI local appending = false local s local range local list = {} for i = 1, NSeg do s = UserSelect(i) if s then if appending then range[2] = i else range = {i,i} list[#list+1] = range appending = true end else if appending then appending = false end end end for i = 1,#list do if list[i][1] == list[i][2] then list[i] = tostring(list[i][1]) else list[i] = tostring(list[i][1]).."-"..tostring(list[i][2]) end end options.range = table.concat(list," ") return 2 end -- sort by score, also filter by mutability function SortSegments(segs) local scores = {} local keys = {} for j = 1,#segs do i = segs[j] if structure.IsMutable(i) and not structure.IsLocked(i) then s = current.GetSegmentEnergyScore(i) - current.GetSegmentEnergySubscore(i,'reference') scores[s] = i -- scores map to segments keys[#keys+1] = s -- keys are scores end end table.sort(keys) for i = 1,#keys do keys[i] = scores[keys[i]] -- replace score with segment end return keys end -- Turn a range string into a list of ranges (allows negatives, skips non-numerica) function ParseRange(str) local ranges = {} local index while true do local a,b,x = str:find("(%-?%d+)") -- next number local c,d,y,z = str:find("(%d+)%s*%-%s*(%d+)") -- next range if a and ( c == nil or a < c ) then x = tonumber(x) ranges[#ranges+1] = { x, x } index = b+1 elseif c then y = tonumber(y) z = tonumber(z) ranges[#ranges+1] = { y, z } index = d+1 else break end str = str:sub(index+1,str:len()) end return ranges end -- Parse the GUI Saver text options function ParseWait(str) local numpat = "(%-?%d*%.?%d*)" local notnumpat = "[^%d-.]*" local _,_,a,b = str:find(notnumpat..numpat..notnumpat..numpat) if options.gui == '' then pause,delay = 0,0 return end options["gui"] = guitext_template:format(delay,pause) local errstate = a == '' or a == nil or b == '' or b == nil if errstate ~= false then return {"To give the GUI a chance to draw, you can wait a", "certain amount of time after a fixed number of", "mutations. Just specify either 0 seconds or 0 mutations", "to go as fast as possible." } end a,b = tonumber(a),tonumber(b) -- doesn't seem like this can crash on any input matching numpat errstate = a == '' or a == nil or b == '' or b == nil -- Something a little goofy having to check this twice if errstate ~= false then return {"To give the GUI a chance to draw, you can wait a", "certain amount of time after a fixed number of", "mutations. Just specify either 0 seconds or 0 mutations", "to go as fast as possible." } end if a < 0 or b < 0 then return {"Looks like you entered a negative number.","Zero or greater only please."} end if a < 0.01 and b > 0 then return {"Did I say zero? Actually, 0.01 seconds is the","shortest delay."} end -- all good pause,delay = b,a options["gui"] = guitext_template:format(delay,pause) return end -- Turn list of ranges into a list of segments function RangeToList(ranges) if #ranges == 0 then ranges = {{1,NSeg}} end local list = {} local err = "" for i = 1,#ranges do local a,b = unpack(ranges[i]) if a < 1 or a > NSeg then return list,tostring(a).." is out of range." end if b < 1 or b > NSeg then return list,tostring(b).." is out of range." end for j = a,b do list[j] = true end end local list2 = {} for u,v in pairs(list) do list2[#list2+1] = u end table.sort(list2) return list2,err end -- =================== Begin Main ========================== print(title) print (puzzle.GetName(),current.GetScore()) -- different classes of AAs charged = "rkdeh" philic = "qnst" -- excluding charged phobic = "cmailvpg" -- excluding rings rings = "fwy" deny = "" preserve = "" all_aa = charged..philic..phobic..rings repeat rc = Menu() if rc == 0 then return end segs,err = RangeToList(ParseRange(options.range)) if err ~= "" then ErrorMessage(err,"Range Input") rc = -1 end if options.custom ~= "" and options.custom:find("[^"..all_aa..all_aa:upper().."]") then ErrorMessage("You gave something other than one of the 20 AAs.") rc = -1 end err = ParseWait(options.gui) if err then ErrorMessage(err,"GUI Saver Delay Parameters") rc = -1 end if rc == 2 then rc = Where() end if rc == 3 then rc = About() end if rc == 0 then return end -- cancels from child dialogs until rc == 1 if delay == 0 or pause == 0 then print ("No delay between mutations.") else print ("Waiting "..options.gui) print ("Maximum possible mutation rate:",pause/delay,"Mutations/second") end if options.custom ~= "" then aas = options.custom else aas = philic..phobic if options.charged then aas = aas..charged end if options.rings then aas = aas..rings end end -- okay add in the subtypes, for checking type later philic = philic..charged phobic = phobic..rings -- build preserve and deny lists from the checkboxes if options.keepc then preserve = preserve.."c" end if options.keepp then preserve = preserve.."p" end if options.keepg then preserve = preserve.."g" end if options.keepa then preserve = preserve.."a" end if not options.cok then deny = deny.."c" end if not options.pok then deny = deny.."p" end if not options.gok then deny = deny.."g" end if not options.aok then deny = deny.."a" end start = current.GetScore() order = SortSegments(segs) start_time = os.time() n_mutations = 0 speedcheck_n = 100 -- every 100 mutations (5 segments?) speedcheck_s = 120 -- every 2 minutes lastspeedcheck_s = start_time lastspeedcheck_n = 0 function PrintSpeedCheck(force) local t = os.time() -- probably won't wrap around local dt = t - start_time if force or t-lastspeedcheck_s > speedcheck_s or n_mutations-lastspeedcheck_n > speedcheck_n then lastspeedcheck_s = t lastspeedcheck_n = n_mutations print ("Average mutation rate:",n_mutations/dt,"mutations/second") end end function Main() for i = 1,#order do recentbest.Save() s = current.GetScore() iSeg = order[i] -- Not Local origaa = structure.GetAminoAcid(iSeg) -- Not Local if preserve:find(origaa) == nil then -- skip keep first_mutation = true -- first mutation this segment for j =1,aas:len() do aa = aas:sub(j,j) hydrook = not options.keephydro or (structure.IsHydrophobic(iSeg) and phobic:find(aa) ~= nil) or (not structure.IsHydrophobic(iSeg) and philic:find(aa) ~= nil) if deny:find(aa) == nil and hydrook then -- if not in deny and correct type, else skip structure.SetAminoAcid(iSeg,aa) n_mutations = n_mutations + 1 if first_mutation and options.removeaa == true and (deny:find(origaa) or aas:find(origaa) == nil) then recentbest.Save() -- forget the original score of the unwanted aa, use this one end first_mutation = false end -- GUI pause here if delay > 0 and pause > 0 and n_mutations > 0 and n_mutations % pause == 0 then t = os.clock() repeat dt = os.clock() - t -- watch out, clock() can wrap to 0 until dt > delay or dt < 0 end PrintSpeedCheck(false) end recentbest.Restore() print( i, "of", #order, "Segment #", iSeg, origaa, "->", structure.GetAminoAcid(iSeg), "change", current.GetScore()-s ) else print( i, "of", #order, "Segment #", iSeg, origaa, "skipped" ) end end end function OnError(errmsg) if string.find(errmsg,"Cancelled") then print("User cancel. Loading recent best.") recentbest.Restore() else -- it's a real error, not a cancel print(errmsg) end return errmsg end rc, err = xpcall(Main,OnError) if rc == true then print("Final score",current.GetScore(), current.GetScore()-start) PrintSpeedCheck(true) end

Comments