Contiguous group of cells in grid - answer-set-programming

I'm working on a puzzle solver (nonograms, griddler, picross...) just for fun and to learn a bit more of ASP. (You can read more about these puzzles in wikipedia https://en.wikipedia.org/wiki/Nonogram)
I want to check if there's a horizontal contiguous group of black colored cells (cell(I,J,o)) surrounded by two white cells (cell(I,J,x)), one to the left and one to the right of the group.
#const rows = 3.
#const cols = 3.
symbol(x;o).
row(0..rows+1).
col(0..cols+1).
% Padding surrounding the puzzle so we can check every group's surroundings
cell(I,0,x) :- row(I).
cell(I,cols+1,x) :- row(I).
cell(0,J,x) :- col(J).
cell(cols+1,J,x) :- col(J).
% Assign symbols to every cell available
1 { cell(I, J, S) : symbol(S) } 1 :- row(I), col(J).
% Horizontal block (row,starting col,length)
hblock(I,J1,L) :- row(I), col(J1), col(J2), J1 <= J2, L = J2-J1+1,
col(J1-1), col(J2+1), cell(I,J1..J2,o),
cell(I,J1-1,x), cell(I,J2+1,x).
% Output only cells that are not padding
out_cell(I,J,S) :- cell(I,J,S), I > 0, J > 0, I <= rows, J <= cols.
#hide.
#show hblock/3.
#show out_cell/3.
As you can see I'm using cell(I,J1..J2,o) in the hblock/3 definition to check that every cell between col(J1) and col(J2) is black (marked with the o symbol), but when given the following input:
cell(1,1,x). cell(1,2,x). cell(1,3,x).
cell(2,1,o). cell(2,2,x). cell(2,3,o).
cell(3,1,x). cell(3,2,x). cell(3,3,x).
It outputs hblock(2,3,1) hblock(2,1,3) hblock(2,1,1), which means that it's detecting two blocks of a single black cell (In (2,1) and (2,3)) and a larger block of three black cells between (2,1) and (2,3), but it shouldn't be detected as it has a cell marked with x in the middle...
What am I doing wrong?

If I recall correctly, cell(I,J1..J2,o) will generate separate rules for each number between J1 and J2. It doesn't expand them on the same line i.e. in one rule. So
hblock(I,J1,L) :- row(I), col(J1), col(J2), J1 <= J2, L = J2-J1+1,
col(J1-1), col(J2+1), cell(I,J1..J2,o),
cell(I,J1-1,x), cell(I,J2+1,x).
expands to
...
hblock(1,1,1) :- cell(1,1,o).
hblock(1,2,1) :- cell(1,2,o).
hblock(1,3,1) :- cell(1,3,o).
hblock(1,1,2) :- cell(1,1,o).
hblock(1,1,2) :- cell(1,2,o).
hblock(1,2,2) :- cell(1,2,o).
hblock(1,2,2) :- cell(1,3,o).
hblock(1,1,3) :- cell(1,1,o).
hblock(1,1,3) :- cell(1,2,o).
hblock(1,1,3) :- cell(1,3,o).
...
I didn't get as far as figuring out why hblock(2,1,2) and hblock(2,2,2) are missing, but that's probably not very relevant.

Related

How to insert a structure within a structure

I have a 1x1 structure called imu_data.txyzrxyz1. It has one field called txyzrxyz1 and the value is 4877x7 double. I just want to "copy and paste" row 62 into row 63 (double up that row) so that the structure now becomes a 4878x7 structure. I've tried the following, with other versions without success:
extra_63 = imu_data.txyzrxyz1(63,:);
imu_data2.txyzrxyz1 = [{imu_data.txyzrxyz1(1:62,:) extra_63 imu_data.txyzrxyz1(63:end,:)}]
Thanks
You can index the row to duplicate twice while matrix indexing:
row_to_duplicate = 63;
yourdata = rand(100,10);
yourstruct.data = yourdata;
yourstruct.data = yourstruct.data([1:row_to_duplicate, row_to_duplicate:end],:)
So in case of 63, 1:row_to_duplicate will create a column vector from 1:63, and row_to_duplicate:end will create a column vector from 63:100 in this example. When combining these, 63 will occur twice, hence that row is duplicated.
You were almost there, you only had to get rid of the {}'s and put the data in the right orientation by using ; instead of a space between matrix entries to vertically concatenate instead of horizontally:
extra_63 = imu_data.txyzrxyz1(63,:);
imu_data2.txyzrxyz1 = [imu_data.txyzrxyz1(1:62,:); extra_63; imu_data.txyzrxyz1(63:end,:)]

How to add values to last column of a table based on certain conditions in MATLAB?

I have a 29736 x 6 table, which is referred to as table_fault_test_data. It has 6 columns, with names wind_direction, wind_speed, air_temperature, air_pressure, density_hubheight and Fault_Condition respectively. What I want to do is to label the data in the Fault_Condition (last table column with either a 1 or a 0 value, depending on the values in the other columns.
I would like to do the following checks (For eg.)
If wind_direction value(column_1) is below 0.0040 and above 359.9940, label 6 th column entry corresponding to the respective row of the table as a 1, else label as 0.
Do this for the entire table. Similarly, do this check for others
like air_temperature, air_pressure and so on. I know that if-else
will be used for these checks. But, I am really confused as to how I
can do this for the whole table and add the corresponding value to
the 6 th column (Maybe using a loop or something).
Any help in this
regard would be highly appreciated. Many Thanks!
EDIT:
Further clarification: I have a 29736 x 6 table named table_fault_test_data . I want to add values to the 6 th column of table based on conditions as below:-
for i = 1:29736 % Iterating over the whole table row by row
if(1st column value <x | 1st column value > y)
% Add 0 to the Corresponding element of 6 th column i.e. table_fault_test_data(i,6)
elseif (2nd column value <x | 2nd column value > y)
% Add 0 to the Corresponding element of 6 th column i.e. table_fault_test_data(i,6)
elseif ... do this for other cases as well
else
% Add 1 to the Corresponding element of 6 th column i.e. table_fault_test_data(i,6)
This is the essence of my requirements. I hope this helps in understanding the question better.
You can use logical indexing, which is supported also for tables (for loops should be avoided, if possible). For example, suppose you want to implement the first condition, and also suppose your x and y are known; also, let us assume your table is called t
logicalIndecesFirstCondition = t{:,1} < x | t{:,2} >y
and then you could refer to the rows which verify this condition using logical indexing (please refer to logical indexing
E.g.:
t{logicalIndecesFirstCondition , 6} = t{logicalIndecesFirstCondition , 6} + 1.0;
This would add 1.0 to the 6th column, for the rows for which the logical condition is true

partial Distance Based RDA - Centroids vanished from Plot

I am trying to fir a partial db-RDA with field.ID to correct for the repeated measurements character of the samples. However including Condition(field.ID) leads to Disappearance of the centroids of the main factor of interest from the plot (left plot below).
The Design: 12 fields have been sampled for species data in two consecutive years, repeatedly. Additionally every year 3 samples from reference fields have been sampled. These three fields have been changed in the second year, due to unavailability of the former fields.
Additionally some environmental variables have been sampled (Nitrogen, Soil moisture, Temperature). Every field has an identifier (field.ID).
Using field.ID as Condition seem to erroneously remove the F1 factor. However using Sampling campaign (SC) as Condition does not. Is the latter the rigth way to correct for repeated measurments in partial db-RDA??
set.seed(1234)
df.exp <- data.frame(field.ID = factor(c(1:12,13,14,15,1:12,16,17,18)),
SC = factor(rep(c(1,2), each=15)),
F1 = factor(rep(rep(c("A","B","C","D","E"),each=3),2)),
Nitrogen = rnorm(30,mean=0.16, sd=0.07),
Temp = rnorm(30,mean=13.5, sd=3.9),
Moist = rnorm(30,mean=19.4, sd=5.8))
df.rsp <- data.frame(Spec1 = rpois(30, 5),
Spec2 = rpois(30,1),
Spec3 = rpois(30,4.5),
Spec4 = rpois(30,3),
Spec5 = rpois(30,7),
Spec6 = rpois(30,7),
Spec7 = rpois(30,5))
data=cbind(df.exp, df.rsp)
dbRDA <- capscale(df.rsp ~ F1 + Nitrogen + Temp + Moist + Condition(SC), df.exp); ordiplot(dbRDA)
dbRDA <- capscale(df.rsp ~ F1 + Nitrogen + Temp + Moist + Condition(field.ID), df.exp); ordiplot(dbRDA)
You partial out variation due to ID and then you try to explain variable aliased to this ID, but it was already partialled out. The key line in the printed output was this:
Some constraints were aliased because they were collinear (redundant)
And indeed, when you ask for details, you get
> alias(dbRDA, names=TRUE)
[1] "F1B" "F1C" "F1D" "F1E"
The F1? variables were constant within ID which already was partialled out, and nothing was left to explain.

Save outputs of nested for loops in MATLAB

I have the following codes which I wish to have an output matrix Rpp of (10201,3). I run this code (which takes a bit long) then I check the matrix size of Rpp and I see (1,3), I tried so many things I couldn't find any proper way. The logic of the codes is to take the 6 values (contain 4 constant values and 2 variable values (chosen from 101 values)) and make the calculation for 3 different i1 and store every output vector of 3 in a matrix with (101*101 (pairs of those 2 variable values)) rows and 3 (for each i1) columns.
I appreciate your help
Vp1=linspace(3000,3500,101);
Vp2=3850;
rho1=2390;
rho2=2510;
Vs1=linspace(1250,1750,101);
Vs2=2000;
i1=[10 25 40];
Rpp = zeros(length(Vp1)*length(Vs1),length (i1));
for n=1:length(Vp1)*length(Vs1)
for m=1:length (i1)
for l=1:length(Vp1)
for k=1:length(Vs1)
p=sin(i1)/Vp1(l);
i2=asin(p*Vp2);
j1=asin(p*Vs1(k));
j2=asin(p*Vs2);
a=rho2*(1-2*Vs2^2*p.^2)-rho1*(1-2*Vs1(k).^2*p.^2);
b=rho2*(1-2*Vs2^2*p.^2)+2*rho1*Vs1(k)^2*p.^2;
c=rho1*(1-2*Vs1(k)^2*p.^2)+2*rho2*Vs2^2*p.^2;
d=2*(rho2*Vs2^2-rho1*Vs1(k)^2);
E=b.*cos(i1)./Vp1(l)+c.*cos(i2)/Vp2;
F=b.*cos(j1)./Vs1(k)+c.*cos(j2)/Vs2;
G=a-d*(cos(i1)/Vp1(l)).*(cos(j2)/Vs2);
H=a-d*(cos(i2)/Vp2).*(cos(j1)/Vs1(k));
D=E.*F+G.*H.*p.^2;
Rpp=((b.*(cos(i1)/Vp1(l))-c.*cos((i2)/Vp2)).*F-(a+d*((cos(i1)/Vp1(l))).*(cos(j2)/Vs2)).*H.*p.^2)./D
end
end
end
end
Try this. You 2 outer loops didn't do anything. You never used m or n so I killed those 2 loops. Also you just kept overwriting Rpp on every loop so your initialization of Rpp didn't do anything. I added an index var to assign the results to the equation to what I think is the correct part of Rpp.
Vp1=linspace(3000,3500,101);
Vp2=3850;
rho1=2390;
rho2=2510;
Vs1=linspace(1250,1750,101);
Vs2=2000;
i1=[10 25 40];
Rpp = zeros(length(Vp1)*length(Vs1),length (i1));
index = 1;
for l=1:length(Vp1)
for k=1:length(Vs1)
p=sin(i1)/Vp1(l);
i2=asin(p*Vp2);
j1=asin(p*Vs1(k));
j2=asin(p*Vs2);
a=rho2*(1-2*Vs2^2*p.^2)-rho1*(1-2*Vs1(k).^2*p.^2);
b=rho2*(1-2*Vs2^2*p.^2)+2*rho1*Vs1(k)^2*p.^2;
c=rho1*(1-2*Vs1(k)^2*p.^2)+2*rho2*Vs2^2*p.^2;
d=2*(rho2*Vs2^2-rho1*Vs1(k)^2);
E=b.*cos(i1)./Vp1(l)+c.*cos(i2)/Vp2;
F=b.*cos(j1)./Vs1(k)+c.*cos(j2)/Vs2;
G=a-d*(cos(i1)/Vp1(l)).*(cos(j2)/Vs2);
H=a-d*(cos(i2)/Vp2).*(cos(j1)/Vs1(k));
D=E.*F+G.*H.*p.^2;
Rpp(index,:)=((b.*(cos(i1)/Vp1(l))-c.*cos((i2)/Vp2)).*F-(a+d*((cos(i1)/Vp1(l))).*(cos(j2)/Vs2)).*H.*p.^2)./D;
index = index+1;
end
end
Results:
>> size(Rpp)
ans =
10201 3
The way you use the for loop is wrong. You're running the calculation for length(Vp1)*length(Vs1) * length (i1) * length(Vp1) * length(Vs1) times. Here's the correct way. I changed l into lll just so I won't confuse it with the number 1. In each iteration of the first for loop, you're running length(Vs1) times, and you need to assign the result (a 1X3 array) to the Rpp by using a row number specified by k+(lll-1)*length(Vp1).
for lll=1:length(Vp1)
for k=1:length(Vs1)
p=sin(i1)/Vp1(lll);
i2=asin(p*Vp2);
j1=asin(p*Vs1(k));
j2=asin(p*Vs2);
a=rho2*(1-2*Vs2^2*p.^2)-rho1*(1-2*Vs1(k).^2*p.^2);
b=rho2*(1-2*Vs2^2*p.^2)+2*rho1*Vs1(k)^2*p.^2;
c=rho1*(1-2*Vs1(k)^2*p.^2)+2*rho2*Vs2^2*p.^2;
d=2*(rho2*Vs2^2-rho1*Vs1(k)^2);
E=b.*cos(i1)./Vp1(lll)+c.*cos(i2)/Vp2;
F=b.*cos(j1)./Vs1(k)+c.*cos(j2)/Vs2;
G=a-d*(cos(i1)/Vp1(lll)).*(cos(j2)/Vs2);
H=a-d*(cos(i2)/Vp2).*(cos(j1)/Vs1(k));
D=E.*F+G.*H.*p.^2;
Rpp(k+(lll-1)*length(Vp1),:)=((b.*(cos(i1)/Vp1(lll))-c.*cos((i2)/Vp2)).*F-(a+d*((cos(i1)/Vp1(lll))).*(cos(j2)/Vs2)).*H.*p.^2)./D;
end
end

Matlab: Loop issue

This is quite a simple issue, but I've been struggling with it. sortedd and sortedfinal_d are 8 x 1000 Matrices and I am using the loop below to check if any of the elements in sortedfinal_d lies between two consecutive elements of sortedd, in terms of magnitude. I'm doing this along each row. overall_p is a 8 x 1000 Matrix as well, but at the end of this process I end up having final_p as a Matrix of Zeros. I don't know why this is.
for k=2:1000
for s=1:1000
for j=1:8
if sortedd(j,k) > sortedfinal_d(j,s) && sortedfinal_d(j,s) > sortedd(j,k-1)
final_p(j,s) = overall_p(j,k);
end
end
end
end
EDIT: Added data for the inputs as shown below:
sortedd (first four columns) =
0.219977361620113 0.219996752039812 0.220344444223787 0.220593274018691
0.272807483153955 0.273682693068593 0.273846498221277 0.274060049642900
0.327201460264565 0.327375792227635 0.327572790857546 0.327856448530021
0.380389118311424 0.380845274148177 0.380893687870765 0.381015090963159
0.434832574575088 0.434860658844550 0.435021604722982 0.435119929919457
0.487119089589798 0.488128501559782 0.488207451439073 0.488430455768512
0.540652551559395 0.541303305046034 0.542195194863130 0.542234381085921
0.595254195563241 0.595296064375604 0.595376090156252 0.595377962767971
sortedfinal_d =
0.182086792394190 0.182406508309366 0.182406508309366 0.182808976400818
0.233058295607543 0.233058295607543 0.233158455616954 0.233158455616954
0.286243848617693 0.286357973626582 0.286918095670684 0.287393171241241
0.336938335090164 0.336938335090164 0.337094505106945 0.337669618738100
0.390287818652551 0.390567879874952 0.390567879874952 0.390670502700602
0.446995120903824 0.447270251510681 0.447452123072880 0.447597175111267
0.501060785098551 0.501060785098551 0.501060785098551 0.501060785098551
0.551311219045087 0.551463923687602 0.551463923687602 0.551653815175502
Thanks a lot
Do you have to use loops to accomplish this?
matching_d = sortedfinal_d(:,1:end-1) < sortedd(:,2:end) ...
& sortedd(:,2:end) < sortedfinal_d(:,2:end);
final_p(matching_d) = overall_p(matching_d);
If you can show us a small sample input (say, 1x5 versions of sortedd and sortedfinal_d) and output (the corresponding matching_d) it would be easier for us to help troubleshoot.
If i set your matrices to random numbers, final_p does return some numbers.
So your code works as is. Post your dataset or at least describe the dataset in some detail, this will make it much easier to diagnose the problem.
I have reduced 1000 down to 10 and re-ordered the iteration variables to i, j, k to make it easier to follow:
sortedd = rand(8, 10);
sortedfinal_d = rand(8, 10);
overall_p = rand(8, 10);
for i=2:10
for j=1:10
for k=1:8
if sortedd(k,i) > sortedfinal_d(k,j) && sortedfinal_d(k,j) > sortedd(k,i-1)
final_p(k,j) = overall_p(k,i);
end
end
end
end
final_p