Related
I want to code this constraint.
d and a in the below code are the subsets of set S with the size of N. For example: (N=5, T=3, S=6), d=[1,2,2,3,1] (the elements of d are the first three digits of S and the size of d is N) and a=[6,4,5,6,4] (the elements of a are the three last digits of set S and the size of a is N).
In the constraint, s should start with d and end with a.
It should be like s[j=1]=1:6, s[j=2]=2:4, s[j=3]=2:5, s[j=4]=3:6, s[j=5]1:4.
I do not know how to deal with this set that depends on the other sets. Can you please help me to code my constraint correctly? The below code is not working correctly.
N = 5
T=3
S=6
Cap=15
Q=rand(1:5,N)
d=[1,2,2,3,1]
a=[6,4,5,6,4]
#variable(model, x[j=1:N,t=1:T,s=1:S], Bin)
#constraint(model, [j= 1:N,t = 1:T, s = d[j]:a[j]], sum(x[j,t,s] * Q[j] for j=1:N) <= Cap)
N, T, S = 5, 3, 6
Q = rand(1:5,N)
d = [1, 2, 2, 3, 1]
a = [6, 4, 5, 6, 4]
using JuMP
model = Model()
#variable(model, x[1:N, 1:T, 1:S], Bin)
#constraint(
model,
[t = 1:T, s = 1:S],
sum(x[j, t, s] * Q[j] for j in 1:N if d[j] <= s < a[j]) <= 15,
)
p.s. There's no need to post multiple comments and questions:
Coding arrays in constraint JuMP
You should also consider posting on the Julia discourse instead: https://discourse.julialang.org/c/domain/opt/13. It's easier to have a conversation there.
Let's say I have a vector a = [1, 0, 1, 2, 3, 4, 5, 0, 5, 6, 7, 8, 0, 9, 0] and I want to split it to smaller vectors based on a condition depending on value in that array. E.g. value being zero.
Thus I want to obtain vector of following vectors
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
So far this was working for me as a naive solution, but it loses the type.
function split_by_λ(a::Vector, λ)
b = []
temp = []
for i in a
push!(temp, i)
if λ(i)
push!(b, temp)
temp = []
end
end
b
end
split_by_λ(a, isequal(0))
Then I tried to play with ranges, which feels a bit more idiomatic, and does not lose the type.
function split_by_λ(a::Vector, λ)
idx = findall(λ, a)
ranges = [(:)(i==1 ? 1 : idx[i-1]+1, idx[i]) for i in eachindex(idx)]
map(x->a[x], ranges)
end
split_by_λ(a, isequal(0))
but it still feels very cumbersome regarding it's a rather simple task.
Is there something I'm missing, some easier way?
Maybe someone has a shorter idea but here is mine:
julia> inds = vcat(0,findall(==(0),a),length(a))
julia> getindex.(Ref(a), (:).(inds[1:end-1].+1,inds[2:end]))
5-element Array{Array{Int64,1},1}:
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
[]
Or if you want to avoid copying a
julia> view.(Ref(a), (:).(inds[1:end-1].+1,inds[2:end]))
5-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
0-element view(::Array{Int64,1}, 16:15) with eltype Int64
Pretty much the same as Przemyslaw's answer, but maybe less cryptic dense:
function split_by(λ, a::Vector)
first, last = firstindex(a), lastindex(a)
splits = [first-1; findall(λ, a); last]
s1, s2 = #view(splits[1:end-1]), #view(splits[2:end])
return [view(a, i1+1:i2) for (i1, i2) in zip(s1, s2)]
end
Also, I changed the signature to the conventional one of "functions first", which allows you to use do-blocks. Additionally, this should work with offset indexing.
One could surely get rid of the intermediate allocations, but I think that gets ugly without yield:
function split_by(λ, a::Vector)
result = Vector{typeof(view(a, 1:0))}()
l = firstindex(a)
r = firstindex(a)
while r <= lastindex(a)
if λ(a[r])
push!(result, #view(a[l:r]))
l = r + 1
end
r += 1
end
push!(result, #view(a[l:end]))
return result
end
Using Prolog:
Write a predicate dispnth to display the nth element of a list. You may assume that the input list always has n or more elements.
For Example:
?- dispnth([1, [2, 3], 4, 5], 2, X). should return X = [2, 3]
I have this so far:
dispnth([X|_], 0, X).
dispnth([_|Xs], N, X) :-
dispnth(N1, X, Xs),
N is N1 + 1.
First let's give the predicate a more descriptive name, say list_nth_element/3. Next you might like to consider an auxiliary predicate list_nth_element_/4 with an additional argument, that holds the current position. From your given example I assume that you start counting at 1, so that's going to be the start value for the fourth argument. Then the predicates might look something like this:
list_nth_element(L,N,E) :-
list_nth_element_(L,N,E,1).
list_nth_element_([X|Xs],N,X,N). % if the 2nd and 4th elements are equal X is the nth element
list_nth_element_([_X|Xs],N,E,P0) :- % if the 2nd and 4th arguments
dif(P0,N), % differ
P1 is P0+1, % increment current position
list_nth_element_(Xs,N,E,P1). % and recurse
So essentially the fourth argument is used as a position indicator that is being incremented until you reached the desired position. However, there is no need to have this additional argument in the actual predicates interface, so it is "hidden" in the auxiliary predicate's interface.
Querying this predicate yields your desired result:
?- list_nth_element([1, [2, 3], 4, 5], 2, X).
X = [2,3] ? ;
no
You can also ask things like Which element is at what position?
?- list_nth_element([1, [2, 3], 4, 5], N, X).
N = X = 1 ? ;
N = 2,
X = [2,3] ? ;
N = 3,
X = 4 ? ;
N = 4,
X = 5 ? ;
no
Let's say I have a vector of unique integers, for example [1, 2, 6, 4] (sorting doesn't really matter).
Given some n, I want to get all possible values of summing n elements of the set, including summing an element with itself. It is important that the list I get is exhaustive.
For example, for n = 1 I get the original set.
For n = 2 I should get all values of summing 1 with all other elements, 2 with all others etc. Some kind of memory is also required, in the sense that I have to know from which entries of the original set did the sum I am facing come from.
For a given, specific n, I know how to solve the problem. I want a concise way of being able to solve it for any n.
EDIT: This question is for Julia 0.7 and above...
This is a typical task where you can use a dictionary in a recursive function (I am annotating types for clarity):
function nsum!(x::Vector{Int}, n::Int, d=Dict{Int,Set{Vector{Int}}},
prefix::Vector{Int}=Int[])
if n == 1
for v in x
seq = [prefix; v]
s = sum(seq)
if haskey(d, s)
push!(d[s], sort!(seq))
else
d[s] = Set([sort!(seq)])
end
end
else
for v in x
nsum!(x, n-1, d, [prefix; v])
end
end
end
function genres(x::Vector{Int}, n::Int)
n < 1 && error("n must be positive")
d = Dict{Int, Set{Vector{Int}}}()
nsum!(x, n, d)
d
end
Now you can use it e.g.
julia> genres([1, 2, 4, 6], 3)
Dict{Int64,Set{Array{Int64,1}}} with 14 entries:
16 => Set(Array{Int64,1}[[4, 6, 6]])
11 => Set(Array{Int64,1}[[1, 4, 6]])
7 => Set(Array{Int64,1}[[1, 2, 4]])
9 => Set(Array{Int64,1}[[1, 4, 4], [1, 2, 6]])
10 => Set(Array{Int64,1}[[2, 4, 4], [2, 2, 6]])
8 => Set(Array{Int64,1}[[2, 2, 4], [1, 1, 6]])
6 => Set(Array{Int64,1}[[2, 2, 2], [1, 1, 4]])
4 => Set(Array{Int64,1}[[1, 1, 2]])
3 => Set(Array{Int64,1}[[1, 1, 1]])
5 => Set(Array{Int64,1}[[1, 2, 2]])
13 => Set(Array{Int64,1}[[1, 6, 6]])
14 => Set(Array{Int64,1}[[4, 4, 6], [2, 6, 6]])
12 => Set(Array{Int64,1}[[4, 4, 4], [2, 4, 6]])
18 => Set(Array{Int64,1}[[6, 6, 6]])
EDIT: In the code I use sort! and Set to avoid duplicate entries (remove them if you want duplicates). Also you could keep track how far in the index on vector x in the loop you reached in outer recursive calls to avoid generating duplicates at all, which would speed up the procedure.
I want a concise way of being able to solve it for any n.
Here is a concise solution using IterTools.jl:
Julia 0.6
using IterTools
n = 3
summands = [1, 2, 6, 4]
myresult = map(x -> (sum(x), x), reduce((x1, x2) -> vcat(x1, collect(product(fill(summands, x2)...))), [], 1:n))
(IterTools.jl is required for product())
Julia 0.7
using Iterators
n = 3
summands = [1, 2, 6, 4]
map(x -> (sum(x), x), reduce((x1, x2) -> vcat(x1, vec(collect(product(fill(summands, x2)...)))), 1:n; init = Vector{Tuple{Int, NTuple{n, Int}}}[]))
(In Julia 0.7, the parameter position of the neutral element changed from 2nd to 3rd argument.)
How does this work?
Let's indent the one-liner (using the Julia 0.6 version, the idea is the same for the Julia 0.7 version):
map(
# Map the possible combinations of `1:n` entries of `summands` to a tuple containing their sum and the summands used.
x -> (sum(x), x),
# Generate all possible combinations of `1:n`summands of `summands`.
reduce(
# Concatenate previously generated combinations with the new ones
(x1, x2) -> vcat(
x1,
vec(
collect(
# Cartesian product of all arguments.
product(
# Use `summands` for `x2` arguments.
fill(
summands,
x2)...)))),
# Specify for what lengths we want to generate combinations.
1:n;
# Neutral element (empty array).
init = Vector{Tuple{Int, NTuple{n, Int}}}[]))
Julia 0.6
This is really just to get a free critique from the experts as to why my method is inferior to theirs!
using Combinatorics, BenchmarkTools
function nsum(a::Vector{Int}, n::Int)::Vector{Tuple{Int, Vector{Int}}}
r = Vector{Tuple{Int, Vector{Int}}}()
s = with_replacement_combinations(a, n)
for i in s
push!(r, (sum(i), i))
end
return sort!(r, by = x -> x[1])
end
#btime nsum([1, 2, 6, 4], 3)
It runs in circa 4.154 μs on my 1.8 GHz processor for n = 3. It produces a sorted array showing the sum (which may appear more than once) and how it is made up (which is unique to each instance of the sum).
I'm trying to match all the paths (up to a certain length) among a group of nodes. I can successfully do so by issuing the following query:
MATCH (n) WHERE ID(n) IN [1, 2, 3, 4, 5]
MATCH (m) WHERE ID(m) IN [1, 2, 3, 4, 5]
MATCH paths = allShortestPaths((n)-[*..3]-(m))
RETURN paths
I'm satisfied with both the result itself and its speed. What I don't understand is whether there is a way of defining a variable to define the collection [1, 2, 3, 4, 5] just once. Sort of:
x = [1, 2, 3, 4, 5]
MATCH (n) WHERE ID(n) IN x
MATCH (m) WHERE ID(m) IN x
MATCH paths = allShortestPaths((n)-[*..3]-(m))
RETURN paths
Is this possible? I've tried several alternatives (using WITH and AS) but with no luck.
Thanks
Use:
WITH [1, 2, 3, 4, 5] AS x
As in:
WITH [1, 2, 3, 4, 5] AS x
MATCH (n) WHERE ID(n) IN x
MATCH (m) WHERE ID(m) IN x
MATCH paths = allShortestPaths((n)-[*..3]-(m))
RETURN paths
By the way, there seems to be a regression in neo4j-community-2.2.0-M03, which causes an error with the above query. M02 seems to have no problems.