Generating two vector of same sum

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

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

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)