1664318160
Julia package for deconstructing dispatch on NamedTuple
s.
Uses the variable names both for the NamedTuple
and deconstruction.
Allows replacing
f((a, b)::NamedTuple{(:a, :b), <: Tuple{Any, Int}}) = ...
(a = a, b = b, c = 3)
with
f(@eponymargs(a, b::Int)) = ...
@eponymtuple(a, b, c = 3)
It is pretty lightweight: @eponymargs
and @eponymtuple
are the only symbols exported; and the package has no dependencies.
The package is registered, install with
pkg> add EponymTuples
Author: Tpapp
Source Code: https://github.com/tpapp/EponymTuples.jl
License: View license
1664318160
Julia package for deconstructing dispatch on NamedTuple
s.
Uses the variable names both for the NamedTuple
and deconstruction.
Allows replacing
f((a, b)::NamedTuple{(:a, :b), <: Tuple{Any, Int}}) = ...
(a = a, b = b, c = 3)
with
f(@eponymargs(a, b::Int)) = ...
@eponymtuple(a, b, c = 3)
It is pretty lightweight: @eponymargs
and @eponymtuple
are the only symbols exported; and the package has no dependencies.
The package is registered, install with
pkg> add EponymTuples
Author: Tpapp
Source Code: https://github.com/tpapp/EponymTuples.jl
License: View license
1668143100
GrammaticalEvolution provides the evolutionary technique of Grammatical Evolution optimization (cite) for Julia. The library focuses on providing the tools necessary to construct a grammar and evolve a population without forcing the user to use a large framework. No XML or configuration files are necessary.
One important aspect of the GrammaticalEvolution library is that uses the strength of Julia to insert arbritrary into the program. Instead of creating a string that then has to be parsed, GrammaticalEvolution instead directly generates Julia code that can then be run. The advantages of doing so are: speeed, simplification of the grammar, and the grammar does not have to be defined in an auxillary file.
The following code defines a grammar:
@grammar <name> begin
rule1 = ...
rule2 = ...
end
The following rules are supported:
Expr
sa | b | c
a + b + c
(a + b) | (c + d)
Example
In the examples
directory there is an example to learn an arbritrary mathemtical equation. Below is an annotated version of that code.
First, we can define the grammar:
@grammar example_grammar begin
start = ex
ex = number | sum | product | (ex) | value
sum = Expr(:call, :+, ex, ex)
product = Expr(:call, :*, ex, ex)
value = :x | :y | number
number[convert_number] = digit + '.' + digit
digit = 0:9
end
Every grammar must define a start
symbol. This grammar supports equations that add and multiply values together, but it's trivial to build more mathematical operations into the grammar.
There are several items of note:
Expr
. This results in the Julia code that makes a function call to the selected function.number
rule is followed by [convert_number]
. This appends an action to the rule which is invoked when the rule gets applied.digit = 0:9
is translated into digit = 0 | 1 | 2 | .. | 9
The action convert_number
is defined as:
convert_number(lst) = float(join(lst))
Next individuals which are generated by the grammar can be defined as:
type ExampleIndividual <: Individual
genome::Array{Int64, 1}
fitness::Float64
code
function ExampleIndividual(size::Int64, max_value::Int64)
genome = rand(1:max_value, size)
return new(genome, -1.0, nothing)
end
ExampleIndividual(genome::Array{Int64, 1}) = new(genome, -1.0, nothing)
end
with a population of the individuals defined as:
type ExamplePopulation <: Population
individuals::Array{ExampleIndividual, 1}
function ExamplePopulation(population_size::Int64, genome_size::Int64)
individuals = Array(ExampleIndividual, 0)
for i=1:population_size
push!(individuals, ExampleIndividual(genome_size, 1000))
end
return new(individuals)
end
end
Finally, the evaluation function for the individuals can be defined as:
function evaluate!(grammar::Grammar, ind::ExampleIndividual)
fitness::Array{Float64, 1} = {}
# transform the individual's genome into Julia code
try
ind.code = transform(grammar, ind)
@eval fn(x, y) = $(ind.code)
catch e
println("exception = $e")
ind.fitness = Inf
return
end
# evaluate the generated code at multiple points
for x=0:10
for y=0:10
# this the value of the individual's code
value = fn(x, y)
# the difference between the ground truth
diff = (value - gt(x, y)).^2
if !isnan(diff) && diff > 0
insert!(fitness, length(fitness)+1, sqrt(diff))
elseif diff == 0
insert!(fitness, length(fitness)+1, 0)
end
end
end
# total fitness is the average over all of the sample points
ind.fitness = mean(fitness)
end
To use our defined grammar and population we can write:
# here is our ground truth
gt(x, y) = 2*x + 5*y
# create population
pop = ExamplePopulation(500, 100)
fitness = Inf
generation = 1
while fitness > 1.0
# generate a new population (based off of fitness)
pop = generate(example_grammar, pop, 0.1, 0.2, 0.2)
# population is sorted, so first entry it the best
fitness = pop[1].fitness
println("generation: $generation, max fitness=$fitness, code=$(pop[1].code)")
generation += 1
end
A couple items of note:
generate
is defined in the base package, it is easy to write your own version.Population
and Individual
are user defined. The fields of these types can differ from what are used in ExamplePopulation
and ExampleIndividual
. However, this may require several methods to be defined so the library can index into the population and genome.The following piece of code in evaluate!
may look strange:
ind.code = transform(grammar, ind)
@eval fn(x, y) = $(ind.code)
So it's worth explaining it in a little more detail. The first part ind.code = transform(grammar, ind)
takes the current genome of the genome and turns it into unevalauate Julia code. In the code we use the variables x
and y
which are currently not defined.
The variables x
and y
are defined in the loop further below. However, they must first be bound to the generated code. Simply running eval
won't work because it is designed to only use variables defined in the global scope. The line @eval fn(x, y) = $(ind.code)
creates a function that has its body bound to an evaluated version of the code. When fn(x, y)
is called, the variables x
and y
will now be in scope of the code.
Author: Abeschneider
Source Code: https://github.com/abeschneider/GrammaticalEvolution
License: View license
1660036740
Diversity is a Julia package that provides functionality for measuring alpha, beta and gamma diversity of metacommunities (e.g. ecosystems) and their constituent subcommunities. It uses the diversity measures described in the arXiv paper arXiv:1404.6520 (q-bio.QM), How to partition diversity. It also provides a series of other older diversity measures through sub-modules. Currently these are all ecological diversity measures, but this will be expanded through interfacing to EcoJulia and BioJulia.
This package is in beta now, but is cross-validated against our R package boydorr/rdiversity, which is developed independently, so please raise an issue if you find any problems. We now use a DataFrame as the common output format for all of the diversity calculations to provide consistency with our R package rdiversity. The code is not optimised for speed at the moment due to the substantial changes that have happened to it under the hood, and the Phylogenetics submodule is also recently revised, and may need further improvements.
The package is registered in the General
registry on v1.x and so can be installed with add
. For example on Julia v1.6:
(@v1.6) pkg> add Diversity
Resolving package versions...
Updating `~/.julia/environments/v1.6/Project.toml`
[d3d5718d] + Diversity v0.5.5
Updating `~/.julia/environments/v1.6/Manifest.toml`
[d3d5718d] + Diversity v0.5.5
(@v1.6) pkg>
The package is confirmed to work against the current LTS Julia v1.4 release and the latest release on Linux, macOS, and Windows. It is also tested against nightly.
Contributions are very welcome, as are feature requests and suggestions. Please open an issue if you encounter any problems or would just like to ask a question.
The main package provides basic numbers-equivalent diversity measures (described in Hill, 1973), similarity-sensitive diversity measures (generalised from Hill, and described in Leinster and Cobbold, 2012), and related alpha, beta and gamma diversity measures at the level of the metacommunity and its component subcommunities (generalised in turn from Leinster and Cobbold, and described in arXiv:1404.6520 (q-bio.QM)). The diversity functions exist both with unicode names (e.g. ᾱ()), which are not automatically exported as we feel they are too short and with matching ascii names (e.g. NormalisedAlpha()), which are. We also provide a general function for extract any diversity measure for a series of subcommunity relative abundances.
Before calculating diversity a Metacommunity
object must be created. This object contains all the information needed to calculate diversity.
# Load the package into Julia
using Diversity
# Example population
pop = [1 1 0; 2 0 0; 3 1 4]
pop = pop / sum(pop)
# Create Metacommunity object
meta = Metacommunity(pop)
First we need to calculate the low-level diversity component seperately, by passing a metacommunity
object to the appropriate function; RawAlpha()
, NormalisedAlpha()
, RawBeta()
, NormalisedBeta()
, RawRho()
, NormalisedRho()
, or Gamma()
.
# First, calculate the normalised alpha component
component = NormalisedAlpha(meta)
Afterwhich, subdiv()
or metadiv()
are used to calculate subcommunity or metacommunity diversity, respectively (since both subcommunity and metacommunity diversity measures are transformations of the same low-level components, this is computationally more efficient).
# Then, calculate species richness of the subcommunities
subdiv(component, 0)
# or the average (alpha) species richness across the whole population
metadiv(component, 0)
# We can also generate a diversity profile by calculating multiple q-values simultaneously
df = subdiv(component, 0:30)
In some instances, it may be useful to calculate all subcommunity (or metacommunity) measures. In which case, a Metacommunity
object may be passed directly to subdiv()
or metadiv()
:
# To calculate all subcommunity diversity measures
subdiv(meta, 0:2)
# To calculate all metacommunity diversity measures
metadiv(meta, 0:2)
Alternatively, if computational efficiency is not an issue, a single measure of diversity may be calculated directly by calling a wrapper function:
norm_sub_alpha(meta, 0:2)
A complete list of these functions is shown below:
raw_sub_alpha()
: per-subcommunity estimate of naive-community metacommunity diversitynorm_sub_alpha()
: similarity-sensitive diversity of each subcommunity in isolationraw_sub_rho()
: redundancy of individual subcommunitiesnorm_sub_rho()
: representativeness of individual subcommunitiesraw_sub_beta()
: distinctiveness of individual subcommunitiesnorm_sub_beta()
: per-subcommunity estimate of effective number of distinct subcommunitiessub_gamma()
: contribution per individual in a subcommunity toward metacommunity diversityraw_meta_alpha()
: naive-community metacommunity diversitynorm_meta_alpha()
: average similarity-sensitive diversity of subcommunitiesraw_meta_rho()
: average redundancy of subcommunitiesnorm_meta_rho()
: average representativeness of subcommunitiesraw_meta_beta()
: average distinctiveness of subcommunitiesnorm_meta_beta()
: effective number of distinct subcommunitiesmeta_gamma()
: metacommunity similarity-sensitive diversityPhylogenetic diversity (described here) is automatically included in the Diversity module when the Phylo
package is loaded. Documentation for these diversity measures can be found here. The phylogenetics code relies on the Phylo package to generate trees to incorporate into the diversity code, and the ppropriate code will be created when both main packages are loaded:
julia> using Diversity, Phylo
julia> communities = [4 1; 3 2; 1 0; 0 1] / 12;
julia> nt = rand(Nonultrametric(4))
RootedTree with 4 tips, 7 nodes and 6 branches.
Leaf names are tip 1, tip 2, tip 4 and tip 3
julia> metaphylo = Metacommunity(communities, PhyloBranches(nt));
julia> raw_meta_rho(metaphylo, [1, 2])
2×8 DataFrame
│ Row │ div_type │ measure │ q │ type_level │ type_name │ partition_level │ partition_name │ diversity │
│ │ String │ String │ Int64 │ String │ String │ String │ String │ Float64 │
├─────┼─────────────────────┼─────────┼───────┼────────────┼───────────┼─────────────────┼────────────────┼───────────┤
│ 1 │ Phylogenetic Branch │ RawRho │ 1 │ types │ │ metacommunity │ │ 1.7787 │
│ 2 │ Phylogenetic Branch │ RawRho │ 2 │ types │ │ metacommunity │ │ 1.66749 │
The package also provides some other sub-modules for related measures:
Many existing ecological diversity measures can be derived from our diversity measures, and so we provide them in the Diversity.Ecology submodule along with generalised versions of them that relate to our general measures of alpha, beta and gamma diversity at subcommunity and metacommunity levels. The generalisations of species richness, Shannon entropy and Simpson's index are the only standard measures we are aware of whose subcommunity components sum directly to the corresponding metacommunity measure (although note that Simpson's index decreases for increased diversity, so small components are more diverse). Documentation for these diversity measures can be found here.
Hill numbers are found in the Diversity.Hill sub-module. Documentation for these diversity measures can be found here.
Lou Jost's diversity measures are found in the Diversity.Jost sub-module. Documentation for these diversity measures is here.
Documentation is generated by the Base documentation in Julia and online via the Documenter package.
Accessing the documentation in Julia is easy:
using Diversity
# Returns any documentation for the subdiv() function
?subdiv
The documentation is also available online.
The online documentation for the current stable release is here.
The online documentation for the latest dev (unreleased) branch is here.
Author: EcoJulia
Source Code: https://github.com/EcoJulia/Diversity.jl
License: BSD-2-Clause license
1668253200
Facilitates wrapping Julia functions into a remote callable API via message queues (e.g. ZMQ, RabbitMQ) and HTTP.
It can plug in to a different messaging infrastructure through an implementation of transport (AbstractTransport
) and message format (AbstractMsgFormat
). Multiple instances of the front (HTTP API) and back (Julia methods) end can help scale an application. Bundled with the package are implementations for:
Channel
for transport within the same processDict
as message format, for use within the same processCombined with a HTTP/Messaging frontend (like JuliaBox), it helps deploy Julia packages and code snippets as hosted, auto-scaling HTTP APIs.
Some amount of basic request filtering and pre-processing is possible by registering a pre-processor with the HTTP frontend. The pre-processor is run at the HTTP server side, where it has access to the complete request. It can examine headers and data and take decision whether to allow calling the service or respond directly and immediately. It can also rewrite the request before passing it on to the service.
A pre-processor can be used to implement features like authentication, request rewriting and such. See example below.
Create a file srvr.jl
with the following code
# Load required packages
using JuliaWebAPI
# Define functions testfn1 and testfn2 that we shall expose
function testfn1(arg1, arg2; narg1="1", narg2="2")
return (parse(Int, arg1) * parse(Int, narg1)) + (parse(Int, arg2) * parse(Int, narg2))
end
testfn2(arg1, arg2; narg1="1", narg2="2") = testfn1(arg1, arg2; narg1=narg1, narg2=narg2)
# Expose testfn1 and testfn2 via a ZMQ listener
process(
JuliaWebAPI.create_responder([
(testfn1, true),
(testfn2, false)
], "tcp://127.0.0.1:9999", true, "")
)
Start the server process in the background. This process will run the ZMQ listener.
julia srvr.jl &
Then, on a Julia REPL, run the following code
using JuliaWebAPI #Load package
#Create the ZMQ client that talks to the ZMQ listener above
const apiclnt = APIInvoker("tcp://127.0.0.1:9999");
#Start the HTTP server in current process (Ctrl+C to interrupt)
run_http(apiclnt, 8888)
Then, on your browser, navigate to http://localhost:8888/testfn1/4/5?narg1=6&narg2=4
This will return the following JSON response to your browser, which is the result of running the testfn1
function defined above: {"data"=>44,"code"=>0}
Example of an authentication filter implemented using a pre-processor:
function auth_preproc(req::HTTP.Request)
if !validate(req)
return HTTP.Response(401)
end
return nothing
end
run_http(apiclnt, 8888, auth_preproc)
Author: JuliaWeb
Source Code: https://github.com/JuliaWeb/JuliaWebAPI.jl
License: View license
1673316180
Julia package for limiting the rate at which expressions are evaluated. This can be useful for rate limiting access to network resources (e.g. websites). All methods are thread safe.
This example uses the Token-Bucket algorithm to limit how quickly the functions can be called.
using RateLimiter
tokens_per_second = 2
max_tokens = 100
initial_tokens = 0
limiter = TokenBucketRateLimiter(tokens_per_second, max_tokens, initial_tokens)
function f_cheap()
println("cheap")
return 1
end
function f_costly()
println("costly")
return 2
end
result = 0
for i in 1:10
result += @rate_limit limiter 1 f_cheap()
result += @rate_limit limiter 10 f_costly()
end
println("RESULT: $result")
See https://chipkent.github.io/RateLimiter.jl/dev/.
Pull requests will publish documentation to https://chipkent.github.io/RateLimiter.jl/previews/PR##
.
Author: Chipkent
Source Code: https://github.com/chipkent/RateLimiter.jl
License: MIT license