103 lines
2.7 KiB
Text
103 lines
2.7 KiB
Text
### Generic utilities
|
|
|
|
# Output: a PRN in range(0; .)
|
|
def prn:
|
|
if . == 1 then 0
|
|
else . as $n
|
|
| (($n-1)|tostring|length) as $w
|
|
| [limit($w; inputs)] | join("") | tonumber
|
|
| if . < $n then . else ($n | prn) end
|
|
end;
|
|
|
|
# bag of words
|
|
def bow(stream):
|
|
reduce stream as $word ({}; .[($word|tostring)] += 1);
|
|
|
|
# Emit a stream of the constituent characters of the input string
|
|
def chars: explode[] | [.] | implode;
|
|
|
|
def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;
|
|
|
|
# Print $n-character segments at a time, each prefixed by a 1-based index
|
|
def pretty_nwise($n):
|
|
(length | tostring | length) as $len
|
|
| def _n($i):
|
|
if length == 0 then empty
|
|
else "\($i|lpad($len)): \(.[:$n])",
|
|
(.[$n:] | _n($i+$n))
|
|
end;
|
|
_n(1);
|
|
|
|
### Biology
|
|
def bases: ["A", "C", "G", "T"];
|
|
|
|
def randomBase:
|
|
bases | .[length|prn];
|
|
|
|
# $w is an array [weightSwap, weightDelete, weightInsert]
|
|
# specifying the weights out of 300 for each of swap, delete and insert
|
|
# Input: an object {dna}
|
|
# Output: an object {dna, message}
|
|
def mutate($w):
|
|
|
|
def removeAt($p): .[:$p] + .[$p+1:];
|
|
(.dna|length) as $le
|
|
# get a random position in the dna to mutate
|
|
| ($le | prn) as $p
|
|
# get a random number between 0 and 299 inclusive
|
|
| (300 | prn) as $r
|
|
| .dna |= [chars]
|
|
| if $r < $w[0]
|
|
then # swap
|
|
randomBase as $base
|
|
| .message = " Change @\($p) \(.dna[$p]) to \($base)"
|
|
| .dna[$p] = $base
|
|
elif $r < $w[0] + $w[1]
|
|
then # delete
|
|
.message = " Delete @\($p) \(.dna[$p])"
|
|
| .dna |= removeAt($p)
|
|
else # insert
|
|
randomBase as $base
|
|
| .message = " Insert @\($p) \($base)"
|
|
| .dna |= .[:$p] + [$base] + .[$p:]
|
|
end
|
|
| .dna |= join("") ;
|
|
|
|
# Generate a random dna sequence of given length:
|
|
def generate($n):
|
|
[range(0; $n) | randomBase] | join("");
|
|
|
|
# Pretty print dna and stats.
|
|
def prettyPrint($rowLen):
|
|
"SEQUENCE:", pretty_nwise($rowLen),
|
|
( bow(chars) as $baseMap
|
|
| "\nBASE COUNT:",
|
|
( bases[] as $c | " \($c): \($baseMap[$c] // 0)" ),
|
|
" ------",
|
|
" Σ: \(length)",
|
|
" ======\n"
|
|
) ;
|
|
|
|
# For displaying the weights
|
|
def pretty_weights:
|
|
" Change: \(.[0])\n Delete: \(.[1])\n Insert: \(.[2])";
|
|
|
|
# Arguments are length, weights, mutations
|
|
def task($n; $w; $muts ):
|
|
generate($n)
|
|
| . as $dna
|
|
| prettyPrint(50),
|
|
"\nWEIGHTS (0 .. 300):", ($w|pretty_weights),
|
|
"\nMUTATIONS (\($muts)):",
|
|
(reduce range(0;$muts) as $i ({$dna};
|
|
mutate($w)
|
|
| .emit += [.message] )
|
|
| (.emit | join("\n")),
|
|
"",
|
|
(.dna | prettyPrint(50)) ) ;
|
|
|
|
|
|
task(250; # length
|
|
[100, 100, 100]; # use e.g. [0, 300, 0] to choose only deletions
|
|
10 # mutations
|
|
)
|