Dear all,
I need to generate two vectors (not the same length) whose sum is the same. I have the first one:
a = rand(1000:2000,5)
5-element Array{Int64,1}:
1404
1438
1529
1039
1071
Supose that I want a another vector b
with 10 entries whose sum is sum(a)
, how can I do this in a simple way?
Trivially:
other = zeros(Int, 10)
other[1] = sum(a)
4 Likes
It might be worth checking out the JuLie package, they have a partitions
function that can get you all the partitions of an integer (optionally of a specified length):
https://ulthiel.github.io/JuLie.jl/stable/combinatorics/#JuLie.partitions
not. I want b with nonzero entries…
You didn’t indicate additional constraints. Another option:
other = ones(Int, 10)
other[1] = sum(a)-(length(other)-1)
2 Likes
Combinatorics.jl also has a partitions
function. And the elements in the result are all positive i.e. no zero entries.
julia> partitions(10, 3) # you can iterate on this directly, and probably should
Combinatorics.FixedPartitions(10, 3)
julia> partitions(10, 3) |> collect
8-element Vector{Vector{Int64}}:
[8, 1, 1]
[7, 2, 1]
[6, 3, 1]
[5, 4, 1]
[6, 2, 2]
[5, 3, 2]
[4, 4, 2]
[4, 3, 3]
Edit : For your purpose, you’re probably better off with one of the other options.
2 Likes
just to give an idea of a possible strategy.
Obviously a lot depends on the real use you have to make of it.
Having not further specified the constraints to the problem, many others could be relevant solutions.
s=sum(rand(1:100,20))
ps=[]
while s > 1
p=rand(1:s)
s-=p
push!(ps,p)
end
edit another way is to generate a random array and add or subtract something to adjust the sum
How about this one?
julia> a = rand(1000:2000, 5);
julia> b = rand(1000:2000, 10);
julia> c = [b; sum(a) - sum(b)];
julia> sum(c) == sum(a)
true
The result there is length 11 (and can have a negative entry, and it’s not clear whether it’s assumed that the result should be all positive). Changing it a little bit:
julia> a = rand(1000:2000, 5);
julia> desiredlength = 10
10
julia> b = rand(1:sum(a)÷desiredlength, desiredlength - 1);
julia> c = [b; sum(a) - sum(b)]
10-element Vector{Int64}:
209
279
188
744
627
256
643
661
624
4081
julia> sum(c) == sum(a)
true
1 Like
@rocco_sprmnt21 's idea is also interesting, but requires a little tweaking for this specification.
julia> a = rand(1000:2000, 5);
julia> s = sum(a);
julia> b = similar(a, desiredlength);
julia> desiredlength = 10;
julia> for i in 1:desiredlength-1
b[i] = rand(1:s-desiredlength)
s -= b[i]
end
julia> b[desiredlength] = s
12
julia> sum(b) == sum(a)
true
julia> b
10-element Vector{Int64}:
3984
3021
511
730
154
102
56
6
80
12
DNF
August 22, 2022, 7:47pm
11
rocco_sprmnt21:
ps=[]
If you ever see a bare []
in your code, beware! This is terrible for performance. What you want here is Int[]
.
I assume you want another random vector, can you just re-scale it?
julia> a = rand(1000:2000,5)
5-element Vector{Int64}:
1484
1053
1135
1863
1823
julia> b = rand(1000:2000,10)
10-element Vector{Int64}:
1784
1708
1512
1169
1703
1394
1855
1520
1645
1652
julia> b = b * sum(a)/sum(b)
10-element Vector{Float64}:
823.4018316396939
788.3241751348639
697.8607452013549
539.5497428177142
786.0164345753356
643.3980679964873
856.1717475849956
701.5531300966002
759.2466440848074
762.477480868147
julia> sum(b) ≈ sum(a)
true
julia> sum(b) == sum(a) #I don't think this is always true
true
If you need Integer, I suppose you can just trunc and wiggle a single element value until the sum matches.
2 Likes
Wonderfull! the best solution!!! Thanks a lot.
na=10
nb=23
s=107
function part(s, n)
v=[rand(1:rand(1:100), n);s]
[diff(v);v[1]]
end
julia> sum(part(s, na))==s
true
julia> sum(part(s, nb))==s
true
to get array of positive numbers
function snpart(s, n)
a=[rand(1:rand(1:s-1), n);s]
sort!(a)
[diff(a);a[1]]
end
empet
August 23, 2022, 5:38pm
15
One more with geometrical arguments:
n=4
v = rand(n)
#x1+x2+x3+x4=s #all points (vectors )with sum s lie in this hyperplane
wn_1 = rand(n-1)
w= vcat(wn_1, [sum(v)-sum(wn_1)])
sum(v), sum(w)