I am new in Julia, so don't judge me please (ha ha)
This is my situation: I needed to save several 2x2x2 matrices whose elements were vectors of 4 elements, but now when I try to retrieve them from a file, I can't !!!
This is what I did:
To create these matrices I made this function
function InitialConf(L_=2,S_=2,T_=2,Dim_=4)
Conf_=Array{Array{Float64,1}}(L_,S_,T_)
for i_ = 1:L_, j_=1:S_,k_=1:T_
Conf_[i_,j_,k_]=RanUniVec(Dim_)
end
return Conf_
end
Where RanUniVec(Dim_) is the function that creates these vectors of 4 dimentions with special characteristics that are not important for this discussion:
function RanUniVec(Dim_)
vector_=Array{Float64}(Dim_)
while true
for i_ in 1:Dim_
vector_[i_]=UniformRand(-1,1)
end
if norm(vector_)<1 && norm(vector_)>0.5
break
end
end
vector_=normalize(vector_) # 2-norm
return vector_
end
function UniformRand(a_,b_)
rand_=(b_-a_)*rand()+a_
return rand_
end
I needed two of these matrices (for example) so I did the next:
States=[]
Conf1=InitialConf()
Conf2=InitialConf()
push!(States,Conf1)
push!(States,Conf2)
f=open("Info.txt","w") do f
write(f,"$States")
end
This made the Info.txt file where is my information, but when I try to get the States array again from this file, Julia tells me that it can't
f=readlines("Info.txt")
States=parse(f)
ERROR: MethodError: no method matching parse(::Array{String,1})
Closest candidates are:
parse(::Type{IPv4}, ::AbstractString) at socket.jl:167
parse(::Type{IPv6}, ::AbstractString) at socket.jl:218
parse(::Type{DateTime}, ::AbstractString, ::DateFormat{Symbol("yyyy-mm-dd\\THH:MM:SS.s"),Tuple{Base.Dates.DatePart{'y'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'m'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'d'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'H'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'M'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'S'},Base.Dates.Delim{Char,1},Base.Dates.DatePart{'s'}}}) at dates/parse.jl:202
...
Do you know how I can get again my State array?
In general you should use Colin's recommendation from the comment in the long run. Here is what you can do if you actually have those text files already generated. I will use a smaller example.
Assume your original array is consisting of two 2x2x2 arrays. Here is an example I will use:
julia> z
2-element Array{Array{Int64,3},1}:
[1 2; 3 4]
[10 20; 30 40]
[1 2; 3 4]
[10 20; 30 40]
julia> z[1]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
10 20
30 40
julia> z[2]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
10 20
30 40
Now it will get saved to a file as the following string:
julia> repr(z)
"Array{Int64,3}[[1 2; 3 4]\n\n[10 20; 30 40], [1 2; 3 4]\n\n[10 20; 30 40]]"
And parsing this string will clearly fail. What you have to do is to edit your files to add cat method invocation on each entry of a big array and pass dimension 3 as the one on which you want to cat them.
This means that from the original contents of the save file:
Array{Int64,3}[[1 2; 3 4]
[10 20; 30 40], [1 2; 3 4]
[10 20; 30 40]]
You have to make this file contain:
Array{Int64,3}[cat(3, [1 2; 3 4], [10 20; 30 40]),
cat(3, [1 2; 3 4], [10 20; 30 40])]
Those changes can be done either by hand or you could write a program to perform the transformation (you have to replace , by ), cat(3,; \n\n by ,; make sure that first cat and last ) are added as they will not be caught by the first two rules).
Now if you read it in it as a string you can evaluate result of parsing it:
julia> s = """Array{Int64,3}[cat(3, [1 2; 3 4], [10 20; 30 40]),
cat(3, [1 2; 3 4], [10 20; 30 40])]"""
"Array{Int64,3}[cat(3, [1 2; 3 4], [10 20; 30 40]),\ncat(3, [1 2; 3 4], [10 20; 30 40])]"
julia> eval(parse(s))[2]
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
10 20
30 40
Note, however, that all this is not recommended - it is better to use the packages that Colin recommended to do this.
Not directly an answer to your specific question, but a general recommendation for future development. To save data to disk, and reload later, give preference to formats such as JLD2.jl.
You save with
#save "filename.jld2" ARRAY
and load with
#load "filename.jld2" ARRAY
without having to figure out what was the format you chose in the past. Saves a lot of headache with complex data structures.
Related
I have two vectors, and I'm trying to find ALL coincidences of one on the other within a certain tolerance without using a for loop.
By tolerance I mean for example if I have the number 3, with tolerance 2, I will want to keep values within 3±2, so (1,2,3,4,5).
A = [5 3 4 2]; B = [2 4 4 4 6 8];
I want to obtain a cell array containing on each cell the numbers of all the coincidences with a tolerance of 1 (or more) units. (A = B +- 1)
I have a solution with zero units (A = B), which would look something like this:
tol = 0;
[tf, ia] = ismembertol(B,A,tol,'DataScale',1); % For tol = 0, this is equivalent to using ismember
idx = 1:numel(B);
ib = accumarray(nonzeros(ia), idx(tf), [], #(x){x}) % This gives the cell array
The output is:
ib =
[]
[]
[2 3 4]
[1]
Which is as desired.
If I change the tolerance to 1, the code doesn't work as intended. It outputs instead:
tol = 1
[tf, ia] = ismembertol(B,A,tol,'DataScale',1); % For tolerance = 1, this is equivalent to using ismember
idx = 1:numel(B);
ib = accumarray(nonzeros(ia), idx(tf), [], #(x){x}) % This gives the cell array
ib =
[5]
[2 3 4]
[]
[1]
When I would expect to obtain:
ib =
[2 3 4 5]
[1 2 3 4]
[2 3 4]
[1]
What am I doing wrong? Is there an alternative solution?
Your problem is that, in the current state of your code, ismembertol only outputs 1 index per element of B found in A, so you lose information in the cases where an element can be found several times within tolerance.
As per the documentation You can use the 'OutputAllIndices',true value pair argument syntax, to output what you want in ia with just a call to ismembertol:
A = [5 3 4 2]; B = [2 4 4 4 6 8];
tol = 0;
[tf, ia] = ismembertol(A,B,tol,'DataScale',1,'OutputAllIndices',true);
celldisp(ia) % tol = 0
ia{1} =
0
ia{2} =
0
ia{3} =
2
3
4
ia{4} =
1
celldisp(ia) % tol = 1
ia{1} =
2
3
4
5
ia{2} =
1
2
3
4
ia{3} =
2
3
4
ia{4} =
1
Here is a manual approach, just to provide another method. It computes an intermediate matrix of all absolute differences (using implicit expansion), and from the row and column indices of the entries that are less than the tolerance it builds the result:
A = [5 3 4 2];
B = [2 4 4 4 6 8];
tol = 1;
[ii, jj] = find(abs(A(:).'-B(:))<=tol);
ib = accumarray(jj, ii, [numel(A) 1], #(x){x});
Note that this approach
may be memory-intensive, because of the intermediate matrix;
can be made to work in old Matlab versions, because it doesn't use ismembertol; but then implicit expansion has to be replaced by explicitly calling bsxfun:
[ii, jj] = find(abs(bsxfun(#minus, A(:).', B(:)))<=tol);
ib = accumarray(jj, ii, [numel(A) 1], #(x){x});
I'm attempting to index an array based on conditions in the array itself and corresponding locations in other arrays. I've produced a MWE but this will be hopefully used in a much larger example, within a loop to automate across scenarios, dare I say... using parallelisation?
MWE:
# create 3d array
a, b, c = [8;8;6;5;5;6], [8;8;7;6;6;6], [8;2;7;7;6;6]
d = transpose(cat(a,b,c, dims = 2))
e, f, g = [3;2;5;1;4;1], [4;3;1;1;1;2], [5;1;2;1;2;3]
h = transpose(cat(e,f,g, dims = 2))
wrkarr = cat(d,h,dims = 3)
# create temp array for indexes
temp = wrkarr[size(wrkarr,1), :, 1]
# calculate indexes
temp[(wrkarr[size(wrkarr,1),:,1] .== 8) .& (wrkarr[size(wrkarr,1),:,2]) .>= 4] .= 22
In my case it doesn't change anything in the temp array, when I would expect the first element to be changed from 8 to 22. Both of the individual conditional tests produce a vector [1,0,0,0,0,0] so why won't the .& test produce the same? Thx. J
First, and as an aside, please note that you can use arr[end,i] to refer to the element arr with the last index in the 1st axis, and index i in the second axis.
Using this notation, your condition can be rewritten as:
julia> (wrkarr[end,:,1] .== 8) .& (wrkarr[end,:,2]) .>=4
6-element BitArray{1}:
0
0
0
0
0
0
It might be a bit easier to see here that there is a parenthesis issue. I think you actually wanted to write:
julia> (wrkarr[end,:,1] .== 8) .& (wrkarr[end,:,2] .>=4)
6-element BitArray{1}:
1
0
0
0
0
0
Making this change does what (I think) you want. (Also note that I added #views below in order to avoid allocations and speed things up a little)
julia> idx = (#view(wrkarr[end,:,1]) .== 8) .& (#view(wrkarr[end,:,2]) .>=4);
julia> temp[idx] .= 22
1-element view(::Array{Int64,1}, [1]) with eltype Int64:
22
julia> temp
6-element Array{Int64,1}:
22
2
7
7
6
6
EDIT: as mentioned in comments, other solutions could be considered:
using findall to generate a vector of indices matching the condition
using a simple for loop
Here is a benchmark of all three solutions, in order to see how they compare in terms of readability and performance.
TLDR: the for loop seems to be much more efficient in this case, and allocates less.
# create 3d array
d = [8 8 6 5 5 6;
8 8 7 6 6 6;
8 2 7 7 6 6]
h = [3 2 5 1 4 1;
4 3 1 1 1 2;
5 1 2 1 2 3]
wrkarr = cat(d,h,dims = 3)
using BenchmarkTools
Option 1 logical indexing
julia> function version1!(temp, wrkarr)
idx = (#view(wrkarr[end,:,1]) .== 8) .& (#view(wrkarr[end,:,2]) .>= 4)
temp[idx] .= 22
end
version1! (generic function with 1 method)
julia> temp = wrkarr[end, :, 1]; #btime version1!($temp, $wrkarr); temp
182.646 ns (3 allocations: 224 bytes)
6-element Array{Int64,1}:
22
2
7
7
6
6
Option 2 vector of indices
julia> function version2!(temp, wrkarr)
idx = findall(i -> (wrkarr[end,i,1] == 8) & (wrkarr[end,i,2] >=4), axes(wrkarr,2))
temp[idx] .= 22
end
version2! (generic function with 1 method)
julia> temp = wrkarr[end, :, 1]; #btime version2!($temp, $wrkarr); temp
134.395 ns (3 allocations: 208 bytes)
6-element Array{Int64,1}:
22
2
7
7
6
6
Option 3 for loop
julia> function version3!(temp, wrkarr)
#inbounds for i in axes(wrkarr, 2)
if wrkarr[end, i, 1] == 8 && wrkarr[end, i, 2] >= 4
temp[i] = 22
end
end
end
version3! (generic function with 1 method)
julia> temp = wrkarr[end, :, 1]; #btime version3!($temp, $wrkarr); temp
21.820 ns (0 allocations: 0 bytes)
6-element Array{Int64,1}:
22
2
7
7
6
6
Based on all the clever stuff given to me above I pushed it a bit further and this solution appears to work and dispenses with the need for an index array, simply does the substitution right back into the original array. Is there anything wrong with that? Looking at #François Févotte's answer the loop function is the fastest, and this could be very important when scaled up to proper size. Now for my next challenge I want to use the same function to loop through sets of numbers to replace the 8, 4, 22, for example for the same wrkarr:
== 8 &>= 4 -> 22
== 7 &>= 2 -> 8
== 6 &>= 3 -> 7
Any takers or suggestions? When I get that to work I want to see if it can be parallelized across these individual sets of numbers, i.e. each substitution can be done independently, not dependent on any other. Thx a bunch!
function version4(wrkarr)
#inbounds for i in axes(wrkarr, 2)
if wrkarr[end, i, 1] == 8 && wrkarr[end, i, 2] >= 4
wrkarr[end,i, 1] = 22
end
end
end
wrkarr[end, :, 1]; #btime version4($wrkarr); wrkarr
2.237 ns (0 allocations: 0 bytes)
3×6×2 Array{Int64,3}:
[:, :, 1] =
8 8 6 5 5 6
8 8 7 6 6 6
22 2 7 7 6 6
[:, :, 2] =
3 2 5 1 4 1
4 3 1 1 1 2
5 1 2 1 2 3
I have a 2D array such as:
julia> m = [1 2 3 4 5
6 7 8 9 10
11 12 13 14 15]
3×5 Array{Int64,2}:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
I want to pick one value from each column and construct a 1D array.
So for instance, if my choices are
julia> choices = [1, 2, 3, 2, 1]
5-element Array{Int64,1}:
1
2
3
2
1
Then the desired output is [1, 7, 13, 9, 5]. What's the best way to do that? In my particular application, I am randomly generating these values, e.g.
choices = rand(1:size(m)[1], size(m)[2])
Thank you!
This is probably the simplest approach:
[m[c, i] for (i, c) in enumerate(choices)]
EDIT:
If best means fastest for you such a function should be approximately 2x faster than the comprehension for large m:
function selector(m, choices)
v = similar(m, size(m, 2))
for i in eachindex(choices)
#inbounds v[i] = m[choices[i], i]
end
v
end
I have a bunch of arrays that I have generated from a loop
Peaks [1, 2, 3, 4, 5]
Latency [23,24,25,26,27] etc.
I want to put all of those in a matrix that will look like that:
Peaks Latency
1 23
2 24
3 25
4 26
5 27
Then I'll want to save this as a text file.
It seems like it would be fairly simple but can't seem to find anything that closely speaks to me right now.
Concatentate:
>> Peaks = [1 2 3 4 5];
>> Latency = [23 24 25 26 27];
>> T = [Peaks(:) Latency(:)]
T =
1 23
2 24
3 25
4 26
5 27
Write:
fileName = 'PeaksLatency.txt';
hdr = {'Peaks','Latency'}
txt = sprintf('%s\t',hdr{:}); txt(end) = [];
dlmwrite(fileName,txt,''); % write header
dlmwrite(fileName,T,'-append','delimiter','\t'); % append data
Here is the code
Peaks = [1, 2, 3, 4, 5].';
Latency = [23,24,25,26,27].';
T = table(Peaks, Latency);
writetable(T,'table.txt', 'Delimiter', '\t');
Note that you need to make Peaks and Latency into column vectors (use .' operator).
Ref: http://www.mathworks.com/help/matlab/ref/writetable.html
suppose there are arrays A and B, both of which can have any arbitrary numbers and size. for example
A=[1 2 3]
B=[4 8 52 7 10]
i was wondering if there was any way to check if any of the elements in A are contained in B without using a loop? Once again, the numbers and size of the array will be arbitrary so i can't hard code it. Any help and input would be appreciated. Thanks!
You mean like this:
A=[1 2 3]; B=[4 8 52 7 10]
ismember(A,B)
ans =
0 0 0
Add to #NasserM.Abbasi: ismember will work regardless shapes and sizes, it is always element-wise. So if you have A=[1 2; 3 4] and B=[1 3; 4 2; 1 2],
then ismember will return :
ismember(A,B); % -> [1 1; 1 1] due to element-wise membership check
ismember(A,B, 'rows'); % -> [1 0] since it checks row-wise.
use ismember carefully according to the possible shapes in A and B.