'OCaml task, Contagion, issues with syntax [closed]
This is the task:
Write a function
onstepcontagion : bool array array -> bool array array = <fun>that given a rectangular bool matrix, where true represents an infected square and false represent non-infected square it calculates the next step of infection. Infected squares remain infected indefinitely, non-infected squares become infected if the they are vertically/horizontally adjacent to at least two other infected squares
This is my code so far:
let printmat matrix =
let n = Array.length matrix in
let n1 = Array.length matrix.(0) in
for i = 0 to n - 1 do
for j = 0 to n1 - 1 do
if matrix.(i).(j) == true then print_string"1"
else print_string"0";
done;
print_string "\n";
done;;
let onstepcontagion matrix =
let n = Array.length matrix in
let n1 = Array.length matrix.(0) in
for i = 0 to n - 1 do
for j = 0 to n1 - 1 do
let tmp = 0 in
if (j < n1-2) then
let right = if matrix.(i).(j+1) = true then 1 else 0 in
if (j > 0) then
let left = if matrix.(i).(j-1) = true then 1 else 0 in
if (i < n-2) then
let up = if matrix.(i-1).(j) = true then 1 else 0 in
if (i > 0) then
let down = if matrix.(i+1).(j) = true then 1 else 0 in
let sum = right + left + up + down in
if sum > 1 then print_string "JTB "
else print_string "0"
done;
done;;
I have no errors, but no output when I call the function. I am very confused regarding the syntax and function of OCaml, I am a total beginner and still in learning phase. I wrote my task in C, I was trying to implement a similar solution in ocaml.
C code:
#include <stdio.h>
#include <stdlib.h>
void print_mat (int n, int m, int arr[n][m])
{
int i,j;
for (i = 0; i < n; i++){
for (j = 0; j < m; j++)
printf("%d ",arr[i][j]);
printf("\n");
}
printf("\n\n");
}
int main()
{
int n, m, i, j, tmp, changes = 1;
printf("input Mat len\n");
scanf("%d%d",&n,&m);
int arr[n][m];
int cpy[n][m];
for (i = 0; i < n; i++)
for (j = 0; j < m; j++){
scanf("%d",&tmp);
if (tmp == 0)
arr[i][j] = tmp;
else
arr[i][j] = 1;
}
while (changes){
changes = 0;
for (i = 0; i < n; i++){
for (j = 0; j < m; j++)
{
tmp = 0;
if (arr[i][j] != 1){
if (j < m-1)
if (arr[i][j+1] == 1)
tmp++;
if (j > 0)
if (arr[i][j-1] == 1)
tmp++;
if (i < n-1)
if (arr[i+1][j] == 1)
tmp++;
if (i > 0)
if (arr[i-1][j] == 1)
tmp++;
if (tmp > 1){
cpy[i][j] = 1;
changes = 1;
}
}
}
}
if (changes == 1){
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
if (arr[i][j] == 1 || cpy[i][j] == 1)
arr[i][j] = 1;
printf("\n");
print_mat(n,m, arr);
}
}
return 0;
}
//010 100 001 000
I would appreciate if someone could give me a hand here. I learn best trough examples, and I am unable to find similar solved tasks to learn from.
Solution 1:[1]
Your printmat function works for me:
# printmat [|[|true;false|];[|false;true|]|];;
10
01
- : unit = ()
In your onstepcontagion the indentation isn't accurate; i.e., it doesn't show the nested structure of the if tests.
If I run onstepcontagion on a 4x4 matrix of all false, I see an indexing error:
# onstepcontagion (Array.init 4 (fun _ -> Array.make 4 false));;
Exception: Invalid_argument "index out of bounds".
On this line:
let up = if matrix.(i-1).(j) = true then 1 else 0 in
You haven't yet verified that i > 0, so it will fail when i = 0.
(However, I'm not sure the code is actually doing what you wanted, because the indentation is incorrect.)
You should show your call to onstepcontagion so SO commenters can try the same test as you. If your matrix is too small, the function indeed does nothing much (as at least one of the ifs will be false).
Solution 2:[2]
To augment Jeffrey's answer, your onstepcontagion function formatted better to reflect the nesting of the conditions and with extraneous parentheses removed.
let onstepcontagion matrix =
let n = Array.length matrix in
let n1 = Array.length matrix.(0) in
for i = 0 to n - 1 do
for j = 0 to n1 - 1 do
let tmp = 0 in
if j < n - 2 then
let right = if matrix.(i).(j + 1) = true then 1 else 0 in
if j > 0 then
let left = if matrix.(i).(j - 1) = true then 1 else 0 in
if i < n - 2 then
let up = if matrix.(i - 1).(j) = true then 1 else 0 in
if i > 0 then
let down = if matrix.(i + 1).(j) = true then 1 else 0 in
let sum = right + left + up + down in
if sum > 1 then print_string "JTB "
else print_string "0"
done;
done
Since nothing happens unless all of these conditions are true, you might streamline this with something like the following. Note that tmp appears to serve no purpose, as has thus been elided.
let onstepcontagion matrix =
let n = Array.length matrix in
let n1 = Array.length matrix.(0) in
for i = 0 to n - 1 do
for j = 0 to n1 - 1 do
if j < n - 2 && j > 0 && i < n - 2 && i > 0 then
let right = if matrix.(i).(j + 1) then 1 else 0 in
let left = if matrix.(i).(j - 1) then 1 else 0 in
let up = if matrix.(i - 1).(j) then 1 else 0 in
let down = if matrix.(i + 1).(j) then 1 else 0 in
let sum = right + left + up + down in
if sum > 1 then
print_string "JTB "
else
print_string "0"
done;
done
We could also introduce a int_of_bool function.
let onstepcontagion matrix =
let int_of_bool = function true -> 1 | _ -> 0 in
let n = Array.length matrix in
let n1 = Array.length matrix.(0) in
for i = 0 to n - 1 do
for j = 0 to n1 - 1 do
if j < n - 2 && j > 0 && i < n - 2 && i > 0 then
let right = int_of_bool matrix.(i).(j + 1) in
let left = int_of_bool matrix.(i).(j - 1) in
let up = int_of_bool matrix.(i - 1).(j) in
let down = int_of_bool matrix.(i + 1).(j) in
let sum = right + left + up + down in
if sum > 1 then
print_string "JTB "
else
print_string "0"
done;
done
Thank you for clarifying your purpose in comments. As I understand it now, you are checking to see if any two horizontal or vertical neighbors are true.
As written, your code checks to ensure that matrix elements have four vertical/horizontal neighbors. This rules out corner and edge elements. The sample data you've shown is a 2x2 matrix. No part of that matrix has more than two neighbors, so the condition is never true.
You have demonstrated imperative thinking in how you've constructed your code (and in how you've indented this). Each if does not define a variable and then move onto the next. There are no if statements in OCaml but rather if expressions.
if a then ... else ...
The else can be elided only if the return value of the expression is unit.
Your set of conditional expressions has formed one big expression. If the first condition is not true, the whole thing is not evaluated.
So the real question becomes, how do we handle a matrix "cell" not having a particular neighbor? Well, what happens if we try to access an array element out of bounds?
utop # let arr = [| 1; 2; 3; 4 |] in arr.(4);;
Exception: Invalid_argument "index out of bounds".
We get an exception. But we can handle exceptions.
An out of bounds exception in this case would be equivalent to finding 0 in that "cell", so we can handle each access by returning 0 if such an exception occurs.
We also now don't need to do any explicit bounds-checking and every "cell" gets evaluated.
let onstepcontagion matrix =
let int_of_bool = function true -> 1 | _ -> 0 in
let n = Array.length matrix in
let n1 = Array.length matrix.(0) in
for i = 0 to n - 1 do
for j = 0 to n1 - 1 do
let right = try int_of_bool matrix.(i).(j + 1) with Invalid_argument _ -> 0 in
let left = try int_of_bool matrix.(i).(j - 1) with Invalid_argument _ -> 0 in
let up = try int_of_bool matrix.(i - 1).(j) with Invalid_argument _ -> 0 in
let down = try int_of_bool matrix.(i + 1).(j) with Invalid_argument _ -> 0 in
let sum = right + left + up + down in
if sum > 1 then
print_string "JTB "
else
print_string "0"
done;
done
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
