Url: http://tiny.cc/jujus
Noun:
- The power associated with a juju
- A charm superstitiously believed to embody magical powers
Url: http://tiny.cc/jujus
Noun:
| #!/usr/bin/env bash | |
| julia -O0 --compile=min --startup=no $* | |
| # vim: set et sts=2 sw=2 ts=2 : | |
| include("lib.jl") | |
| the,help = settings(" | |
| JUJU: multi-objective semi-supervised explabations in O(log(N)) time | |
| (c) 2023 Tim Menzies <[email protected]> BSD-2 license | |
| USAGE: | |
| julia juju.jl [OPTIONS] | |
| OPTIONS: | |
| -c --cohen trivial is up to sd*cohen = 0.35 | |
| -f --file where to get data = ../data/auto93.csv | |
| -g --go start up action = nothing | |
| -h --help show help = false | |
| -s --seed random number seed = 937162211") | |
| @with_kw mutable struct ROW | |
| cells=[]; id=0; klass=nothing end | |
| (i::ROW)(col) = begin println("asdas",o(col)); i.cells[col.pos] end | |
| @with_kw mutable struct DATA | |
| rows=[]; cols=nothing end | |
| @with_kw mutable struct NUM | |
| pos=0; txt=""; n=0; | |
| w=1; lo=10.0^64; hi=-10.0^64 | |
| mu=0; m2=0 end | |
| @with_kw mutable struct SYM | |
| pos=0; txt=""; n=0; w=1; | |
| has=Dict(); most=0; mode=nothing end | |
| function COL(pos, txt, inits=[], by=identity) | |
| x = occursin(r"^[A-Z]", txt) ? NUM : SYM | |
| x(pos=pos, txt=txt, w= occursin(r"-$",txt) ? -1 : 1) | |
| [inc!(x,by(y)) for y in inits] | |
| x end | |
| function COLS(a) | |
| names,all,x,y,klass = a,[],[],[],nothing | |
| for (pos,txt) in enumerate(a) | |
| col = COL(pos,txt) | |
| push!(all, col) | |
| if !occursin(r"X$", txt) | |
| push!(occursin(r"[!\-\+]$", txt) ? y : x, col) | |
| if occursin(r"!$", txt) klass=col end end end | |
| (names=names, all=all, x=x, y=y, klass=klass) end | |
| function inc!(i,x,inc=1) | |
| if x != "?" | |
| i.n += inc; inc1!(i,x,inc) end end | |
| function inc1!(i::NUM,n,_) | |
| i.lo = min(i.lo, n) | |
| i.hi = max(i.hi, n) | |
| d = n - i.mu | |
| i.mu += d / i.n | |
| i.m2 += d * (n - i.mu) end | |
| function inc1!(i::SYM,s,inc=1) | |
| now = i.has[s] = get(i.has,s,0) + inc | |
| if now > i.most | |
| i.mode, i.most = s, now end end | |
| rnd(i::NUM,x,digits=2) = round(x, digits=2) | |
| rnd(i::SYM,x,_) = x | |
| mid(i::NUM) = i.mu | |
| mid(i::SYM) = i.mode | |
| div(i::SYM) = -sum((n/i.n*log2(n/i.n) for (_,n) in i.has)) | |
| div(i::NUM) = i.m2<0 ? 0 : (i.n<2 ? 0 : (i.m2 / (i.n - 1))^0.5) | |
| norm(i::NUM,n) = n=="?" ? n : (n - i.lo)/(i.hi - i.lo + 1E-16) | |
| function holds(on, also=[]) | |
| i = DATA() | |
| holds1(i,on) | |
| [row(i,x) for x in also] | |
| i end | |
| holds1(i::DATA, on::String) = [row(i,x) for x in csv(on)] | |
| holds1(i::DATA, on::DATA) = row(i, on.cols.names) | |
| holds1(i::DATA, on) = [row(i,x) for x in on] | |
| _id=0 | |
| function row(i::DATA, a) | |
| if i.cols==nothing | |
| i.cols=COLS(a) | |
| else | |
| global _id = _id + 1 | |
| row(i, ROW(cells=a,id=_id)) end end | |
| function row(i::DATA, row1::ROW) | |
| push!(i.rows, row1) | |
| for cols in [i.cols.x, i.cols.y] | |
| for col in cols | |
| inc!(col, row1(col)) end end end | |
| function stats(i::DATA; cols=i.cols.y, fn=mid, digits=3) | |
| d=Dict(col.txt=>rnd(col,fn(col),digits) for col in cols) | |
| d["n"] = length(i.rows) | |
| d end | |
| function better(i::DATA, r1::ROW, r2::ROW) | |
| s1, s2, n = 0, 0, length(i.cols.y) | |
| for col in i.cols.y | |
| x,y = norm(col, r1(col)), norm(col, r2(col)) | |
| s1 -= exp(col.w * (x-y)/n) | |
| s2 -= exp(col.w * (y-x)/n) end | |
| return s1/n < s2/n end | |
| # function chop(a,x) | |
| # xs = COL(txt=x.txt,pos=x.pos, inits=a, by=x) | |
| # eps = the.cohen * div(xs) | |
| # m = length(a) | |
| # tmp,out, n = xy(), m / the.div.divs | |
| # last=nothing | |
| # for (i,one) in enumerate(a) | |
| # if tmp.x.n>=n && m - i > n && one(x) != last(x) | |
| # if x(one) - x(tmp[1]) > eps | |
| # push!(out, tmp) | |
| # tmp = xy() end end | |
| # add!(tmp, one) | |
| # last =one end | |
| # if length(tmp.x.n) > 0 push!(out,tmp) end | |
| # out end | |
| # | |
| # function bins(lst, x, y) | |
| # function xy() (rows= [], | |
| # x = COL(pos=x.pos,txt=x.txt), | |
| # y = COL(pos-y.ps,txt=y.txt)) end | |
| # function add!(xy,row) | |
| # inc!(xy.x,row(x)) | |
| # inc!(xy.y,row(y)) | |
| # push!(xy.rows, row) end | |
| # function merge(a) | |
| # tmp, out, j, m = [], [], 1, length(a) | |
| # while j <= m | |
| # one = a[j] | |
| # if j < m | |
| # two = a[j+1] | |
| # three = [ one ; two ] | |
| # n1, n2, n3= length(one), length(two), length(three) | |
| # sd1,sd2,sd3= sd(one,y), sd(two,y), sd(three,y) | |
| # sd12 = n1/n3*sd1 + n2/n3*sd2 | |
| # if abs(sd1 - sd2) < 0.01 || sd12*the.div.trivial >sd3 | |
| # one = three | |
| # j += 1 end end | |
| # push!(tmp,one) | |
| # j += 1 end | |
| # return length(tmp) == length(a) ? a : merge(tmp) | |
| # end #--------------------------- | |
| # merge(chop( sort([z for z in lst if x(z) != "?"], by=x) )) | |
| # end |
| # vim: set et sts=2 sw=2 ts=2 : | |
| using Parameters | |
| using ResumableFunctions | |
| rseed=937162211 | |
| function rani(nlo, nhi) int(.5 + ranf(nlo,nhi)) end | |
| function ranf(nlo=0, nhi=1) | |
| global rseed = (16807 * rseed) % 214748347 | |
| nlo + (nhi - nlo) * rseed / 214748347 end | |
| int(n) = floor(Int,n) | |
| any(a) = a[ rani(1,length(a)) ] | |
| many(a,n) = [any(a) for _ in 1:n] | |
| function coerce(x) | |
| for thing in [Int32,Float64,Bool] | |
| if (y=tryparse(thing,x)) != nothing return y end end | |
| x end | |
| @resumable function csv(sfile) | |
| src = open(sfile) | |
| while ! eof(src) | |
| new = replace(readline(src), r"([ \t\n]|#.*)"=>"") | |
| if sizeof(new) != 0 | |
| @yield map(coerce,split(new,",")) end end end | |
| function settings(s; update=false) #-> settings::NamedTuple,help::String | |
| function cli(k,v) | |
| for (i,flag) in enumerate(ARGS) | |
| if update && (flag=="-"*k[1] || flag=="--"*k) | |
| v= v=="true" ? "false" : (v=="false" ? "true" : ARGS[i+1]) end end | |
| Symbol(k) => coerce(v) end | |
| #--------------------------- | |
| pat = r"\n *-[^-]+--(\S+)[^=]+= *(\S+)" | |
| d = Dict(cli(k,String(v)) for (k,v) in eachmatch(pat,s)) | |
| ((;d...), s) end # Julia idiom for coercing a dictionary to a named tuple | |
| oo(x,d=2) = println(o(x,d)) | |
| o(i::AbstractString,_) = i | |
| o(i::Bool ,_) = string(i) | |
| o(i::Char ,_) = string(i) | |
| o(i::Number ,d=2) = string(round(i;digits=d)) | |
| o(i::Array ,d=2) = "["*join((o(x,d) for x in i), ", ")*"]" | |
| o(i::NamedTuple,d=2) = "{"*join(("$k="*o(v,d) for (k,v) in pairs(i)),", ")*"}" | |
| o(i::Dict ,d=2) = "{"*join(("$k="*o(v,d) for (k,v) in sort(i)), ", ")*"}" | |
| o(i::Any ,d=2) = begin | |
| s, pre="$(typeof(i)){", "" | |
| for f in sort([x for x in fieldnames(typeof(i)) | |
| if ("$x"[1] != '_')]) | |
| s = s * pre * "$f=$(o(getfield(i,f),d))" | |
| pre=", " end | |
| return s * "}" end | |
| function tests(funs...) | |
| function shout(s,c) printstyled(s;bold=true,color=c) end | |
| global rseed,help | |
| global the,_ = settings(help;update=true) | |
| cache = deepcopy(the) | |
| fails = 0 | |
| for fun in funs | |
| k = string(fun) | |
| if k==the.go || the.go=="all" | |
| shout(">> $k ",:blue) | |
| pass, rseed = true, the.seed | |
| try | |
| pass = fun() | |
| catch e | |
| @error "E> " exception=(e, catch_backtrace()) | |
| pass = false | |
| end | |
| the = deepcopy(cache) | |
| if pass == false | |
| shout("FAIL\n",:light_red) | |
| fails += 1 | |
| else shout("PASS\n",:light_green) end end end | |
| fails end |
| -include ../config/do.mk | |
| DO_what= JUJU: semi-supervised multi-objective explanations | |
| DO_copyright= Copyright (c) 2023 Tim Menzies, BSD-2. | |
| DO_repos= . ../config ../data | |
| install: $(DO_repos) packages ## get related repos | |
| ../data: | |
| (cd ..; git clone https://gist.github.com/d47b8699d9953eef14d516d6e54e742e.git data) | |
| ../config: | |
| (cd ..; git clone https://gist.github.com/42f78b8beec9e98434b55438f9983ecc.git config) | |
| julia: | |
| brew install julia | |
| brew link julia | |
| packages: ## install julia packages: | |
| julia -e 'using Pkg; Pkg.add("Parameters")' | |
| julia -e 'using Pkg; Pkg.add("ResumableFunctions")' |
| # using StackTraces | |
| # | |
| # function test1() | |
| # x=1 | |
| # try | |
| # print(x/a) | |
| # catch | |
| # stacktrace(catch_backtrace()) | |
| # end end | |
| # | |
| #o | |
| function getproperty(x::Dict{String, Int64}, f::Symbol) | |
| print(1) | |
| get(x,f) | |
| end | |
| d=Dict("a"=>1, "b"=>2) | |
| print(d.a) | |
| function tests1(k,fun) | |
| print("⚠️a $k") | |
| if fun() println(" ✅"); 0 else println(" ❌"); 1 end end | |
| print(1) | |
| exit(5) | |
| # | |
| # function tests(a) | |
| # global the,help,rseed | |
| # fails = 0 | |
| # b4 = deepcopy(the) | |
| # if the.help | |
| # print(help) | |
| # else | |
| # for (k,fun) in pairs(a) | |
| # if the.help==k || then.help=="all" | |
| # rseed = the.seed | |
| # the = deepcopy(b4) | |
| # print("⚠️a $k") | |
| # if fun() println(" ✅") | |
| # else println(" ❌"); fails += 1 end end end | |
| # | |
| # catch e | |
| # @error "Something went wrong" exception=(e, catch_backtrace()) | |
| # end end | |
| # | |
| test2() |
| # vim: set et sts=2 sw=2 ts=2 : | |
| using Random | |
| using Test | |
| include("juju.jl") | |
| function aa() | |
| typeof(coerce("true")) == typeof(true) end | |
| function bb() oo(the); false end | |
| function cc() | |
| n=0 | |
| for r in csv("../data/auto93.csv"); n=n+length(r) end | |
| n==3192 end | |
| exit(tests(aa, bb, cc)) | |
| # tests(( | |
| # libs = -> begin | |
| # )) | |
| # # | |
| # @testset "jujus" begin | |
| # @testset "libs" begin | |
| # n=0; for r in csv("../data/auto93.csv"); n=n+length(r) end | |
| # @test n==3192 | |
| # @test typeof(coerce("true")) == typeof(true) | |
| # lst= sort(many([1,2,3,4],100)) | |
| # @test 1 in lst && 4 in lst | |
| # println(the) | |
| # oo(Dict("a"=>1,"b"=>2)) | |
| # end | |
| # @testset "nums" begin | |
| # ok() | |
| # num = NUM() | |
| # [inc!(num,ranf()) for x in 1:10^4] | |
| # @test .49 < mid(num) < .51 | |
| # @test .28 < div(num) < .32 | |
| # end | |
| # @testset "syms" begin | |
| # sym = SYM() | |
| # [inc!(sym,x) for x in "aaaabbc"] | |
| # @test mid(sym) == 'a' | |
| # @test 1.37 < div(sym) < 1.38 | |
| # end | |
| # @testset "data" begin | |
| # d=holds(the.file) | |
| # oo(d.cols.y[3]) | |
| # oo(stats(d)) | |
| # d1=holds(d,d.rows) | |
| # @test d1.cols.y[1].m2 == d.cols.y[1].m2 | |
| # end | |
| # # @testset "sort" begin | |
| # # d = holds(the.file) | |
| # # println("b4 ",o(stats(d))) | |
| # # a=sort(d.rows, lt= (x,y) -> better(d,x,y)) | |
| # # println("best ", o(stats(holds(d,a[1:20])))) | |
| # # println("rest ", o(stats(holds(d,a[21:end])))) | |
| # # end | |
| # end | |
| # | |
| true |