I have a list of vectors in the vector space Q with a dimension of 5, which I want to order in a list and use Combinations(list, 4) to get all sublists with 4 elements. I then want to
check how many of those sublists are linear independent in the Vector Space with V.linear dependence(vs) == [].
I'm running into an error when running my code:
V = VectorSpace(QQ,5)
V.list = ([2, 2, 2,-3,-3],[2, 2,-3,2,-3],[2,2,-3,-3,2],[2,-3,2,2,-3],[2,-3,2,-3,2],[2,-3,-3,2,2],[-3,2,2,2,-3],[-3,2,2,-3,2],[-3,2,-3,2,2],[-3,-3,2,2,2])
C = Combinations(list, 4)
V.linear_dependence(C) == []
"ValueError: vector [[2, 2, 2, -3, -3], [2, 2, -3, 2, -3], [2, 2, -3, -3, 2], [2, -3, 2, 2, -3]] is not an element of Vector space of dimension 5 over Rational Field"
Anyone got any clues as to what im missing?
You are asking it to just take a list (or actually, tuple) and put it in the vector space, but I think Sage doesn't do that automatically. Try this.
V = VectorSpace(QQ,5)
list = ([2, 2, 2,-3,-3],[2, 2,-3,2,-3],[2,2,-3,-3,2],[2,-3,2,2,-3],[2,-3,2,-3,2],[2,-3,-3,2,2],[-3,2,2,2,-3],[-3,2,2,-3,2],[-3,2,-3,2,2],[-3,-3,2,2,2])
C = Combinations(list, 4)
for c in C:
if V.linear_dependence([V(x) for x in c]) == []: print c
The reason for a double list is that neither of these things are inherently in a vector space.
A slight modification to this, replacing print c with z+=1 (having predefined z=0) says that 185 of your 210 combinations appear to be linearly independent.
By the way, comparing to the empty list might not be as efficient as other options.
Related
I have two 1D tensors
a = tensor([1, 2])
b = tensor([3, 4, 5])
I want to compute custom operation pairwise matrix, for example
"a + b" - adds every element from a to every element from b
tensor([4, 5, 6], [5, 6, 7])
"a / b" - divides every element from a by every element from b
tensor([1/3, 1/4, 1/5], [2/3, 2/4, 2/5])
Can this be done efficiently, without for cycles?
Yes, you can do that element-wise in a vectorised form.
First bring the operands to broadcastable shapes (You can read about the pytorch broadcasting semantics here)
a = a.unsqueeze(-1) # a.shape == (2, 1)
b = b.unsqueeze(-2) # b.shape == (1, 3)
# the last line is redundant in fact, according to the semantics
Then apply the operation you want:
c = a / b # c.shape == (2, 3)
I have an array x and I would like to repeat each entry of x a number of times specified by the corresponding entries of another array y, of the same length of x.
x = [1, 2, 3, 4, 5] # Array to be repeated
y = [3, 2, 1, 2, 3] # Repetitions for each element of x
# result should be [1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5]
Is there a way to do this in Julia?
Your x and y vectors constitute what is called a run-length encoding of the vector [1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5]. So if you take the inverse of the run-length encoding, you will get the vector you are looking for. The StatsBase.jl package contains the rle and inverse_rle functions. We can use inverse_rle like this:
julia> using StatsBase
julia> x = [1, 2, 3, 4, 5];
julia> y = [3, 2, 1, 2, 3];
julia> inverse_rle(x, y)
11-element Vector{Int64}:
1
1
1
2
2
3
4
4
5
5
5
You've given what I would have suggested as the answer already in your comment:
vcat(fill.(x, y)...)
How does this work? Start with fill:
help?> fill
fill(x, dims::Tuple)
fill(x, dims...)
Create an array filled with the value x. For example, fill(1.0, (5,5)) returns a 5×5 array of floats, with each element initialized to 1.0.
This is a bit more complicated than it needs to be for our case (where we only have one dimension to fill into), so let's look at a simple example:
julia> fill(1, 3)
3-element Vector{Int64}:
1
1
1
so fill(1, 3) just means "take the number one, and put this number into a one-dimensional array 3 times."
This of course is exactly what we want to do here: for every element in x, we want an array that holds this element multiple times, with the multiple given by the corresponding element in y. We could therefore loop over x and y and do something like:
julia> for (xᵢ, yᵢ) ∈ zip(x, y)
fill(xᵢ, yᵢ)
end
Now this loop doesn't return anything, so we'd have to preallocate some storage and assign to that within the loop. A more concise way of writing this while automatically returning an object would be a comprehension:
julia> [fill(xᵢ, yᵢ) for (xᵢ, yᵢ) ∈ zip(x, y)]
5-element Vector{Vector{Int64}}:
[1, 1, 1]
[2, 2]
[3]
[4, 4]
[5, 5, 5]
and even more concisely, we can just use broadcasting:
julia> fill.(x, y)
5-element Vector{Vector{Int64}}:
[1, 1, 1]
[2, 2]
[3]
[4, 4]
[5, 5, 5]
so from the comprehension or the broadcast we are getting a vector of vectors, each vector being an element of x repeated y times. Now all that remains is to put these together into a single vector by concatenating them vertically:
julia> vcat(fill.(x, y)...)
11-element Vector{Int64}:
1
1
1
2
2
3
4
4
5
5
5
Here we are using splatting to essentially do:
z = fill.(x, y)
vcat(z[1], z[2], z[3], z[4], z[5])
Note that splatting can have suboptimal performance for arrays of variable length, so a better way is to use reduce which is special cased for this and will give the same result:
reduce(vcat, fill.(x, y))
If performance is a priority, you can also do it the long, manual way:
function runlengthdecode(vals::Vector{T}, reps::Vector{<:Integer}) where T
length(vals) == length(reps) || throw(ArgumentError("Same number of values and counts expected"))
result = Vector{T}(undef, sum(reps))
resind = 1
for (valind, numrep) in enumerate(reps)
for i in 1:numrep
#inbounds result[resind] = vals[valind]
resind += 1
end
end
result
end
This runs about 12 times faster than the vcat/fill based method for the given data, likely because of avoiding creating all the intermediate filled vectors.
You can also instead use fill! on the preallocated result's #views, by replacing the loop in above code with:
for (val, numrep) in zip(vals, reps)
fill!(#view(result[resind:resind + numrep - 1]), val)
resind += numrep
end
which has comparable performance.
Also, for completeness, a comprehension can be quite handy for this. And it's faster than fill and vcat.
julia> [x[i] for i=1:length(x) for j=1:y[i]]
11-element Vector{Int64}:
1
1
1
2
2
3
4
4
5
5
5
My question is about getting rid of a for loop while retaining the functionality of the code.
I have a matrix of pairwise orderings of elements A_1, A_2, ... A_N. Each ordering is represented as a row of a matrix. The code below shows an example.
# Matrix representing the relations
# A1 < A2, A1 < A5, A2 < A4
(mat <- matrix(c(1, 2, 1, 5, 2, 4), ncol = 2, byrow = TRUE))
#> [,1] [,2]
#> [1,] 1 2
#> [2,] 1 5
#> [3,] 2 4
I want this whole matrix as a set of ordered pairs. The reason is that I later need to generate the transitive closure of these relations. I have been using the sets package and created the function below.
create_sets <- function(mat){
# Empty set
my_set <- sets::set()
# For loop for adding pair elements to the set, one at a time
for(i in seq(from = 1, to = nrow(mat), by = 1)){
my_set <- sets::set_union(my_set,
sets::pair(mat[[i, 1]], mat[[i, 2]]))
}
return(my_set)
}
create_sets(mat)
#> {(1, 2), (1, 5), (2, 4)}
This function works well, but I believe the for loop is unnecessary, and am not capable of replacing it. For the particular example matrix above with exactly three rows, I could instead have used to following code:
my_set2 <- sets::set(
sets::pair(mat[[1, 1]], mat[[1, 2]]),
sets::pair(mat[[2, 1]], mat[[2, 2]]),
sets::pair(mat[[3, 1]], mat[[3, 2]])
)
my_set2
#> {(1, 2), (1, 5), (2, 4)}
The reason why this works, is that sets::set takes any number of pairs.
args(sets::set)
#> function (...)
#> NULL
However, the matrix mat will have an arbitrary number of rows, and I want the function to be able to handle all possible cases. This is why I have not been able to get rid of the for loop.
My question is hence: Given a matrix mat in which each row represents an ordered pair, is there some generic way of passing the pairs in each row as separate arguments to sets::set, without looping?
The OP has asked
[...] is there some generic way of passing the pairs in each row as separate arguments to sets::set, without looping?
Yes, the do.call() function is probably what you are looking for. From help(do.call):
do.call constructs and executes a function call from a name or a function and a list of arguments to be passed to it.
So, OP's create_sets() function can be replaced by
do.call(sets::set, apply(mat, 1, function(x) sets::pair(x[1], x[2])))
{(1, 2), (1, 5), (2, 4)}
The second argument to do.call() requires a list. This is created by
apply(mat, 1, function(x) sets::pair(x[1], x[2]))
which returns the list
[[1]]
(1, 2)
[[2]]
(1, 5)
[[3]]
(2, 4)
apply(mat, 1, FUN) is a kind of implied for loop which loops over the rows of a matrix mat and takes the vector of row values as argument when calling function FUN.
Edit: as.tuple() instead of pair()
The pair() function requires exactly two arguments. This is why we were forced to define an anonymous function function(x) sets::pair(x[1], x[2]).
The as.tuple() function coerces the elements of an object into elements of a set. So, the code can be even more simplified :
do.call(sets::set, apply(mat, 1, sets::as.tuple))
{(1, 2), (1, 5), (2, 4)}
Here, as.tuple() takes the whole vector of row values and coerces it to a set.
Option 1: do nothing
for loops aren't always the end of the world, this doesn't look too bad if your matrices aren't enormous.
Option 2: the split, apply, combine way (by way of a new function)
Write a function that combines the row things (there is a shorter way to do this, but this makes your task explicit)
f <- function(x) {
sets::pair(x[1], x[2])
}
Reduce(sets::set_union, lapply(split(mat, 1:nrow(mat)), f))
## {(1, 2), (1, 5), (2, 4)}
The Reduce does the same thing as the for loop (repeatedly apply set_union), and the lapply turns the matrix into a list of pairs (also like a for loop would)
I have a vector in R, say c(2, 2, 3, 2, 3, 4, 4), and I want to build a square matrix of size n (the number of elements of the vector) that has a 1 if the element i of the vector has the same value of the element j , and 0 otherwise. In this example , the element [1,2] and [1,4] of the matrix must have a 1 because the first, second and fourth elements of the vector are the same.
Is there a way to do this ? A command or function to build ? Something with combinations ? I would like to avoid loops like for.
Thank you !
This just came to my mind... Is this what you want?
a <- c(2, 2, 3, 2, 3, 4, 4)
mat <- a%*%t(a)
apply(mat, 2, function(x){as.integer((x/a)==a)})
We can use outer to create a square matrix by comparing each element of the vector with the other elements
+(outer(v1, v1, `==`))
Or use sapply
+(sapply(v1, `==`, v1))
Let's say I have a multi-dimensional array called pi, and its number of dimensions isn't known until the runtime:
dims <- rep(3, dim_count)
pi <- array(0, dims)
As you can see the dimension count depends on dim_count. How do I retrieve a value from the array when I have a vector of the indexes? For example when I have:
dim_count <- 5
indexes <- c(1, 2, 3, 3, 3)
I want to retrieve
pi[1, 2, 3, 3, 3]
Is there a short, effective and hopefully elegant way of doing this?
Making use of a little known usage of [:
When indexing arrays by [ a single argument i can be a matrix with as many columns as there are dimensions of x; the result is then a vector with elements corresponding to the sets of indices in each row of i.
you can simply do:
pi[matrix(indexes, 1)]
do.call("[",...) seems to work.
indexes <- c(1,2,3,3,3)
pi[1,2,3,3,3] <- 17 ## so we know if we succeeded or not
do.call("[",c(list(pi),as.list(indexes)))
Note that your example wouldn't work -- your dimensions were all 3, but some of your index elements were >3 ...
do.call() is an option:
dim_count <- 5
indexes <- c(1, 2, 2, 2, 3)
dims <- rep(3, dim_count)
pi <- array(seq_len(prod(dims)), dims)
do.call(`[`, c(list(x = pi), as.list(indexes)))
Which gives:
> do.call(`[`, c(list(x = pi), as.list(indexes)))
[1] 202
> pi[1, 2, 2, 2, 3]
[1] 202
The tricky bit is getting the list of arguments in the right format. pi should be the first argument to "[" (or named as argument x, see ?"["), whilst we want each element of indexes itself to be a component of the supplied list, not a vector within that list. Hence the convoluted c(list(x = pi), as.list(indexes)).
An alternative way to construct the argument list which might be easier to follow is:
ARGS <- vector("list", length = dim_count + 1)
ARGS[[1]] <- pi
ARGS[2:length(ARGS)] <- indexes
do.call("[", ARGS)
which gives
> do.call("[", ARGS)
[1] 202
> pi[1, 2, 2, 2, 3]
[1] 202