Storing elements in a Vector using "for" loop in Julia
Asked Answered
S

4

7

I aim to divide elements of two different interval vectors, alpha, and gamma, and want to store the resultant intervals in a vector form. I am trying to run this code in Pluto-Julia but not getting the results:

using IntervalArithmetic, Plots, PlutoUI, Arblib, RecursiveArrayTools, StaticArrays

begin
    α = [(200..225); (225..250); (250..275); (275..300)]
    γ = [(2..2.25); (2.25..2.5); (2.5..2.75); (2.75..3)]
    local kk = 0
    for i in 1:4
        for j in 1:4
            ol = α[i]/γ[j]
            kk = kk + 1
        end
    end
    @show ol
end

I expect that the resultant interval vector should contain 16 elements (4*4). I think there is a syntax error. I would be great help for me if code is provided for generalized case, means i and j will not be just 4 and 4 but can be changed.

Somniferous answered 5/12, 2022 at 11:9 Comment(0)
S
3

I don't know why you are using a begin block, but if you intend to use a hard scope, the best choice is to wrap it in a function (Also, it's possible to use the let block, but I won't recommend it generally) and the bein blocks do not introduce a new scope.

  1. The first problem with your code is using the double dots, which isn't meaningful in Julia for separating elements.

α = [(200..225); (225..250); (250..275); (275..300)]

Instead, you can separate elements of a container via comma or semicolon. In your case, you can do it like this:

julia> α = [(200, 225); (225, 250); (250, 275); (275, 300)]
4-element Vector{Tuple{Int64, Int64}}:
 (200, 225)
 (225, 250)
 (250, 275)
 (275, 300)
  1. Since the begin blocks do not introduce a new scope (read here about scopes in Julia), then you don't need to declare the local variable (unless there is further code that you didn't provide in the question).
  2. If you are intended to store the result of an arithmetic operation using the for loop in a container:
    One way is first to define initialized containers and then update their values (as it seems you intended such an approach. Although the structure can be improved much more, I won't change the overall code structure of OP, but the content in the following code block):
julia> begin
           α = [(1, 5); (5, 10); (10, 15); (15, 20)]
           β = [(3, 6); (6, 9); (9, 12); (12, 15)]
           kk = 0

           ol = Matrix{NTuple{2, Float64}}(undef, 4, 4)
           for i in 1:4
               for j in 1:4
                   ol[i, j] = (α[i][1]/β[j][1], α[i][2]/β[j][2])
                   kk += 1
               end
           end
       end

julia> ol
4×4 Matrix{Tuple{Float64, Float64}}:
 (0.333333, 0.833333)  (0.166667, 0.555556)  (0.111111, 0.416667)  (0.0833333, 0.333333)
 (1.66667, 1.66667)    (0.833333, 1.11111)   (0.555556, 0.833333)  (0.416667, 0.666667)
 (3.33333, 2.5)        (1.66667, 1.66667)    (1.11111, 1.25)       (0.833333, 1.0)
 (5.0, 3.33333)        (2.5, 2.22222)        (1.66667, 1.66667)    (1.25, 1.33333)

julia> kk
16

Note that the result is a 4*4 Matrix (as you expected) with 16 elements.

  • Q1: What is the meaning of ol = Matrix{NTuple{2, Float64}}(undef, 4, 4)?
    Here, I defined an Initialized Matrix with a size of 4*4 in which elements are Tuples with a length of 2 and the Float64 element type.
  • Q2: What is happening in the ol[i, j] = (α[i][1]/β[j][1], α[i][2]/β[j][2])?
    Here, I'm trying to divide the first member of the i'th element of the α by the first member of the j'th element of the β (in the α[i][1]/β[j][1]), and the second member of the i'th element of the α by the second member of the j'th element of the β (in the α[i][2]/β[j][2]) and replace the result with the [i, j] element of the ol.

Update

Here is a similar structure using the IntervalArithmetic.jl package:

using IntervalArithmetic

begin
    α = [(1..5); (5..10); (10..15); (15..20)]
    β = [(3..6); (6..9); (9..12); (12..15)]
    kk = 0

    ol = Matrix{Interval{Float64}}(undef, 4, 4)
    for i in 1:4
        for j in 1:4
            ol[i, j] = α[i]/β[j]
            kk += 1
        end
    end
end

Then if I check for the ol and the kk:

julia> ol
4×4 Matrix{Interval{Float64}}:
 [0.166666, 1.66667]  [0.111111, 0.833334]  [0.0833333, 0.555556]     [0.0666666, 0.416667]
 [0.833333, 3.33334]  [0.555555, 1.66667]   [0.416666, 1.11112]       [0.333333, 0.833334]
 [1.66666, 5]         [1.11111, 2.5]        [0.833333, 1.66667]       [0.666666, 1.25]
 [2.5, 6.66667]       [1.66666, 3.33334]    [1.25, 2.22223]        [1, 1.66667]

julia> typeof(ol[1, 1])
Interval{Float64}

julia> kk
16

Since this approach is what you desire, we can write it least a little bit better. First, I begin by defining a function. Second, we can use Iterators.product to avoid nested for loop:

function div_intervals(first_itv::T, second_itv::T) where T<:Vector{Interval{Float64}}
    m, n = length(first_itv), length(second_itv)
    ol = Matrix{Interval{Float64}}(undef, m, n)

    for (i_idx, j_idx) in Iterators.product(1:m, 1:n)
        ol[i_idx, j_idx] = first_itv[i_idx]/second_itv[j_idx]
    end

    return ol
end

This function is written dynamic and can be applied on the α and β with the type of Vector{Interval{Float64}} in any length. Also, we can make it even better by using broadcasting in a for loop:

function div_intervals2(first_itv::T, second_itv::T) where T<:Vector{Interval{Float64}}
    m, n = length(first_itv), length(second_itv)
    ol = Matrix{Interval{Float64}}(undef, m, n)

    for j_idx in eachindex(second_itv)
        ol[:, j_idx] .= first_itv./second_itv[j_idx]
    end

    return ol
end

julia> div_intervals2(α, β)
4×4 Matrix{Interval{Float64}}:
 [0.166666, 1.66667]  [0.111111, 0.833334]  [0.0833333, 0.555556]     [0.0666666, 0.416667]
 [0.833333, 3.33334]  [0.555555, 1.66667]   [0.416666, 1.11112]       [0.333333, 0.833334]
 [1.66666, 5]         [1.11111, 2.5]        [0.833333, 1.66667]       [0.666666, 1.25]
 [2.5, 6.66667]       [1.66666, 3.33334]    [1.25, 2.22223]        [1, 1.66667]

julia> div_intervals2(α, β) == div_intervals(α, β)
true
Strake answered 5/12, 2022 at 12:28 Comment(11)
Double dot is perfectly correct when you are using IntervalArithmetic package. RUTRA just did not give the package name.Trixy
@PrzemyslawSzufel, Yes, he didn't mention that. That's a specific case. I thought OP intended to separate elements by ...Strake
The block is most likely there because they use Pluto.jl and want to put the code into a single cell (I have removed the Pluto tag, as it is not relevant to the question).Jenniejennifer
Thank you so much @Shayan. Your solution could solve my problem but in my case vectors contain interval elements, not fixed point numbers. An interval contains all the values from the lower limit to the upper limit. Please provide the modified solution. Please let me know if any information is required.Somniferous
@RUDRAPRAKASH specifically mention the package you've used for creating intervals.Strake
@Strake I have these packages: IntervalArithmetic, Plots, PlutoUI, Arblib, RecursiveArrayTools, StaticArrays.Somniferous
@RUDRAPRAKASH, Check the update section in my answer.Strake
@Strake It is working. Thank you so much for your kind help. Could you please let me know how it would be plotted using plot(IntervalBox) (I want to plot, ol vs alpha or gamma)? Dimensions of ol and alpha are different so an error is coming.Somniferous
@RUDRAPRAKASH, You're welcome. Since this is what you want, I'll provide extra notes for writing it efficiently since you insist on using for loops.Strake
@Strake Could you please let me know where I can find those extra notes?Somniferous
Let us continue this discussion in chat.Somniferous
J
6

There is no syntax error, but you never assign to an array. You only overwrite the local scalar ol in every iteration.

To get your desired result, you need to construct an actual matrix. Probably a matrix comprehension is the most readable short version (using plain floats, as I don't have your interval package loaded):

julia> α = [200, 225, 250, 275]; γ = [2, 2.25, 2.5, 2.75];

julia> [a / g for a in α, g in γ]
4×4 Matrix{Float64}:
 100.0   88.8889   80.0   72.7273
 112.5  100.0      90.0   81.8182
 125.0  111.111   100.0   90.9091
 137.5  122.222   110.0  100.0

You can also use broadcasting, but then you have to change the orientation of one of the vectors:

julia> α ./ permutedims(γ)
4×4 Matrix{Float64}:
 100.0   88.8889   80.0   72.7273
 112.5  100.0      90.0   81.8182
 125.0  111.111   100.0   90.9091
 137.5  122.222   110.0  100.0
Jenniejennifer answered 5/12, 2022 at 11:23 Comment(0)
S
3

I don't know why you are using a begin block, but if you intend to use a hard scope, the best choice is to wrap it in a function (Also, it's possible to use the let block, but I won't recommend it generally) and the bein blocks do not introduce a new scope.

  1. The first problem with your code is using the double dots, which isn't meaningful in Julia for separating elements.

α = [(200..225); (225..250); (250..275); (275..300)]

Instead, you can separate elements of a container via comma or semicolon. In your case, you can do it like this:

julia> α = [(200, 225); (225, 250); (250, 275); (275, 300)]
4-element Vector{Tuple{Int64, Int64}}:
 (200, 225)
 (225, 250)
 (250, 275)
 (275, 300)
  1. Since the begin blocks do not introduce a new scope (read here about scopes in Julia), then you don't need to declare the local variable (unless there is further code that you didn't provide in the question).
  2. If you are intended to store the result of an arithmetic operation using the for loop in a container:
    One way is first to define initialized containers and then update their values (as it seems you intended such an approach. Although the structure can be improved much more, I won't change the overall code structure of OP, but the content in the following code block):
julia> begin
           α = [(1, 5); (5, 10); (10, 15); (15, 20)]
           β = [(3, 6); (6, 9); (9, 12); (12, 15)]
           kk = 0

           ol = Matrix{NTuple{2, Float64}}(undef, 4, 4)
           for i in 1:4
               for j in 1:4
                   ol[i, j] = (α[i][1]/β[j][1], α[i][2]/β[j][2])
                   kk += 1
               end
           end
       end

julia> ol
4×4 Matrix{Tuple{Float64, Float64}}:
 (0.333333, 0.833333)  (0.166667, 0.555556)  (0.111111, 0.416667)  (0.0833333, 0.333333)
 (1.66667, 1.66667)    (0.833333, 1.11111)   (0.555556, 0.833333)  (0.416667, 0.666667)
 (3.33333, 2.5)        (1.66667, 1.66667)    (1.11111, 1.25)       (0.833333, 1.0)
 (5.0, 3.33333)        (2.5, 2.22222)        (1.66667, 1.66667)    (1.25, 1.33333)

julia> kk
16

Note that the result is a 4*4 Matrix (as you expected) with 16 elements.

  • Q1: What is the meaning of ol = Matrix{NTuple{2, Float64}}(undef, 4, 4)?
    Here, I defined an Initialized Matrix with a size of 4*4 in which elements are Tuples with a length of 2 and the Float64 element type.
  • Q2: What is happening in the ol[i, j] = (α[i][1]/β[j][1], α[i][2]/β[j][2])?
    Here, I'm trying to divide the first member of the i'th element of the α by the first member of the j'th element of the β (in the α[i][1]/β[j][1]), and the second member of the i'th element of the α by the second member of the j'th element of the β (in the α[i][2]/β[j][2]) and replace the result with the [i, j] element of the ol.

Update

Here is a similar structure using the IntervalArithmetic.jl package:

using IntervalArithmetic

begin
    α = [(1..5); (5..10); (10..15); (15..20)]
    β = [(3..6); (6..9); (9..12); (12..15)]
    kk = 0

    ol = Matrix{Interval{Float64}}(undef, 4, 4)
    for i in 1:4
        for j in 1:4
            ol[i, j] = α[i]/β[j]
            kk += 1
        end
    end
end

Then if I check for the ol and the kk:

julia> ol
4×4 Matrix{Interval{Float64}}:
 [0.166666, 1.66667]  [0.111111, 0.833334]  [0.0833333, 0.555556]     [0.0666666, 0.416667]
 [0.833333, 3.33334]  [0.555555, 1.66667]   [0.416666, 1.11112]       [0.333333, 0.833334]
 [1.66666, 5]         [1.11111, 2.5]        [0.833333, 1.66667]       [0.666666, 1.25]
 [2.5, 6.66667]       [1.66666, 3.33334]    [1.25, 2.22223]        [1, 1.66667]

julia> typeof(ol[1, 1])
Interval{Float64}

julia> kk
16

Since this approach is what you desire, we can write it least a little bit better. First, I begin by defining a function. Second, we can use Iterators.product to avoid nested for loop:

function div_intervals(first_itv::T, second_itv::T) where T<:Vector{Interval{Float64}}
    m, n = length(first_itv), length(second_itv)
    ol = Matrix{Interval{Float64}}(undef, m, n)

    for (i_idx, j_idx) in Iterators.product(1:m, 1:n)
        ol[i_idx, j_idx] = first_itv[i_idx]/second_itv[j_idx]
    end

    return ol
end

This function is written dynamic and can be applied on the α and β with the type of Vector{Interval{Float64}} in any length. Also, we can make it even better by using broadcasting in a for loop:

function div_intervals2(first_itv::T, second_itv::T) where T<:Vector{Interval{Float64}}
    m, n = length(first_itv), length(second_itv)
    ol = Matrix{Interval{Float64}}(undef, m, n)

    for j_idx in eachindex(second_itv)
        ol[:, j_idx] .= first_itv./second_itv[j_idx]
    end

    return ol
end

julia> div_intervals2(α, β)
4×4 Matrix{Interval{Float64}}:
 [0.166666, 1.66667]  [0.111111, 0.833334]  [0.0833333, 0.555556]     [0.0666666, 0.416667]
 [0.833333, 3.33334]  [0.555555, 1.66667]   [0.416666, 1.11112]       [0.333333, 0.833334]
 [1.66666, 5]         [1.11111, 2.5]        [0.833333, 1.66667]       [0.666666, 1.25]
 [2.5, 6.66667]       [1.66666, 3.33334]    [1.25, 2.22223]        [1, 1.66667]

julia> div_intervals2(α, β) == div_intervals(α, β)
true
Strake answered 5/12, 2022 at 12:28 Comment(11)
Double dot is perfectly correct when you are using IntervalArithmetic package. RUTRA just did not give the package name.Trixy
@PrzemyslawSzufel, Yes, he didn't mention that. That's a specific case. I thought OP intended to separate elements by ...Strake
The block is most likely there because they use Pluto.jl and want to put the code into a single cell (I have removed the Pluto tag, as it is not relevant to the question).Jenniejennifer
Thank you so much @Shayan. Your solution could solve my problem but in my case vectors contain interval elements, not fixed point numbers. An interval contains all the values from the lower limit to the upper limit. Please provide the modified solution. Please let me know if any information is required.Somniferous
@RUDRAPRAKASH specifically mention the package you've used for creating intervals.Strake
@Strake I have these packages: IntervalArithmetic, Plots, PlutoUI, Arblib, RecursiveArrayTools, StaticArrays.Somniferous
@RUDRAPRAKASH, Check the update section in my answer.Strake
@Strake It is working. Thank you so much for your kind help. Could you please let me know how it would be plotted using plot(IntervalBox) (I want to plot, ol vs alpha or gamma)? Dimensions of ol and alpha are different so an error is coming.Somniferous
@RUDRAPRAKASH, You're welcome. Since this is what you want, I'll provide extra notes for writing it efficiently since you insist on using for loops.Strake
@Strake Could you please let me know where I can find those extra notes?Somniferous
Let us continue this discussion in chat.Somniferous
N
3

There are two Interval arithmetic packages in Julia eco-system: Intervals.jl and IntervalArithmetic.jl. The latter provides a pre-defined / operator (which satisfies interval guarantees). So let's assume the latter is used.

Additionally, the vectors specified are Float64 but from the actual values, the numbers 'want' to be Rational. Making the numbers Rational turns out to step on some missing convert methods in IntervalArithmetic, but this is easily fixed. So:

using IntervalArithmetic                                                                                          
                                                                                                                         
α = [(200..225); (225..250); (250..275); (275..300)]                                                              
γ = [(2..2.25); (2.25..2.5); (2.5..2.75); 

alpha = Interval.(zip((rationalize.(getproperty.(α,k)) for k in [:lo, :hi])...))
gamma = Interval.(zip((rationalize.(getproperty.(γ,k)) for k in [:lo, :hi])...))

permutedims(alpha) ./ gamma  # like other answers suggested

This returns:

4×4 Matrix{Interval{Rational{Int64}}}:
  [800//9, 225//2]   [100//1, 125//1]   [1000//9, 275//2]   [1100//9, 150//1]
   [80//1, 100//1]   [90//1, 1000//9]   [100//1, 1100//9]    [110//1, 400//3]
  [800//11, 90//1]  [900//11, 100//1]  [1000//11, 110//1]    [100//1, 120//1]
 [200//3, 900//11]  [75//1, 1000//11]    [250//3, 100//1]  [275//3, 1200//11]
Nonbeliever answered 5/12, 2022 at 14:39 Comment(1)
Thank you Mr. @Dan. I have much more elements in the vector and also need a solution using "for" loop because I will use this concept in much more complex calculations. Please provide the solution using for loop, if possible.Somniferous
M
2

Julia's broadcasting machinery is so powerful, use the dot notation with transpose to divide the vectors the way you want. This gives you a matrix, convert to a vector if you wish using vec.

α = [200, 225, 250, 275]; γ = [2, 2.25, 2.5, 2.75];
vec(α' ./ γ)

The same code works with IntervalArithmetic.jl:

using IntervalArithmetic

α = [200..225, 225..250, 250..275, 275..300]
γ = [2..2.25, 2.25..2.5, 2.5..2.75, 2.75..3]

vec(α' ./ γ)
16-element Vector{Interval{Float64}}:
        [88.8888, 112.5]
  [80, 100]
        [72.7272, 90]
        [66.6666, 81.8182]
 [100, 125]
   [90, 111.112]
        [81.8181, 100]
    [75, 90.9091]
       [111.111, 137.5]
  [100, 122.223]
        [90.909, 110]
        [83.3333, 100]
       [122.222, 150]
  [110, 133.334]
 [100, 120]
        [91.6666, 109.091]
Marelya answered 5/12, 2022 at 13:15 Comment(1)
Thank you Mr. @AboAmmar. I need a solution using the "for" loop because I will use that concept when I will be having multiple for loops in more complex analyses. Please provide the solution.Somniferous

© 2022 - 2024 — McMap. All rights reserved.