API Reference
AllocationOpt.AnalyticOpt
— TypeAnalyticOpt{
T<:Real,
V<:AbstractArray{T},
U<:AbstractArray{T},
A<:AbstractArray{T},
S<:AbstractVector{<:Hook},
} <: SemioticOpt.OptAlgorithm
Optimise the indexing reward analytically.
Fields
x::V
is the current best guess for the solution. Typically zeros.Ω::U
is the allocation vector of other indexers.ψ::A
is the signal vector.σ::T
is the stake.hooks::S
are the hooks
Example
julia> using AllocationOpt
julia> using SemioticOpt
julia> x = zeros(2)
julia> Ω = [1.0, 1.0]
julia> ψ = [10.0, 10.0]
julia> σ = 5.0
julia> alg = AllocationOpt.AnalyticOpt(;
x=x, Ω=Ω, ψ=ψ, σ=σ, hooks=[StopWhen((a; kws...) -> kws[:i] > 1)]
)
julia> f = x -> x # This doesn't matter. `f` isn't used by the algorithm.
julia> alg = minimize!(f, alg)
julia> SemioticOpt.x(alg)
2-element Vector{Float64}:
2.5
2.5
AllocationOpt.allocatablesubgraphs
— Method allocatablesubgraphs(s::FlexTable, config::AbstractDict)
For the subgraphs s
return a view of the subgraphs on which we can allocate.
julia> using AllocationOpt
julia> using TheGraphData
julia> s = flextable([
Dict("ipfsHash" => "Qma", "signalledTokens" => 10,),
Dict("ipfsHash" => "Qmb", "signalledTokens" => 20),
Dict("ipfsHash" => "Qmc", "signalledTokens" => 5),
])
julia> config = Dict(
"whitelist" => String["Qmb", "Qmc"],
"blacklist" => String[],
"frozenlist" => String[],
"pinnedlist" => String[],
"min_signal" => 0.0
)
julia> fs = AllocationOpt.allocatablesubgraphs(s, config)
FlexTable with 2 columns and 2 rows:
signalledTokens ipfsHash
┌──────────────────────────
1 │ 20 Qmb
2 │ 5 Qmc
AllocationOpt.allocate_action
— Methodallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)
Create and push allocate actions to the action queue.
julia> using AllocationOpt
julia> using TheGraphData
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
])
julia> t = flextable([
Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"),
Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
])
julia> config = Dict(
"indexer_url" => "http://localhost:18000"
)
julia> TheGraphData.client!(config["indexer_url"])
julia> AllocationOpt.allocate_action(Val(:actionqueue), a, t, config)
1-element Vector{Dict{String, Any}}:
Dict("amount" => "2", "priority" => 0, "status" => AllocationOpt.queued, "source" => "AllocationOpt", "reason" => "Expected profit: 0", "type" => AllocationOpt.allocate, "deploymentID" => "Qmb", "protocolNetwork" => "mainnet")
AllocationOpt.allocate_action
— Methodallocate_action(::Val{:none}, a, t, config)
Do nothing.
julia> using AllocationOpt
julia> using TheGraphData
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
])
julia> t = flextable([
Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"),
Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
])
julia> AllocationOpt.allocate_action(Val(:none), a, t, Dict())
AllocationOpt.allocate_action
— Methodallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)
Print the rules that allocates to new subgraphs.
```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"), Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> AllocationOpt.allocate_action(Val(:rules), a, t, Dict()) graph indexer rules set Qmb decisionBasis always allocationAmount 2 1-element Vector{String}: "[0mgraph indexer rules set Qmb decisionBasis always allocationAmount 2"
AllocationOpt.aquery
— Methodaquery(id::AbstractString)
Return the components of a GraphQL query for active allocations of indexer id
.
For use with the TheGraphData.jl package.
julia> using AllocationOpt
julia> id = "0xa"
julia> value, args, fields = AllocationOpt.aquery(id)
("allocations", Dict{String, Union{Dict{String, String}, String}}("where" => Dict("status" => "Active", "indexer" => "0xa")), ["allocatedTokens", "id", "subgraphDeployment{ipfsHash}"])
Extended Help
You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl
AllocationOpt.availablestake
— Methodavailable(::Val{:indexer}, x)
The tokens available for the indexer to allocate in table x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"stakedTokens" => 10,
"delegatedTokens" => 20,
"lockedTokens" => 5,
),
])
julia> AllocationOpt.availablestake(Val(:indexer), x)
25.0
AllocationOpt.bestprofitpernz
— Methodbestprofitpernz(ixs::AbstractVector{Integer}, profitmatrix::AbstractMatrix{Real})
Compute the best profit amongst the given ixs
given profit matrix p
julia> using AllocationOpt
julia> ixs = Dict([1] => [1], [2] => [2])
julia> profitmatrix = [[2.5 5.0]; [2.5 1.0]]
julia> AllocationOpt.bestprofitpernz.(values(ixs), Ref(profitmatrix))
2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:
(profit = 5.0, index = 1)
(profit = 6.0, index = 2)
AllocationOpt.blockissuance
— Methodblockissuance(::Val{:network}, x)
The tokens issued per block.
```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "networkGRTIssuancePerBlock" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.blockissuance(Val(:network), n) 1
AllocationOpt.blocksperepoch
— Methodblocksperepoch(::Val{:network}, x)
The number of blocks in each epoch.
```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "networkGRTIssuancePerBlock" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.blocksperepoch(Val(:network), n) 28
AllocationOpt.closeipfs
— Methodcloseipfs(existingipfs, proposedipfs, frozenlist)
Get the list of the ipfs hashes of allocations to close.
julia> using AllocationOpt
julia> AllocationOpt.closeipfs(["Qma"], ["Qmb"], String[])
1-element Vector{String}:
"Qma"
AllocationOpt.configuredefaults!
— Methodconfiguredefaults!(config::AbstractDict)
Set default values for the config dictionary if the value was not specified in the config file.
Config Specification
id::String
: The ID of the indexer for whom we're optimising. No default value.network_subgraph_endpoint::String
: The network subgraph endpoint to query. By default,"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet"
writedir::String
: The directory to which to write the results of optimisation. If don't specifyreaddir
,writedir
also specifies the path to which to save the input data tables. By default,"."
readdir::Union{String, Nothing}
: The directory from which to read saved data tables. This speeds up the process as we won't have to query the network subgraph for the relevant data. If you don't specifyreaddir
, we will query your specifiednetwork_subgraph_endpoint
for the data and write it to CSV files inwritedir
. This way, you can use your previouswritedir
as yourreaddir
in future runs. By default,nothing
whitelist::Vector{String}
: A list of subgraph IPFS hashes that you want to consider as candidates to which to allocate. If you leave this empty, we'll assume all subgraphs are in the whitelist. By default,String[]
blacklist::Vector{String}
: A list of subgraph IPFS hashes that you do not want to consider allocating to. For example, this list could include broken subgraphs or subgraphs that you don't want to index. By default,String[]
frozenlist::Vector{String}
: If you have open allocations that you don't want to change, add the corresponding subgraph IPFS hashes to this list. By default,String[]
pinnedlist::Vector{String}
: If you have subgraphs that you absolutely want to be allocated to, even if only with a negligible amount of GRT, add it to this list. By default,String[]
allocation_lifetime::Integer
: The number of epochs for which you expect the allocations the optimiser finds to be open. By default,28
gas::Real
: The estimated gas cost in GRT to open/close allocations. By default,100
min_signal::Real
: The minimum amount of signal in GRT that must be on a subgraph in order for you to consider allocating to it. By default,100
max_allocations::Integer
: The maximum number of new allocations you'd like the optimiser to consider opening. By default,10
num_reported_options::Integer
: The number of proposed allocation strategies to report. For example, if you select10
we'd report best 10 allocation strategies ranked by profit. By default,1
verbose::Bool
: If true, the optimiser will print details about what it is doing to stdout. By default,false
execution_mode::String
: How the optimiser should execute the allocation strategies it finds. Options are"none"
, which won't do anything,"actionqueue"
, which will push actions to the action queue, and"rules"
, which will generate indexing rules. By default,"none"
indexer_url::Union{String, Nothing}
: The URL of the indexer management server you want to execute the allocation strategies on. If you specify"actionqueue"
, you must also specifyindexer_url
. By default,nothing
opt_mode::String
: We support three optimisation modes. One is"fastnogas"
. This mode does not consider gas costs and optimises allocation amount over all subgraph deployments. Second one is"fastgas"
. This mode considers gas, may not find the optimal strategy and could potentially fail to converge. This mode is also used to the topnum_reported_options
allocation strategies. The final mode is"optimal"
. This mode is slower, but it satisfies stronger optimality conditions. It will find strategies at least as good as"fastgas"
, but not guaranteed to be better. By default,"optimal"
mode to find the optimal allocation. By default,"optimal"
protocol_network::String
: Defines the protocol network that allocation transactions should be sent to. The current protocol network options are "mainnet", "goerli", "arbitrum", and "arbitrum-goerli". By default,"mainnet"
syncing_networks::Vector{String}
: The list of syncing networks to support when selecting the set of possible subgraphs. This list should match the networks available to your graph-node. By default, the list is a singleton of your protocol network
julia> using AllocationOpt
julia> config = Dict{String, Any}("id" => "0xa")
julia> config = AllocationOpt.configuredefaults!(config)
Dict{String, Any} with 16 entries:
"execution_mode" => "none"
"readdir" => nothing
"writedir" => "."
"num_reported_options" => 1
"id" => "0xa"
"pinnedlist" => String[]
"indexer_url" => nothing
"gas" => 100
"allocation_lifetime" => 28
"blacklist" => String[]
"verbose" => false
"min_signal" => 100
"network_subgraph_endpoint" => "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet"
"whitelist" => String[]
"protocol_network" => "mainnet"
"syncing_networks" => String["mainnet"]
AllocationOpt.correcttypes!
— Methodcorrecttypes!(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable)
Convert all tables to be in GRT.
julia> using AllocationOpt
julia> using TheGraphData
julia> i = flextable([
Dict(
"stakedTokens" => "1",
"delegatedTokens" => "0",
"id" => "0xa",
"lockedTokens" => "0",
),
])
julia> s = flextable([
Dict(
"stakedTokens" => "1",
"signalledTokens" => "0",
"ipfsHash" => "Qma",
),
])
julia> a = flextable([
Dict(
"allocatedTokens" => "1",
"subgraphDeployment.ipfsHash" => "Qma",
),
])
julia> n = flextable([
Dict(
"id" => 1,
"networkGRTIssuancePerBlock" => "1",
"epochLength" => 28,
"totalTokensSignalled" => "2",
"currentEpoch" => 1,
)
])
julia> i, a, s, n = AllocationOpt.correcttypes!(i, a, s, n)
AllocationOpt.correcttypes!
— Methodcorrecttypes!(::Val{:allocation}, a::FlexTable)
Convert the string currency fields in the allocation table to be in GRT.
julia> using AllocationOpt
julia> using TheGraphData
julia> a = flextable([
Dict(
"allocatedTokens" => "1",
"subgraphDeployment.ipfsHash" => "Qma",
),
])
julia> AllocationOpt.correcttypes!(Val(:allocation), a)
FlexTable with 2 columns and 1 row:
subgraphDeployment.ipfsHash allocatedTokens
┌─────────────────────────────────────────────
1 │ Qma 1.0e-18
AllocationOpt.correcttypes!
— Methodcorrecttypes!(::Val{:indexer}, i::FlexTable)
Convert the string currency fields in the indexer table to be in GRT.
julia> using AllocationOpt
julia> using TheGraphData
julia> i = flextable([
Dict(
"stakedTokens" => "1",
"delegatedTokens" => "0",
"id" => "0xa",
"lockedTokens" => "0",
),
])
julia> AllocationOpt.correcttypes!(Val(:indexer), i)
FlexTable with 4 columns and 1 row:
stakedTokens delegatedTokens id lockedTokens
┌─────────────────────────────────────────────────
1 │ 1.0e-18 0.0 0xa 0.0
AllocationOpt.correcttypes!
— Methodcorrecttypes!(::Val{:network}, n::FlexTable)
Convert the string currency fields in the network table to be in GRT.
julia> using AllocationOpt
julia> using TheGraphData
julia> n = flextable([
Dict(
"id" => 1,
"networkGRTIssuancePerBlock" => "1",
"epochLength" => 28,
"totalTokensSignalled" => "2",
"currentEpoch" => 1,
)
])
julia> AllocationOpt.correcttypes!(Val(:network), n)
FlexTable with 6 columns and 1 row:
totalTokensSignalled currentEpoch id networkGRTIssuancePerBlock epochLength
┌────────────────────────────────────────────────────────────────────────────────
1 │ 2.0e-18 1 1 1.0e-18 28
AllocationOpt.correcttypes!
— Methodcorrecttypes!(::Val{:subgraph}, s::FlexTable)
Convert the string currency fields in the subgraph table to be in GRT.
julia> using AllocationOpt
julia> using TheGraphData
julia> s = flextable([
Dict(
"stakedTokens" => "1",
"signalledTokens" => "0",
"ipfsHash" => "Qma",
"deniedAt" => 0,
),
])
julia> AllocationOpt.correcttypes!(Val(:subgraph), s)
FlexTable with 4 columns and 1 row:
deniedAt stakedTokens signalledTokens ipfsHash
┌──────────────────────────────────────────────────
1 │ 0 1.0e-18 0.0 Qma
AllocationOpt.currentepoch
— Methodcurrentepoch(::Val{:network}, x)
The current epoch.
```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "networkGRTIssuancePerBlock" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.currentepoch(Val(:network), n) 1
AllocationOpt.delegation
— Methoddelegation(::Val{:indexer}, x)
The tokens delegated to the indexer in table x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"delegatedTokens" => 10,
),
])
julia> AllocationOpt.delegation(Val(:indexer), x)
10
AllocationOpt.deniedat
— Methoddeniedat(::Val{:subgraph}, x)
If this value is non-zero, the subgraph doesn't receive indexing rewards.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict("deniedAt" => 10,),
Dict("deniedAt" => 0,),
])
julia> AllocationOpt.deniedat(Val(:subgraph), x)
2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
10
0
AllocationOpt.deniedzeroixs
— Methoddeniedzeroixs(s::FlexTable)
Find the indices of subgraphs that have "deniedAt" equal to zero.
julia> using AllocationOpt
julia> using TheGraphData
julia> s = flextable([
Dict("ipfsHash" => "Qma", "signalledTokens" => 5.0, "deniedAt" => 0),
Dict("ipfsHash" => "Qmb", "signalledTokens" => 10.0, "deniedAt" => 10),
Dict("ipfsHash" => "Qmc", "signalledTokens" => 15.0, "deniedAt" => 0),
])
julia> AllocationOpt.deniedzeroixs(s)
2-element Vector{Int64}:
1
3
AllocationOpt.dual
— Methoddual(Ω, ψ, σ)
Analytic solution of the dual form of the optimisation problem given signals ψ
, allocation vector Ω
, and stake σ
.
You should probably not use this function directly. Use optimizeanalytic
instead.
AllocationOpt.execute
— Methodexecute(
a::FlexTable,
ix::Integer,
s::FlexTable,
xs::AbstractMatrix{T},
ps::AbstractMatrix{T},
config::AbstractDict
) where {T<:Real}
Execute the actions picked by the optimiser.
julia> using AllocationOpt
julia> using TheGraphData
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
])
julia> xs = [[2.5 5.0]; [2.5 0.0]]
julia> ps = [[3.0 5.0]; [3.0 0.0]]
julia> s = flextable([
Dict("stakedTokens" => "1", "signalledTokens" => "0", "ipfsHash" => "Qma"),
Dict("stakedTokens" => "2", "signalledTokens" => "0", "ipfsHash" => "Qmb"),
])
julia> config = Dict("execution_mode" => "none")
julia> ix = 1
julia> AllocationOpt.execute(a, ix, s, xs, ps, config)
AllocationOpt.formatconfig!
— Methodformatconfig!(config::AbstractDict)
Given a config
, reformat values that need to be standardised.
julia> using AllocationOpt
julia> config = Dict("id" => "0xA")
julia> AllocationOpt.formatconfig!(config)
Dict{String, String} with 1 entry:
"id" => "0xa"
AllocationOpt.frozen
— Methodfrozen(a::FlexTable, config::AbstractDict)
The frozen stake of the indexer with allocations a
.
julia> using AllocationOpt
julia> using TheGraphData
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "allocatedTokens" => 5),
Dict("subgraphDeployment.ipfsHash" => "Qmb", "allocatedTokens" => 10),
])
julia> config = Dict("frozenlist" => ["Qma", "Qmb"])
julia> AllocationOpt.frozen(a, config)
15.0
AllocationOpt.groupunique
— Methodgroupunique(x::AbstractVector)
Find the indices of each unique value in x
julia> using AllocationOpt
julia> x = [1, 2, 1, 3, 2, 3]
julia> AllocationOpt.groupunique(x)
Dict{Vector{Int64}, Vector{Int64}} with 3 entries:
[3] => [4, 6]
[1] => [1, 3]
[2] => [2, 5]
AllocationOpt.id
— Methodid(::Val{:allocation}, x)
Get the allocation id for each allocation in x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"id" => "0x1"
),
])
julia> AllocationOpt.id(Val(:allocation), x)
1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:
"0x1"
AllocationOpt.indexingreward
— Methodindexingreward(x::Real, Ω::Real, ψ::Real, Φ::Real, Ψ::Real)
The indexing rewards for the allocation scalar x
given signals ψ
, the existing allocation on subgraphs Ω
, token issuance Φ
, and total signal Ψ
.
julia> using AllocationOpt
julia> ψ = 0.0
julia> Ω = 1.0
julia> Φ = 1.0
julia> Ψ = 2.0
julia> x = 1.0
julia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)
0.0
AllocationOpt.indexingreward
— Methodindexingreward(
ixs::AbstractArray{Integer},
x::AbstractVector{Real},
Ω::AbstractVector{Real},
ψ::AbstractVector{Real},
Φ::Real,
Ψ::Real
)
The indexing rewards for the allocation vector x
given signals ψ
, the existing allocations on subgraphs Ω
, token issuance Φ
, and total signal Ψ
. Here ixs
is a vector of indices Ω
, and ψ
. x
will be filtered by SemioticOpt
, so we don't do this here.
julia julia> using AllocationOpt julia> ixs = Int32[2] julia> ψ = [0.0, 1.0] julia> Ω = [1.0, 1.0] julia> Φ = 1.0 julia> Ψ = 2.0 julia> x = [0.0, 1.0] julia> AllocationOpt.indexingreward(ixs, x, Ω, ψ, Φ, Ψ) 0.25
`
AllocationOpt.indexingreward
— Methodindexingreward(
x::AbstractVector{Real},
Ω::AbstractVector{Real},
ψ::AbstractVector{Real},
Φ::Real,
Ψ::Real
)
The indexing rewards for the allocation vector x
given signals ψ
, the existing allocations on subgraphs Ω
, token issuance Φ
, and total signal Ψ
.
julia> using AllocationOpt
julia> ψ = [0.0, 1.0]
julia> Ω = [1.0, 1.0]
julia> Φ = 1.0
julia> Ψ = 2.0
julia> x = [0.0, 1.0]
julia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)
0.25
AllocationOpt.ipfshash
— Methodipfshash(::Val{:allocation}, x)
Get the ipfs hash of x
when x
is part of the allocation table.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"subgraphDeployment.ipfsHash" => "Qma",
),
])
julia> AllocationOpt.ipfshash(Val(:allocation), x)
1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:
"Qma"
AllocationOpt.ipfshash
— Methodipfshash(::Val{:subgraph}, x)
Get the ipfs hash of x
when x
is part of the allocation table.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"ipfsHash" => "Qma",
),
])
julia> AllocationOpt.ipfshash(Val(:subgraph), x)
1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:
"Qma"
AllocationOpt.iquery
— Methodiquery(id::AbstractString)
Return the components of a GraphQL query for the stake of indexer id
.
For use with the TheGraphData.jl package.
julia> using AllocationOpt
julia> id = "0xa"
julia> value, args, fields = AllocationOpt.iquery(id)
("indexer", Dict{String, Union{Int64, Dict{String, String}, String}}("id" => "0xa"), ["delegatedTokens", "stakedTokens", "lockedTokens"])
Extended Help
You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl
AllocationOpt.lipschitzconstant
— Methodlipschitzconstant(ψ, Ω)
The Lipschitz constant of the indexing reward function given signals ψ
and allocations Ω
.
julia> using AllocationOpt
julia> ψ = [0.0, 1.0]
julia> Ω = [1.0, 1.0]
julia> AllocationOpt.lipschitzconstant(ψ, Ω)
2.0
AllocationOpt.locked
— Methodlocked(::Val{:indexer}, x)
The locked tokens of the indexer in table x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"lockedTokens" => 10,
),
])
julia> AllocationOpt.locked(Val(:indexer), x)
10
AllocationOpt.newtokenissuance
— Methodnewtokenissuance(n::FlexTable, config::Dict)
How many new tokens are issued over the allocation lifetime given network parameters n
. Calcualted by networkGRTIssuancePerBlock * epochLength * allocation_lifetime
julia> using AllocationOpt
julia> using TheGraphData
julia> n = flextable([
Dict(
"id" => 1,
"networkGRTIssuancePerBlock" => 2,
"epochLength" => 1,
"totalTokensSignalled" => 2,
"currentEpoch" => 1,
)
])
julia> config = Dict("allocation_lifetime" => 1)
julia> AllocationOpt.newtokenissuance(n, config)
1.0
AllocationOpt.nonzero
— Methodnonzero(v::AbstractVector)
Get the non-zero elements of vector v
.
julia> using AllocationOpt
julia> v = [0.0, 1.0]
julia> AllocationOpt.nonzero(v)
1-element view(::Vector{Float64}, [2]) with eltype Float64:
1.0
AllocationOpt.nquery
— Methodnquery()
Return the components of a GraphQL query for network parameters.
For use with the TheGraphData.jl package.
julia> using AllocationOpt
julia> value, args, fields = AllocationOpt.nquery()
("graphNetwork", Dict("id" => 1), ["id", "networkGRTIssuance", "epochLength", "totalTokensSignalled", "currentEpoch"])
Extended Help
You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl
AllocationOpt.optimize
— Methodoptimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config::AbstractDict)
Find the optimal solution vector given allocations of other indexers Ω
, signals ψ
, available stake σ
, new tokens issued Φ
, total signal Ψ
, and gas in grt g
. rixs
are the indices of subgraphs that are eligible to receive indexing rewards.
Dispatches to optimize
with the opt_mode
key.
If opt_mode
is fastgas
, then run projected gradient descent with GSSP and Halpern. If opt_mode
is fastnogas
, then run analytics solution over all eligible subgraphs. If opt_mode
is optimal
, then run Pairwise Greedy Optimisation.
julia> using AllocationOpt
julia> config = Dict("opt_mode" => "fastgas")
julia> rixs = [1, 2]
julia> Ω = [1.0, 1.0]
julia> ψ = [10.0, 10.0]
julia> σ = 5.0
julia> K = 2
julia> Φ = 1.0
julia> Ψ = 20.0
julia> g = 0.01
julia> xs, nonzeros, profits = AllocationOpt.optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config)
([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
AllocationOpt.optimize
— Methodoptimize(::Val{:fastgas}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)
Find the optimal vectors for k ∈ [1,K
] given allocations of other indexers Ω
, signals ψ
, available stake σ
, new tokens issued Φ
, total signal Ψ
, and gas in grt g
. rixs
are the indices of subgraphs that are eligible to receive indexing rewards.
julia> using AllocationOpt
julia> rixs = [1, 2]
julia> Ω = [1.0, 1.0]
julia> ψ = [10.0, 10.0]
julia> σ = 5.0
julia> K = 2
julia> Φ = 1.0
julia> Ψ = 20.0
julia> g = 0.01
julia> xs, nonzeros, profits = AllocationOpt.optimize(Val(:fastgas), Ω, ψ, σ, K, Φ, Ψ, g, rixs)
([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
AllocationOpt.optimize
— Methodoptimize(::Val{:fastnogas}, Ω, ψ, σ, _, Φ, Ψ, g, rixs)
Find the analytic optimal vector for given allocations of other indexers Ω
, signals ψ
, available stake σ
, new tokens issued Φ
, total signal Ψ
. g
is the gas, but it is not used since analytic optimisation assumes 0 gas fees. rixs
are the indices of subgraphs that are eligible to receive indexing rewards.
julia> using AllocationOpt
julia> rixs = [1, 2]
julia> Ω = [1.0, 1.0]
julia> ψ = [10.0, 10.0]
julia> σ = 5.0
julia> Φ = 1.0
julia> Ψ = 20.0
julia> g = 0.01
julia> xs, nonzeros, profits = AllocationOpt.optimize(Val(:fastnogas), Ω, ψ, σ, K, Φ, Ψ, g, rixs)
([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
AllocationOpt.optimize
— Methodoptimize(::Val{:optimal}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)
Find the optimal solution vector given allocations of other indexers Ω
, signals ψ
, available stake σ
, new tokens issued Φ
, total signal Ψ
, and gas in grt g
. rixs
are the indices of subgraphs that are eligible to receive indexing rewards.
Example
julia> using AllocationOpt
julia> rixs = [1, 2]
julia> Ω = [1.0, 1.0]
julia> ψ = [10.0, 10.0]
julia> σ = 5.0
julia> K = 2
julia> Φ = 1.0
julia> Ψ = 20.0
julia> g = 0.01
julia> xs, nonzeros, profits = AllocationOpt.optimize(
Val(:optimal), Ω, ψ, σ, K, Φ, Ψ, g, rixs
)
([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
AllocationOpt.optimizeanalytic
— Methodoptimizeanalytic(Ω, ψ, σ)
Optimise analytically over existing allocation vector Ω
, signals ψ
, and stake σ
.
julia> using AllocationOpt
julia> Ω = [1.0, 7.0]
julia> ψ = [10.0, 5.0]
julia> σ = 5.0
julia> AllocationOpt.optimizeanalytic(Ω, ψ, σ)
2-element Vector{Float64}:
3.5283092056122474
1.4716907943877526
AllocationOpt.optimizek
— Methodoptimizek(::Val{:fastgas}, x₀, Ω, ψ, σ, k, Φ, Ψ)
Find the optimal k
sparse vector given initial value x₀
, allocations of other indexers Ω
, signals ψ
, available stake σ
, new tokens issued Φ
, and total signal Ψ
.
julia> using AllocationOpt
julia> x₀ = [2.5, 2.5]
julia> Ω = [1.0, 1.0]
julia> ψ = [10.0, 10.0]
julia> σ = 5.0
julia> k = 1
julia> Φ = 1.0
julia> Ψ = 20.0
julia> AllocationOpt.optimizek(Val(:fastgas), x₀, Ω, ψ, σ, k, Φ, Ψ)
2-element Vector{Float64}:
5.0
0.0
AllocationOpt.optimizek
— Methodoptimizek(::Val{:optimal}, x₀, Ω, ψ, σ, k, Φ, Ψ, g)
Find the optimal k
sparse vector given allocations of other indexers Ω
, signals ψ
, available stake σ
, new tokens issued Φ
, total signal Ψ
, and gas g
.
Example
julia> using AllocationOpt
julia> Ω = [1.0, 1.0]
julia> ψ = [10.0, 10.0]
julia> σ = 5.0
julia> k = 1
julia> Φ = 1.0
julia> Ψ = 20.0
julia> g = 0.01
julia> x₀ = zeros(length(Ω))
julia> x = AllocationOpt.optimizek(Val(:optimal), x₀, Ω, ψ, σ, k, Φ, Ψ, g)
2-element Vector{Float64}:
5.0
0.0
AllocationOpt.pinned
— Methodpinned(config::AbstractDict)
The pinned vector of the indexer.
julia> using AllocationOpt
julia> s = flextable([
Dict("ipfsHash" => "Qma", "signalledTokens" => 5.0),
Dict("ipfsHash" => "Qmb", "signalledTokens" => 10.0),
Dict("ipfsHash" => "Qmc", "signalledTokens" => 15.0),
])
julia> config = Dict("pinnedlist" => ["Qma", "Qmb"])
julia> AllocationOpt.pinned(s, config)
3-element Vector{Float64}:
0.1
0.1
0.0
AllocationOpt.primal
— Methodprimal(Ω, ψ, ν)
Analytic solution of the primal form of the optimisation problem given signals ψ
, allocations Ω
, and a dual solution vector ν
.
You should probably not use this function directly. Use optimizeanalytic
instead.
AllocationOpt.profit
— Methodprofit(r::Real, g::Real)
Compute the profit for one allocation with reward r
and gas cost g
.
julia> using AllocationOpt
julia> r = 10
julia> g = 1
julia> AllocationOpt.profit(r, g)
9
AllocationOpt.read
— Methodread(config::AbstractDict)
Given a config
, read the data in as flextables.
If you have specified a "readdir" in the config, this will read from CSV files in that directory. Otherwise, this will query the specified "network_subgraph_endpoint"
julia> using AllocationOpt
julia> config = Dict("verbose" => false, "readdir" => "mydatadir")
julia> i, a, s, n = AllocationOpt.read(config) # Read data from CSVs
julia> using AllocationOpt
julia> config = Dict(
"verbose" => false,
"network_subgraph_endpoint" => "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet",
"readdir" => nothing,
)
julia> i, a, s, n = AllocationOpt.read(config) # Query GQL endpoint
AllocationOpt.read
— Methodread(f::AbstractString, config::AbstractDict)
Read the CSV files from f
and return the tables from those files.
julia> using AllocationOpt
julia> i, a, s, n = AllocationOpt.read("myreaddir", Dict("verbose" => true))
AllocationOpt.read
— Methodread(::Nothing, config::AbstractDict)
Query the required data from the provided endpoint in the config
.
julia> using AllocationOpt
julia> config = Dict(
"verbose" => true,
"network_subgraph_endpoint" => "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet",
)
julia> i, a, s, n = AllocationOpt.read(nothing, config)
AllocationOpt.readconfig
— Methodreadconfig(p::AbstractString)
Read the config file from path p
. The config file must be specifed as a TOML.
See configuredefaults!
to see which fields you should specify in the config.
julia> using AllocationOpt
julia> path = "myconfig.toml"
julia> config = AllocationOpt.readconfig(path)
Dict{String, Any} with 13 entries:
"execution_mode" => "none"
"writedir" => "data"
"num_reported_options" => 2
"id" => "0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c"
"pinnedlist" => Union{}[]
"gas" => 100
"allocation_lifetime" => 28
"blacklist" => Union{}[]
"verbose" => true
"min_signal" => 100
"whitelist" => Union{}[]
"max_allocations" => 5
"frozenlist" => Union{}[]
"protocol_network" => "mainnet"
"syncing_networks" => String["mainnet", "gnosis"]
AllocationOpt.reallocate_action
— Methodreallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)
Create and push reallocate actions to the action queue.
julia> using AllocationOpt
julia> using TheGraphData
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
])
julia> t = flextable([
Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"),
Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
])
julia> config = Dict("indexer_url" => "http://localhost:18000")
julia> TheGraphData.client!(config["indexer_url"])
julia> AllocationOpt.reallocate_action(Val(:actionqueue), a, t, config)
1-element Vector{Dict{String, Any}}:
Dict("amount" => "1", "priority" => 0, "status" => AllocationOpt.queued, "allocationID" => "0xa", "source" => "AllocationOpt", "reason" => "Expected profit: 0", "type" => AllocationOpt.reallocate, "deploymentID" => "Qma", "protocolNetwork" => "mainnet")
AllocationOpt.reallocate_action
— Methodreallocate_action(::Val{:none}, a, t, config)
Do nothing.
```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"), Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> AllocationOpt.reallocate_action(Val(:none), a, t, Dict())
AllocationOpt.reallocate_action
— Methodreallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)
Print a rule that reallocates the old allocation with a new allocation amount
julia> using AllocationOpt
julia> using TheGraphData
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
])
julia> t = flextable([
Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"),
Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
])
julia> AllocationOpt.reallocate_action(Val(:rules), a, t, Dict())
graph indexer rules stop Qma
Check allocation status being closed before submitting: graph indexer rules set Qma decisionBasis always allocationAmount 1
1-element Vector{String}:
"[0mgraph indexer rules stop Qm" ⋯ 122 bytes ⋯ "asis always allocationAmount 1"
AllocationOpt.reportingtable
— Methodreportingtable(
s::FlexTable, xs::AbstractMatrix{Real}, ps::AbstractMatrix{Real}, i::Integer
)
Construct a table for the strategy mapping the ipfshash, allocation amount, and profit
julia> using AllocationOpt
julia> s = flextable([
Dict("stakedTokens" => "1", "signalledTokens" => "2", "ipfsHash" => "Qma"),
Dict("stakedTokens" => "2", "signalledTokens" => "1", "ipfsHash" => "Qmb"),
])
julia> xs = [[2.5 5.0]; [2.5 0.0]]
julia> ps = [[3.0 5.0]; [3.0 0.0]]
julia> i = 1
julia> AllocationOpt.reportingtable(s, xs, ps, i)
FlexTable with 3 columns and 2 rows:
ipfshash amount profit
┌─────────────────────────
1 │ Qma 2.5 3.0
2 │ Qmb 2.5 3.0
AllocationOpt.savenames
— Methodsavenames(p::AbstractString)
Return a generator of the generic names of the CSV files containing the data with the path specified by p
.
julia> using AllocationOpt
julia> path = "mypath"
julia> paths = AllocationOpt.savenames(path)
Base.Generator{NTuple{4, String}, AllocationOpt.var"#1#2"{String}}(AllocationOpt.var"#1#2"{String}("mypath"), ("indexer.csv", "allocation.csv", "subgraph.csv", "network.csv"))
AllocationOpt.signal
— Methodsignal(::Val{:network}, x)
The total signal in the network
```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "networkGRTIssuancePerBlock" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.signal(Val(:network), n) 2
AllocationOpt.signal
— Methodsignal(::Val{:subgraph}, x)
The tokens signalled on the subgraphs in table x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict("signalledTokens" => 10,),
Dict("signalledTokens" => 5,),
])
julia> AllocationOpt.signal(Val(:subgraph), x)
2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
10
5
AllocationOpt.sortprofits!
— Methodsortprofits!(NamedTuple{Tuple{Float64, Int64}})
Sort the nonzero best profits from highest to lowest
julia> using AllocationOpt
julia> popts = [
(; :profit => 5.0, :index => 2),
(; :profit => 6.0, :index => 1)
]
julia> popts = AllocationOpt.sortprofits!(popts)
2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:
(profit = 6.0, index = 1)
(profit = 5.0, index = 2)
AllocationOpt.squery
— Methodsquery(config::AbstractDict)
Return the components of a GraphQL query for subgraphs.
For use with the TheGraphData.jl package.
julia> using AllocationOpt
julia> config = Dict("syncing_networking" => ["mainnet"])
julia> value, args, fields = AllocationOpt.squery(config)
("subgraphDeployments", Dict{String, Union{Dict{String, String}, String}}(), ["ipfsHash", "signalledTokens", "stakedTokens"])
Extended Help
You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl
AllocationOpt.stake
— Methodstake(::Val{:allocation}, x)
Get the allocated tokens for each allocation in x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"allocatedTokens" => 1,
),
])
julia> AllocationOpt.stake(Val(:allocation), x)
1-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
1
AllocationOpt.stake
— Methodstake(::Val{:indexer}, x)
The tokens staked by the indexer in table x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict(
"stakedTokens" => 10,
),
])
julia> AllocationOpt.stake(Val(:indexer), x)
10
AllocationOpt.stake
— Methodstake(::Val{:subgraph}, x)
The tokens staked on the subgraphs in table x
.
julia> using AllocationOpt
julia> using TheGraphData
julia> x = flextable([
Dict("stakedTokens" => 10,),
Dict("stakedTokens" => 5,),
])
julia> AllocationOpt.stake(Val(:subgraph), x)
2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
10
5
AllocationOpt.strategydict
— Methodstrategydict(
p::NamedTuple,
xs::AbstractMatrix{Real},
nonzeros::AbstractVector{Integer},
fs::FlexTable,
profitmatrix::AbstractMatrix{Real}
)
For a profit, index pair p
, generate the nested dictionary representing the data to convert to a JSON string. xs
is the allocation strategy matrix, nonzeros
are the number of nonzeros in each allocation strategy, fs
is a table containing subgraph ipfshashes, and the profitmatrix
is a matrix containing profit for each allocation in xs
julia> using AllocationOpt
julia> using TheGraphData
julia> popts = [
(; :profit => 6.0, :index => 1),
(; :profit => 5.0, :index => 2)
]
julia> xs = [[2.5 5.0]; [2.5 0.0]]
julia> profits = [[3.0 5.0]; [3.0 0.0]]
julia> nonzeros = [2, 1]
julia> fs = flextable([
Dict("stakedTokens" => "1", "signalledTokens" => "0", "ipfsHash" => "Qma"),
Dict("stakedTokens" => "2", "signalledTokens" => "0", "ipfsHash" => "Qmb"),
])
julia> AllocationOpt.strategydict.(popts, Ref(xs), Ref(nonzeros), Ref(fs), Ref(profits))
2-element Vector{Dict{String, Any}}:
Dict("num_allocations" => 2, "profit" => 6.0, "allocations" => Dict{String, Any}[Dict("allocationAmount" => "2.5", "profit" => 3.0, "deploymentID" => "Qma"), Dict("allocationAmount" => "2.5", "profit" => 3.0, "deploymentID" => "Qmb")])
Dict("num_allocations" => 1, "profit" => 5.0, "allocations" => Dict{String, Any}[Dict("allocationAmount" => "5", "profit" => 5.0, "deploymentID" => "Qma")])
AllocationOpt.subtractindexer!
— Methodsubtractindexer!(a::FlexTable, s::FlexTable)
Subtract the indexer's allocated tokens from the total allocated tokens on each subgraph.
julia> using AllocationOpt
julia> using TheGraphData
julia> s = flextable([
Dict("ipfsHash" => "Qmb", "stakedTokens" => 20),
Dict("ipfsHash" => "Qma", "stakedTokens" => 10),
Dict("ipfsHash" => "Qmc", "stakedTokens" => 5),
])
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "allocatedTokens" => 5, "id" => "0xa"),
Dict("subgraphDeployment.ipfsHash" => "Qmb", "allocatedTokens" => 10, "id" => "0xb"),
])
julia> a, s = AllocationOpt.subtractindexer!(a, s)
(NamedTuple[(var"subgraphDeployment.ipfsHash" = "Qma", allocatedTokens = 5, id = "0xa"), (var"subgraphDeployment.ipfsHash" = "Qmb", allocatedTokens = 10, id = "0xb")], NamedTuple[(stakedTokens = 5.0, ipfsHash = "Qma"), (stakedTokens = 10, ipfsHash = "Qmb"), (stakedTokens = 5, ipfsHash = "Qmc")])
AllocationOpt.togrt
— Methodtogrt(x::AbstractString)
Convert x
to GRT.
This function is meant to be used with freshly queried data, so it operates on strings.
julia> using AllocationOpt
julia> AllocationOpt.togrt("1")
1.0e-18
AllocationOpt.unallocate_action
— Methodunallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)
Create and push the unallocate actions to the action queue.
```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> config = Dict( "frozenlist" => [], "indexerurl" => "http://localhost:18000" ) julia> TheGraphData.client!(config["indexerurl"]) julia> AllocationOpt.unallocate_action(Val(:actionqueue), a, t, config) 1-element Vector{Dict{String, Any}}: Dict("priority" => 0, "status" => AllocationOpt.queued, "allocationID" => "0xa", "source" => "AllocationOpt", "reason" => "AllocationOpt", "type" => AllocationOpt.unallocate, "deploymentID" => "Qma", "protocolNetwork" => "mainnet")
AllocationOpt.unallocate_action
— Methodunallocate_action(::Val{:none}, a, t, config)
Do nothing.
julia> using AllocationOpt
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
])
julia> t = flextable([
Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"),
Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
])
julia> AllocationOpt.unallocate_action(Val(:none), a, t, Dict())
AllocationOpt.unallocate_action
— Methodunallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)
Print a rule that stops old allocations that the optimiser has not chosen and that aren't frozen.
julia> using AllocationOpt
julia> a = flextable([
Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
])
julia> t = flextable([
Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
])
julia> AllocationOpt.unallocate_action(Val(:rules), a, t, Dict("frozenlist" => []))
graph indexer rules stop Qma
1-element Vector{String}:
"[0mgraph indexer rules stop Qma"
AllocationOpt.write
— Methodwrite(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable, config::AbstractDict)
Write the tables to the writedir
specified in the config
.
julia> using AllocationOpt
julia> using TheGraphData
julia> config = Dict("verbose" => true, "writedir" => "datadir")
julia> t = flextable([
Dict("ipfsHash" => "Qma", "signalledTokens" => "1"),
Dict("ipfsHash" => "Qmb", "signalledTokens" => "2"),
])
julia> i, a, s, n = repeat([t,], 4)
juila> AllocationOpt.write(i, a, s, n, config)
AllocationOpt.writejson
— Methodfunction writejson(results::AbstractString, config::AbstractDict)
Write the optimized results to the writedir
specified in the config
.
julia> Using AllocationOpt
julia> results = "{"strategies":[{"num_allocations":2,"profit":6.0,"allocations":[{"allocationAmount":2.5,"profit":3.0,"deploymentID":"Qma"},{"allocationAmount":2.5,"profit":3.0,"deploymentID":"Qmb"}]},{"num_allocations":1,"profit":5.0,"allocations":[{"allocationAmount":5.0,"profit":5.0,"deploymentID":"Qma"}]}]}"
julia> config = Dict{"writedir" => "."}
julia> AllocationOpt.writejson(results, config)
SemioticOpt.iteration
— Methoditeration(f::Function, a::AnalyticOpt)
Perform the analytic optimisation.
SemioticOpt.x!
— MethodSemioticOpt.x
— Methodx(a::AnalyticOpt)
Return the current best guess for the solution.