Made a post earlier today expressing I was trying to find a solution to the N-Queens problem. The first part of this is determining the following function:
>safe(chess.piece,chess.board)
Where:
>chess.board <- matrix(0,8,8)
>chess.board[r,c] <- 1 #1 represents the queen which can be placed in any row/column on the board
>chess.piece <- c(x,x) #basically and row/column value I choose in the 8x8 matrix
Currentley I have the following code for the horizontal and vertical planes:
>safe <- function(a,b){
if((sum(b[a[1],])<1) & (sum(b[,a[2]])<1))
{return(TRUE)
}else{
return(FALSE)
}
}
Basically works on summing the rows/columns and checking if greater (FALSE) or equal (TRUE) to 0. But how in the world do I find the diagonal sum of the chess.board matrix based on the rows/columns determined by the chess.piece ?! I am ripping my hair out over this as I am decently new to R but I need a solution and just can't seem to figure it out.
Any help would be greatly appreciated! Thanks in advance, J.S
Consider you have to check if board element (x,y) can be attacked from any diagonal element or not. (x,y) can be attacked diagonally if any element lying on its diagonal element is a queen.Assume (p,q) is board element having a queen.Now condition for element(x,y) to lie on diagonal coordinates of board element (p,q) would be p+q == x+y or p-q == x-y .This can also be interpreted as the condition for elements (p,q) and (x,y) to lie on same diagonal.So, if there is queen at (p,q) and we have to check whether (x,y) can be attacked by this queen or not, the condition for this would be:-
if((board[p][q] == 1 ) && ((p+q == x+y) || (p-q == x-y))){
return true;
}
Complete function for checking if element at (x,y) i.e., board[x,y] is attacked by diagonal elements or not would be:-
for(int p=1;p<board.length;p++){
for(int q=1;q<board.length;q++){
if(p==x && q==y){ //skipping check if element under consideration is same
continue;
}
if((board[p][q] == 1 )&& ((p+q == x+y) || (p-q == x-y))){
return true;
}
}
}
Complete function for checking if element (x,y) is attacked or not would be:-
public static boolean is_attacked(int x,int y,int board[][],int n){
for(int i = 1;i < board.length;i++){
if(board[x][i] == 1){ //if any cell in xth row is 1 i.e.,queen is there in that row
return true;
}
}
for(int i = 1;i < board.length;i++){
if(board[i][y] == 1){ //if any cell in yth column is 1 i.e.,queen is there in that column
return true;
}
}
for(int p=1;p<board.length;p++){
for(int q=1;q<board.length;q++){
if(p==x && q==y){
continue;
}
if((board[p][q]== 1 )&& ((p+q== x+y) || (p-q == x-y))){
return true;
}
}
}
return false;
}
Hope this helps!!!
One approach is to write a couple of functions to extract partial diagonals from a square matrix, using the fact that you can use 1-dimensional indexing since matrices are just vectors under the hood and these diagonals correspond to certain arithmetical sequences of indices:
udiag <- function(A,i,j){
n <- nrow(A)
a <- i + n*(j-1) - (n-1)*min(n-i,j-1)
b <- i + n*(j-1) + (n-1)*min(i-1,n-j)
A[seq(a,b,n-1)]
}
ddiag <- function(A,i,j){
n <- nrow(A)
a <- i + n*(j-1) - (n+1)*min(i-1,j-1)
b <- i + n*(j-1) + (n+1)*min(n-i,n-j)
A[seq(a,b,n+1)]
}
These two functions extract the upward slanting and downward slanting diagonals respectively. You can use these two functions and write your safe like this:
safe <- function(x,y){
i <- x[1]
j <- x[2]
sum(y[i,]) == 0 & sum(y[,j]) == 0 & sum(udiag(y,i,j)) == 0 & sum(ddiag(y,i,j)) == 0
}
On Edit: In view of the intended application, I wrote udiag() and ddiag() to work with square matrices only. Since they may have other uses in potentially nonsquare matrices, they can be easily modified to handle such cases:
udiag <- function(A,i,j){
m <- nrow(A)
n <- ncol(A)
a <- i + m*(j-1) - (m-1)*min(m-i,j-1)
b <- i + m*(j-1) + (m-1)*min(i-1,n-j)
A[seq(a,b,m-1)]
}
ddiag <- function(A,i,j){
m <- nrow(A)
n <- ncol(A)
a <- i + m*(j-1) - (m+1)*min(i-1,j-1)
b <- i + m*(j-1) + (m+1)*min(m-i,n-j)
A[seq(a,b,m+1)]
}
For example:
> A <- matrix(1:12,nrow = 3)
> A
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
> udiag(A,2,3)
[1] 6 8 10
> ddiag(A,2,3)
[1] 4 8 12
Related
I am trying to apply a function on the elements of an array that are different from NA. I tried to use an if statement with the !is.na function but I get an error message saying that the "argument is of length zero". Would someone have an idea on how to fix that error or an alternative way to only select the non NA values of the matrix?
F <- function(x, a, b, c, d) {
f <- a*(tanh(b*(x - c)) - d)
return(f)
}
nlon <- 3241 ; nlat <- 1680
p1 <- 3221 ; p2 <- 1103
pr_new <- matrix(0, nlat, nlon) # for the example
lim <- 10
for (n in 1:nlon) {
a <- -0.5; b <- 1; c <- 0; d <- 1 #Parameters of F
if (n < p1) { #left side of the step
for (m in nlat - lim:nlat) {
if (!is.na(c(pr_new[m, n]))) { #no calculation on the NA values
pr_new[m, n] <- F(n, a, b, c, d)
}
}
} else { #right side of the step
if (is.na(c(pr_new[p2, n]))) { #if we are on the upper step
for (m in p2 - 1:p2 - 1 - lim) {
if (!is.na(c(pr_new[m, n]))) { #no calculation on the NA values
pr_new[m, n] <- F(m, a, b, c, d)
}
}
} else { #if we are on the lower step
for (m in p2:p2 - lim) {
if (!is.na(c(pr_new[m, n]))) { #no calculation on the NA values
pr_new[m, n] <- F(m, a, b, c, d)
}
}
}
}
}
You can find out which value to which a loop-index was set after an error by simply typing the loop-index name at the console:
Error in if (!is.na(c(pr_new[m, n]))) { : argument is of length zero
> m
[1] 0 # R uses 1 based indexing so 0 indexed value is not there
> n
[1] 1
> str( p2:p2-lim) # demonstrating error
num 1093
The comment was correct from #zephryl , but it only identified one of the three times that a similar error was made.
for (m in nlat-lim:nlat){ ...
for (m in p2-1:p2-1-lim){ ...
for (m in p2:p2-lim){ ...
In each of these an expression using both colons and minnus signs has been incorrectly contsructed because the ":" has a higher operator precedence than a binary minus sign. You can find the operator precedence rules at the ?Syntax help page.
If you correct those three errors you get code that runs without error.
for (n in 1:nlon){
a= -0.5; b=1; c=0; d=1 #Parameters of F
if (n<p1){ #left side of the step
for (m in (nlat-lim):nlat ){ # fix #1
if (!is.na(c(pr_new[m,n]))){ #no calculation on the NA values
pr_new[m,n]=F(n,a,b,c,d)
}
}
}
else{ #right side of the step
if (is.na(c(pr_new[p2,n]))) { #if we are on the upper step
for (m in (p2-1):(p2-1-lim) ){ # fix #2
if (!is.na(c(pr_new[m,n]))){ #no calculation on the NA values
pr_new[m,n]=F(m,a,b,c,d)
}
}
}
else { #if we are on the lower step
for (m in p2:(p2-lim) ){ # fix # 3
if (!is.na(c(pr_new[m,n]))){ #no calculation on the NA values
pr_new[m,n]=F(m,a,b,c,d)
}
}
}
}
}
Regarding the tangential "answer" from a new user of low rep, I did test the theory that it might return a similar answer. I did try chatGPT on some questions and noticed that it not only returned incorrect ansers, but it was alo unable to learn from its mistakes when there were reported to it. When the title and body of the question were given to ChatGPT it gave an almost identical answer to the now-deleted one.
The which function can be used to return a vector of indices from an array or matrix but it is most useful when it is used with the arr.ind parameter is set to its non-default value: ..., arr.in = TRUE. And na.omit can be used to remove cases from matrices. It will however, remove, entire lines of values for any row that contains a single NA.
A sequence (e.g. c(1,2,3,4)) is almost increasing when we can remove exactly one element from the sequence and get a strictly increasing sequence (i.e. a0 < a1 < ... < an). I'm trying to find a way to check whether a sequence is almost increasing. If it is, I want to return TRUE; if it isn't I want to output FALSE. I've got this far:
solution <- function(sequence) {
sequence1 <- unlist(sequence)
if (length(sequence1) == 1) {
next
}
count <- 0
for (i in (length(sequence1) - 1)) {
if (sequence1[i + 1] > sequence1[i]) {
next
} else if (((sequence1[i + 2] > sequence1[i]) & count == 0) & i !=
length(sequence1)-1) {
sequence1 <- sequence1[- (i + 1)]
count <- count + 1
} else if ((sequence1[i + 1] > sequence1[i - 1]) & count == 0 & i != 1) {
sequence1 <- sequence1[-i]
count <- count + 1
} else {
return(FALSE)
}
}
return(TRUE)
}
I've used unlist() because codesignal, for some reason, doesn't accept you to refer to the function argument within the function. This works for some sequences: solution(c(4,1,5)) correctly returns TRUE. It doesn't work for others: solution(c(1, 1, 1, 2, 3)) incorrectly returns TRUE. solution(c(2,1,2,1)) correctly returns FALSE and yet solution(c(1,2,1,2)) incorrectly returns TRUE. I've lost my grip on what's going on. I wonder if anyone can spot anything?
Clarification: the basic idea of my code is to iterate through the sequence and for each element check whether its right neighbour is a bigger number. If it isn't, then we have two options: get rid of i or get rid of i+1, so I check those in turn. Since we can only make one change, i've added the condition that if count is 1, then we skip to finish. Also, if the index is 1 then we can't check i-1, and if the index is length(sequence)-1, then we can't check i+2, so i've added those conditions in to make sure my code skips to the other option if appropriate.
Here is a solution which works for me. The idea is that diff(x) has negative elements for every downwards step in x. For example, min(diff(x)) is positive, if x is strictly increasing. If diff(x)[i] <= 0 for exactly one index i, we have to check whether either removing x[i] or removing x[i+1] makes the sequence strictly increasing. The following function passed all tests I tried:
check_almost <- function(x) {
if (length(x) < 2) {
return(TRUE)
}
d <- diff(x)
i <- which(d <= 0)
if (length(i) == 0) {
return(TRUE) # strictly increasing
} else if (length(i) > 1) {
return(FALSE)
}
return(i == 1 || # we can remove x[1]
i == length(d) || # we can remove x[length(x)]
d[i-1]+d[i] > 0 || # we can remove x[i]
d[i] + d[i+1] > 0) # we can remove x[i+1]
}
I am trying to run a loop that contains a while and an if statement. The code works outside of the loop but not inside! This is a very simplified version which basically is trying to collect sets xx[j] which contain 10 numbers each.
When I run it, it never actually allocates the 'x' to the set xx[j] but I'm not sure why!
n <- 10
xx <- list()
for (j in 1:5) {
xx[j] <= NULL
while (length(xx[j]) < n) {
x <- runif(1)
if (0.5 <= x) {
xx[j] <- c(xx[j], x)
}
}
}
I've fixed and polished the code.
The changes are:
Elements of a list are accessed with double brackets xx[[j]]
The list is created of the target length 5
Removed setting the elements of the list to NULL as they are NULL initially
The fixed code:
n = 10
xx = vector('list',5)
for (j in seq_along(xx)) {
while(length(xx[[j]]) < n){
x = runif(1)
if (0.5 <= x) {
xx[[j]] = c(xx[[j]], x)
}
}
}
Here is my function that does a loop:
answer = function(a,n) {
for (k in 0:n) {
x =+ (a^k)/factorial(k)
}
return(x)
}
answer(1,2) should return 2.5 as it is the calculated value of
1^0 / 0! + 1^1 / 1! + 1^2 / 2! = 1 + 1 + 0.5 = 2.5
But I get
answer(1,2)
#[1] 0.5
Looks like it fails to accumulate all three terms and just stores the newest value every time. += does not work so I used =+ but it is still not right. Thanks.
answer = function(a,n) {
x <- 0 ## initialize the accumulator
for (k in 0:n) {
x <- x + (a^k)/factorial(k) ## note how to accumulate value in R
}
return(x)
}
answer(1, 2)
#[1] 2.5
There is "vectorized" solution:
answer = function(a,n) {
x <- a ^ (0:n) / factorial(0:n)
return(sum(x))
}
In this case you don't need to initialize anything. R will allocate memory behind that <- and sum.
You are using Taylor expansion to approximate exp(a). See this Q & A on the theme. You may want to pay special attention to the "numerical convergence" issue mentioned in my answer.
Hi I was wondering if someone knows how to realize this sequence in R?
Consider a sequence with following requirement.
a1=1
an=an-1+3 (If n is a even number)
an=2×an-1-5 (If n is a odd number)
e.g. 1,4,3,6,7,10,15,...
a30=?
Try the following.
It will return the entire sequence, not just the last element.
seq_chih_peng <- function(n){
a <- integer(n)
a[1] <- 1
for(i in seq_along(a)[-1]){
if(i %% 2 == 0){
a[i] <- a[i - 1] + 3
}else{
a[i] <- 2*a[i - 1] - 5
}
}
a
}
seq_chih_peng(30)
Note that I do not include code to check for input errors such as passing n = 0 or a negative number.
If you want to do it recursively, you just have the write the equations in your function as follows:
sequence <- function(n) {
if (n == 1) return(1)
else if (n > 1) {
if (n %% 2 == 1) {
return(2 * sequence(n - 1) - 5)
}else{
return(sequence(n - 1) + 3)
}
}else{
stop("n must be stricly positive")
}
}
sequence(30)
# returns 32770