Icon representing a recipe

Recipe: ST Softwalker 2.0

created by LociOiling

Profile


Name
ST Softwalker 2.0
ID
108301
Shared with
Public
Parent
ST Soft Walker
Children
Created on
May 25, 2023 at 18:57 PM UTC
Updated on
May 27, 2023 at 20:18 PM UTC
Description

ST Softwalker, modernized by SemperRabbit, gmn, and LociOiling

Best for


Code


--[[ ST - softwalker v1.0.0.0. gently LWS (Local Wiggle Segments) protein in a way which prevents stiffening. Copyright (C) 2011 Seagat2011 <https://fold.it/users/199249> Copyright (C) 2011 thom001 <https://fold.it/users/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/>. - Port to APIv2 by SemperRabbit 20220911 2.0 LociOiling 20230525 + corrected Seagat2011's user number and updated user links in copyright notices, but can't find thom001 on fold.it or old.fold.it + added xpcall and cleanup + eliminate _floor in favor of math.floor + track starting score, round score reports to three places + change "Step" to "minimum gain" in message, add run # + add timestamps to messages + only report segment range on gain, add more informational messages, timestamps ]]-- Recipe = "ST Softwalker" Version = "2.0" ReVersion = Recipe .. " " .. Version startScore = 0 -- starting score function r3 ( ii ) return ii - ii % 0.001 end function r4 ( ii ) return ii - ii % 0.0001 end function select_range ( seg ) -- Select the next segment range, based on the number of groups, set the next starting segment selection.DeselectAll ( ) local g = math.floor ( seg.count / seg.groups ) if seg.idx + g <= seg.count then -- print ( "Range: " .. seg.idx .. " - " .. seg.idx + g .. ", length: " .. g + 1 ) seg.rfrst = seg.idx seg.rlast = seg.idx + g if seg.idx + g + 1 <= seg.count then seg.idx = seg.idx + g + 1 else seg.idx = seg.count end else -- print ( "Ending range: " .. seg.idx .. " - " .. seg.count .. ", length " .. seg.count - seg.idx + 1 ) seg.rfrst = seg.idx seg.rlast = seg.count end selection.SelectRange ( seg.rfrst, seg.rlast ) return seg end function lws ( seg ) -- Continue with LWS while threshold is met local maxTries = 100 -- don't spend too much time on tiny gains local try = 0 local st = current.GetEnergyScore ( ) local a, b repeat try = try + 1 a = current.GetEnergyScore ( ) structure.LocalWiggleSelected ( seg.duration ) b = current.GetEnergyScore ( ) until b - a <= seg.thr or try > maxTries local en = current.GetEnergyScore ( ) if en > st then local twd = "tries" if try == 1 then twd = "try" end print ( fmtGain ( st ) .. ", " .. try .. " " .. twd .. ", range: " .. seg.rfrst .. "-" .. seg.rlast ) end recentbest.Restore ( ) end function fmtGain ( startScore, endScore ) if endScore == nil then endScore = current.GetEnergyScore () end local gain = endScore - startScore local gainStr = "+" .. r3 ( gain ) if gain == 0 then gainStr = "0" elseif gain < 0.001 then gainStr = "tiny" end return gainStr .. " gain, score " .. r3 ( endScore ) end function main () local duration = 25 -- duration of both local and regular wiggle print ( ReVersion .. " " ) recentbest.Save ( ) startScore = current.GetEnergyScore () print ( "Starting score = " .. r3 ( startScore ) ) local cycle = 1 -- number of times through the main loop while true do -- local wiggle Init runStartScore = current.GetEnergyScore () -- -- "seg" is a Lua table containing options used by lws and other functions -- local seg = { thr = 10, -- gain threshhold, reported as "step" idx = 1, -- segment index idx_reset = 1, -- index for resetting idx groups = 2, -- number of segment groups groups_reset = 2, -- for resetting number of groups duration = duration, -- local wiggle cycles (does not change) count = structure.GetCount (), -- number of segments in puzzle rfrst = 0, -- first segment in current range rlast = 0, -- last segment in current range } duration = duration + 1 -- duration is now only for regular (non-local) wiggle cycles while true do -- local wiggle at this minimum gain threshold print ( "---- Run " .. cycle .. ", minimum gain " .. r4 ( seg.thr ) .. " points ---- " .. os.date ( "%x %X" ) ) while true do -- local wiggle this range size print ( "Local wiggle on " .. seg.groups .. " ranges of " .. math.floor ( seg.count / seg.groups ) + 1 .. " segments" ) local rangeStartScore = current.GetEnergyScore () while true do -- local wiggle each range local idx = seg.idx seg = select_range ( seg ) lws ( seg ) if idx == seg.idx then break end end print ( "Ended " .. seg.groups .. " ranges, " .. fmtGain ( rangeStartScore ) ) seg.idx = seg.idx_reset seg.groups = seg.groups * 2 if seg.groups > seg.count then break end end seg.groups = seg.groups_reset selection.SelectAll ( ) local bws = current.GetEnergyScore () structure.WiggleAll ( duration, true, true ) structure.ShakeSidechainsSelected ( 1 ) local aws = current.GetEnergyScore () if aws > bws then print ( "end of ranges wiggle/shake, " .. fmtGain ( bws ) ) end if seg.thr > 0.0002 then seg.thr = seg.thr / 5 else break end end print ( "---- Run " .. cycle .. " ended, " .. fmtGain ( runStartScore ) .. "---- " .. os.date ( "%x %X" ) ) cycle = cycle + 1 end end function cleanup ( errmsg ) -- cleanup v0.3 if CLEANUPENTRY ~= nil then return end CLEANUPENTRY = true print ( "---" ) local reason local start, stop, line, msg if errmsg == nil then reason = "complete" else start, stop, line, msg = errmsg:find ( ":(%d+):%s()" ) if msg ~= nil then errmsg = errmsg:sub ( msg, #errmsg ) end if errmsg:find ( "Cancelled" ) ~= nil then reason = "cancelled" else reason = "error" end end print ( ReVersion .. " " .. reason .. " " .. os.date ( "%x %X" )) if reason == "error" then print ( "Unexpected error detected" ) print ( "Error line: " .. line ) print ( "Error: \"" .. errmsg .. "\"" ) end recentbest.Restore () local finalScore = current.GetEnergyScore () local gain = finalScore - startScore print ( "Starting score = " .. r3 ( startScore ) ) print ( "Final score = " .. r3 ( finalScore ) ) print ( "Gain = " .. r3 ( gain ) ) end xpcall ( main, cleanup )

Comments


LociOiling Lv 1

ST Softwalker 2.0 is an updated version of a local wiggle recipe originally written by Seagat2011 and thom001.

This version of ST Softwalker adds a cleanup routine, which restores the best score and summarizes the results when the recipe is cancelled. This is helpful in a recipe which runs until cancelled.

The recipe's scriptlog output is now more focused on reporting gains. There should be fewer scriptlog lines in most cases. Scores and gains are now rounded to three decimal places. Small gains are reported as "tiny" to avoid being rounded to zero.

As before, there is no user dialog. Softwalker 2.0 starts to work immediately.

Softwalker 2.0 has been trimmed down to only 200 lines, but this version should behave like the original in most cases. One exception is the case of very small gains. The original Softwalker could get stuck on a particular segment range, repeating local wiggle as long as there was a tiny gain, of only 0.0001 points. Softwalker 2.0 repeats local wiggle on a given range a maximum of 100 times before moving on. The recipe will eventually revisit the same segment range at the same minimum gain unless cancelled.

How Softwalker works

Softwalker starts by looking for a minimum local wiggle gain of 10 points. Segments are initially divided into 2 groups. Softwalker does local wiggle on each of the groups, in sequence. Each group is a specific range of segments.

The first segment range always starts with segment 1. For a given number of groups, all segment ranges have the same size except for the last range. The last range may be smaller than other ranges.

For each segment range, if the local wiggle gain exceeds the minimum gain, local wiggle is repeated. Local wiggle is done on each range at least once. Up to 100 local wiggles (of 30 cycles each) may be tried before Softwalker moves on the the next range.

After processing all segment ranges for a given group size, the group size is doubled, and the process repeats for the new segment ranges, with the same minimum gain. So, the group sizes are 2, 4, 8, 16, 32, 64, 128, and so on. A larger number of groups means fewer segments in each range.

Once the size of the segment ranges reaches 1 segment each, the number of groups is reset to 2, and the minimum gain is divided by 5. So the minimum gain starts at 10 points, then becomes 2 points, then 0.4 points, then 0.08 points, and so on.

When the minimum gain changes, the recipe does a regular wiggle and a shake of the entire protein.

When minimum gain goes below 0.0001 points, everything resets, and a new run starts with 2 groups and a minimum gain of 10 points. The recipe continues to run until cancelled.

Scriptlog output

Older versions of Softwalker produced a lot of "Range" and "Ending Range" messages. Gains were also reported, but the messages tended to get lost among all the "Range" messages

In Softwalker 2.0, the initial "Step" message has been changed to include a run number, with the words "minimum gain" in place of "Step":

 ---- Run 1, minimum gain 10 points ----   05/25/23 20:59:02

Each run also has an end message, showing the total gain:

---- Run 1 ended, +0.002 gain, score 10344.233----    05/26/23 20:09:48

All gain reports use "tiny" for gains less than 0.001 points.

New messages show the size of the ranges being processed:

Local wiggle on 16 ranges of 4 segments

As before, the last segment range in each set may be shorter than the other ranges.

Each group of ranges also has an end message:

Ended 4 ranges, tiny gain, score 10344.359

There are no more "Range" and "Ending Range" messages. The specific range being worked on is only reported when there's a gain. Any gain is reported when there is no more gain or when the maximum number of tries is exhausted:

+2.94 gain, score 8542.396, 1 try, range: 1-4

The number of "tries" reported is how many time the range was local wiggled. Each local wiggle has a fixed length of 30 cycles.

Possible enhancements and miscellaneous

Softwalker has several fixed parameters:

  • the initial number of segment groups (2)
  • the initial minimum gain (10 points)
  • minimum gain reset threshold (<0.0002 points)
  • the number of times local wiggle is repeated for a given range. (100 tries)
  • the number of local wiggle cycles in each try (30 cycles)
  • group size increase factor (2)
  • minimum gain decrease factor (0.02)

A user dialog could allow changing these parameters.

Softwalker does not modify the filter/objective settings. Disabled filters are left disabled throughout. Objectives could be disabled selectively for performance.

Softwalker has a slightly quirky way of dividing segments into groups. Given a puzzle size of 60 segments, Softwalker divides it into one group of 31 segments, and one group of 29 segments. A slightly refined method could produce more evenly sized ranges.

Softwalker always starts at segment 1, and then follows with each range in order of its starting segment. The order of starts could be reversed or randomized. When a shorter range is needed, it could appear in a random spot among the other ranges.

Acknowledgements

Thanks to SemperRabbit for dusting off this golden oldie, and to gmn for sharing.

There were once many versions of this classic recipe, but most of them were lost with the conversion to the new Foldit, when old recipes using the "V1" Foldit Lua interface were dropped. It's still technically possible to recover old "V1" recipes from a saved all.macro cookbook file.