I am working on a promela model that is fairly simple. Using two different modules, it acts as a crosswalk/Traffic light. The first module is the traffic light that outputs the current signal (green, red, yellow, pending). This module also receives as an input a signal called "pedestrian" which acts as an indicator that there are pedestrians wanting to cross. The second module acts as the crosswalk. It receives output signals from the traffic light module (green, yellow, green). It outputs the pedestrian signal to the traffic light module. This module simply defines whether the pedestrian(s) is crossing, waiting or not present. My issue is that once the count value goes to 60, a timeout occurs. I believe the statement "SigG_out ! 1" is causing the error but I do not know why. I have attached the image of the trace I receive from the command line. I am completely new to Spin and Promela and so I am not sure how to use the information form the trace to find my issue in the code. Any help is greatly appreciated.
Here is the code for the complete model:
mtype = {red, green, yellow, pending, none, crossing, waiting};
mtype traffic_mode;
mtype crosswalk_mode;
int count;
chan pedestrian_chan = [0] of {byte};
chan sigR_chan = [0] of {byte};
chan sigG_chan = [0] of {byte};
chan sigY_chan = [0] of {byte};
ltl l1 {!<> (pedestrian_chan[0] == 1) && (traffic_mode == green || traffic_mode == yellow || traffic_mode == pending)}
ltl l2 {[]<> (pedestrian_chan[0] == 1) -> crosswalk_mode == crossing }
proctype traffic_controller(chan pedestrian_in, sigR_out, sigG_out, sigY_out)
{
do
::if
::(traffic_mode == red) ->
count = count + 1;
if
::(count >= 60) ->
sigG_out ! 1;
count = 0;
traffic_mode = green;
:: else -> skip;
fi
::(traffic_mode == green) ->
if
::(count < 60) ->
count = count + 1;
::(pedestrian_in == 1 & count < 60) ->
count = count + 1;
traffic_mode = pending;
::(pedestrian_in == 1 & count >= 60)
count = 0;
traffic_mode = yellow;
fi
::(traffic_mode == pending) ->
count = count + 1;
if
::(count >= 60) ->
sigY_out ! 1;
count = 0;
traffic_mode = yellow;
::else -> skip;
fi
::(traffic_mode == yellow) ->
count = count + 1;
if
::(count >= 5) ->
sigR_out ! 1;
count = 0;
traffic_mode = red;
:: else -> skip;
fi
fi
od
}
proctype crosswalk(chan sigR_in, sigG_in, sigY_in, pedestrian_out)
{
do
::if
::(crosswalk_mode == crossing) ->
if
::(sigG_in == 1) -> crosswalk_mode = none;
fi
::(crosswalk_mode == none) ->
if
:: (1 == 1) -> crosswalk_mode = none
:: (1 == 1) ->
pedestrian_out ! 1
crosswalk_mode = waiting
fi
::(crosswalk_mode == waiting) ->
if
::(sigR_in == 1) -> crosswalk_mode = crossing;
fi
fi
od
}
init
{
count = 0;
traffic_mode = red;
crosswalk_mode = crossing;
atomic
{
run traffic_controller(pedestrian_chan, sigR_chan, sigG_chan, sigY_chan);
run crosswalk(sigR_chan, sigG_chan, sigY_chan, pedestrian_chan);
}
}
You are using channels incorrectly, this line in particular I wouldn't even know how to interpret it:
:: (sigG_in == 1) ->
Your channels are synchronous, which means that whenever a process sends something on one side, another process must listen on the other end of the channel in order to deliver the message. Otherwise, the process blocks until when the situation changes. Your channels are synchronous because you declared them of size 0.
To read from a channel, you need to use the proper syntax:
int some_var;
...
some_channel?some_var;
// here some_var contains value received through some_channel
It seems to be a bit pointless to use three different channels to send different signals. What about using three different values?
mtype = { RED, GREEN, YELLOW };
chan c = [0] of { mtype };
...
c!RED
...
// (some other process)
...
mtype var;
c?var;
// here var contains RED
...
Related
Ok, so I'm trying to model a CLH-RW lock in Promela.
The way the lock works is simple, really:
The queue consists of a tail, to which both readers and writers enqueue a node containing a single bool succ_must_wait they do so by creating a new node and CAS-ing it with the tail.
The tail thereby becomes the node's predecessor, pred.
Then they spin-wait on pred.succ_must_wait until it is false.
Readers first increment a reader counter ncritR and then set their own flag to false, allowing multiple readers at in the critical section at the same time. Releasing a readlock simply means decrementing ncritR again.
Writers wait until ncritR reaches zero, then enter the critical section. They do not set their flag to false until the lock is released.
I'm kind of struggling to model this in promela, though.
My current attempt (see below) tries to make use of arrays, where each node basically consists of a number of array entries.
This fails because let's say A enqueues itself, then B enqueues itself. Then the queue will look like this:
S <- A <- B
Where S is a sentinel node.
The problem now is, that when A runs to completeness and re-enqueues, the queue will look like
S <- A <- B <- A'
In actual execution, this is absolutely fine because A and A' are distinct node objects. And since A.succ_must_wait will have been set to false when A first released the lock, B will eventually make progress, and therefore A' will eventually make progress.
What happens in the array-based promela model below, though, is that A and A' occupy the same array positions, causing B to miss the fact that A has released the lock, thereby creating a deadlock where B is (wrongly) waiting for A' instead of A and A' is waiting (correctly) for B.
A possible "solution" to this could be to have A wait until B acknowledges the release. But that would not be true to how the lock works.
Another "solution" would be to wait for a CHANGE in pred.succ_must_wait, where a release would increment succ_must_wait, rather than reset it to 0.
But I'm intending to model a version of the lock, where pred may change (i.e. where a node may be allowed to disregard some of its predecessors), and I'm not entirely convinced something like the increasing version wouldn't cause an issue with this change.
So what's the "smartest" way to model an implicit queue like this in promela?
/* CLH-RW Lock */
/*pid: 0 = init, 1-2 = reader, 3-4 = writer*/
ltl liveness{
([]<> reader[1]#progress_reader)
&& ([]<> reader[2]#progress_reader)
&& ([]<> writer[3]#progress_writer)
&& ([]<> writer[4]#progress_writer)
}
bool initialised = 0;
byte ncritR;
byte ncritW;
byte tail;
bool succ_must_wait[5]
byte pred[5]
init{
assert(_pid == 0);
ncritR = 0;
ncritW = 0;
/*sentinel node*/
tail =0;
pred[0] = 0;
succ_must_wait[0] = 0;
initialised = 1;
}
active [2] proctype reader()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else ->
succ_must_wait[_pid] = 1;
atomic {
pred[_pid] = tail;
tail = _pid;
}
(succ_must_wait[pred[_pid]] == 0)
ncritR++;
succ_must_wait[_pid] = 0;
atomic {
/*freeing previous node for garbage collection*/
pred[_pid] = 0;
}
/*CRITICAL SECTION*/
progress_reader:
assert(ncritR >= 1);
assert(ncritW == 0);
ncritR--;
atomic {
/*necessary to model the fact that the next access creates a new queue node*/
if
:: tail == _pid -> tail = 0;
:: else ->
fi
}
od
}
active [2] proctype writer()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else ->
succ_must_wait[_pid] = 1;
atomic {
pred[_pid] = tail;
tail = _pid;
}
(succ_must_wait[pred[_pid]] == 0)
(ncritR == 0)
atomic {
/*freeing previous node for garbage collection*/
pred[_pid] = 0;
}
ncritW++;
/* CRITICAL SECTION */
progress_writer:
assert(ncritR == 0);
assert(ncritW == 1);
ncritW--;
succ_must_wait[_pid] = 0;
atomic {
/*necessary to model the fact that the next access creates a new queue node*/
if
:: tail == _pid -> tail = 0;
:: else ->
fi
}
od
}
First of all, a few notes:
You don't need to initialize your variables to 0, since:
The default initial value of all variables is zero.
see the docs.
You don't need to enclose a single instruction inside an atomic {} statement, since any elementary statement is executed atomically. For better efficiency of the verification process, whenever possible, you should use d_step {} instead. Here you can find a related stackoverflow Q/A on the topic.
init {} is guaranteed to have _pid == 0 when one of the two following conditions holds:
no active proctype is declared
init {} is declared before any other active proctype appearing in the source code
Active Processes, includig init {}, are spawned in order of appearance inside the source code. All other processes are spawned in order of appearance of the corresponding run ... statement.
I identified the following issues on your model:
the instruction pred[_pid] = 0 is useless because that memory location is only read after the assignment pred[_pid] = tail
When you release the successor of a node, you set succ_must_wait[_pid] to 0 only and you don't invalidate the node instance onto which your successor is waiting for. This is the problem that you identified in your question, but was unable to solve. The solution I propose is to add the following code:
pid j;
for (j: 1..4) {
if
:: pred[j] == _pid -> pred[j] = 0;
:: else -> skip;
fi
}
This should be enclosed in an atomic {} block.
You correctly set tail back to 0 when you find that the node that has just left the critical section is also the last node in the queue. You also correctly enclose this operation in an atomic {} block. However, it may happen that --when you are about to enter this atomic {} block-- some other process --who was still waiting in some idle state-- decides to execute the initial atomic block and copies the current value of tail --which corresponds to the node that has just expired-- into his own pred[_pid] memory location. If now the node that has just exited the critical section attempts to join it once again, setting his own value of succ_must_wait[_pid] to 1, you will get another instance of circular wait among processes. The correct approach is to merge this part with the code releasing the successor.
The following inline function can be used to release the successor of a given node:
inline release_succ(i)
{
d_step {
pid j;
for (j: 1..4) {
if
:: pred[j] == i ->
pred[j] = 0;
:: else ->
skip;
fi
}
succ_must_wait[i] = 0;
if
:: tail == _pid -> tail = 0;
:: else -> skip;
fi
}
}
The complete model, follows:
byte ncritR;
byte ncritW;
byte tail;
bool succ_must_wait[5];
byte pred[5];
init
{
skip
}
inline release_succ(i)
{
d_step {
pid j;
for (j: 1..4) {
if
:: pred[j] == i ->
pred[j] = 0;
:: else ->
skip;
fi
}
succ_must_wait[i] = 0;
if
:: tail == _pid -> tail = 0;
:: else -> skip;
fi
}
}
active [2] proctype reader()
{
loop:
succ_must_wait[_pid] = 1;
d_step {
pred[_pid] = tail;
tail = _pid;
}
trying:
(succ_must_wait[pred[_pid]] == 0)
ncritR++;
release_succ(_pid);
// critical section
progress_reader:
assert(ncritR > 0);
assert(ncritW == 0);
ncritR--;
goto loop;
}
active [2] proctype writer()
{
loop:
succ_must_wait[_pid] = 1;
d_step {
pred[_pid] = tail;
tail = _pid;
}
trying:
(succ_must_wait[pred[_pid]] == 0) && (ncritR == 0)
ncritW++;
// critical section
progress_writer:
assert(ncritR == 0);
assert(ncritW == 1);
ncritW--;
release_succ(_pid);
goto loop;
}
I added the following properties to the model:
p0: the writer with _pid equal to 4 goes through its progress state infinitely often, provided that it is given the chance to execute some instruction infinitely often:
ltl p0 {
([]<> (_last == 4)) ->
([]<> writer[4]#progress_writer)
};
This property should be true.
p1: there is never more than one reader in the critical section:
ltl p1 {
([] (ncritR <= 1))
};
Obviously, we expect this property to be false in a model that matches your specification.
p2: there is never more than one writer in the critical section:
ltl p2 {
([] (ncritW <= 1))
};
This property should be true.
p3: there isn't any node that is the predecessor of two other nodes at the same time, unless such node is node 0:
ltl p3 {
[] (
(((pred[1] != 0) && (pred[2] != 0)) -> (pred[1] != pred[2])) &&
(((pred[1] != 0) && (pred[3] != 0)) -> (pred[1] != pred[3])) &&
(((pred[1] != 0) && (pred[4] != 0)) -> (pred[1] != pred[4])) &&
(((pred[2] != 0) && (pred[3] != 0)) -> (pred[2] != pred[3])) &&
(((pred[2] != 0) && (pred[4] != 0)) -> (pred[2] != pred[4])) &&
(((pred[3] != 0) && (pred[4] != 0)) -> (pred[3] != pred[4]))
)
};
This property should be true.
p4: it is always true that whenever writer with _pid equal to 4 tries to access the critical section then it will eventually get there:
ltl p4 {
[] (writer[4]#trying -> <> writer[4]#progress_writer)
};
This property should be true.
The outcome of the verification matches our expectations:
~$ spin -search -ltl p0 -a clhrw_lock.pml
...
Full statespace search for:
never claim + (p0)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 68 byte, depth reached 3305, errors: 0
...
~$ spin -search -ltl p1 -a clhrw_lock.pml
...
Full statespace search for:
never claim + (p1)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 68 byte, depth reached 1692, errors: 1
...
~$ spin -search -ltl p2 -a clhrw_lock.pml
...
Full statespace search for:
never claim + (p2)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 68 byte, depth reached 3115, errors: 0
...
~$ spin -search -ltl p3 -a clhrw_lock.pml
...
Full statespace search for:
never claim + (p3)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 68 byte, depth reached 3115, errors: 0
...
~$ spin -search -ltl p4 -a clhrw_lock.pml
...
Full statespace search for:
never claim + (p4)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 68 byte, depth reached 3115, errors: 0
...
I have the following program that models a FIFO with a process in PROMELA:
mtype = { PUSH, POP, IS_EMPTY, IS_FULL };
#define PRODUCER_UID 0
#define CONSUMER_UID 1
proctype fifo(chan inputs, outputs)
{
mtype command;
int data, tmp, src_uid;
bool data_valid = false;
do
:: true ->
inputs?command(tmp, src_uid);
if
:: command == PUSH ->
if
:: data_valid ->
outputs!IS_FULL(true, src_uid);
:: else ->
data = tmp
data_valid = true;
outputs!PUSH(data, src_uid);
fi
:: command == POP ->
if
:: !data_valid ->
outputs!IS_EMPTY(true, src_uid);
:: else ->
outputs!POP(data, src_uid);
data = -1;
data_valid = false;
fi
:: command == IS_EMPTY ->
outputs!IS_EMPTY(!data_valid, src_uid);
:: command == IS_FULL ->
outputs!IS_FULL(data_valid, src_uid);
fi;
od;
}
proctype producer(chan inputs, outputs)
{
mtype command;
int v;
do
:: true ->
atomic {
inputs!IS_FULL(false, PRODUCER_UID) ->
outputs?IS_FULL(v, PRODUCER_UID);
}
if
:: v == 1 ->
skip
:: else ->
select(v: 0..16);
printf("P[%d] - produced: %d\n", _pid, v);
access_fifo:
atomic {
inputs!PUSH(v, PRODUCER_UID);
outputs?command(v, PRODUCER_UID);
}
assert(command == PUSH);
fi;
od;
}
proctype consumer(chan inputs, outputs)
{
mtype command;
int v;
do
:: true ->
atomic {
inputs!IS_EMPTY(false, CONSUMER_UID) ->
outputs?IS_EMPTY(v, CONSUMER_UID);
}
if
:: v == 1 ->
skip
:: else ->
access_fifo:
atomic {
inputs!POP(v, CONSUMER_UID);
outputs?command(v, CONSUMER_UID);
}
assert(command == POP);
printf("P[%d] - consumed: %d\n", _pid, v);
fi;
od;
}
init {
chan inputs = [0] of { mtype, int, int };
chan outputs = [0] of { mtype, int, int };
run fifo(inputs, outputs); // pid: 1
run producer(inputs, outputs); // pid: 2
run consumer(inputs, outputs); // pid: 3
}
I want to add wr_ptr and rd_ptr in the program to indicate write and read pointers relative to the depth of FIFO when a PUSH update is performed:
wr_ptr = wr_ptr % depth;
empty=0;
if
:: (rd_ptr == wr_ptr) -> full=true;
fi
and similar chances on POP updates
Could you please help me to add this to this program?
or should i make it an ltl property and use that to check it?
from comments: and i want to verify this property, for example If the fifo is full, one should not have a write request, that is the right syntax?full means that fifo is full and wr_idx is the write pointer, I do not know how to access the full, empty, wr_idx, rd_idx, depth on the fifo process in the properties ltl fifo_no_write_when_full {[] (full -> ! wr_idx)}
Here is an example of the process-based FIFO with size 1 that I gave you here adapted for an arbitrary size, which can be configured with FIFO_SIZE. For verification purposes, I would keep this value as small as possible (e.g. 3), because otherwise you are just widening the state space without including any more significant behaviour.
mtype = { PUSH, POP, IS_EMPTY, IS_FULL };
#define PRODUCER_UID 0
#define CONSUMER_UID 1
#define FIFO_SIZE 10
proctype fifo(chan inputs, outputs)
{
mtype command;
int tmp, src_uid;
int data[FIFO_SIZE];
byte head = 0;
byte count = 0;
bool res;
do
:: true ->
inputs?command(tmp, src_uid);
if
:: command == PUSH ->
if
:: count >= FIFO_SIZE ->
outputs!IS_FULL(true, src_uid);
:: else ->
data[(head + count) % FIFO_SIZE] = tmp;
count = count + 1;
outputs!PUSH(data[(head + count - 1) % FIFO_SIZE], src_uid);
fi
:: command == POP ->
if
:: count <= 0 ->
outputs!IS_EMPTY(true, src_uid);
:: else ->
outputs!POP(data[head], src_uid);
atomic {
head = (head + 1) % FIFO_SIZE;
count = count - 1;
}
fi
:: command == IS_EMPTY ->
res = count <= 0;
outputs!IS_EMPTY(res, src_uid);
:: command == IS_FULL ->
res = count >= FIFO_SIZE;
outputs!IS_FULL(res, src_uid);
fi;
od;
}
No change to producer, consumer or init was necessary:
proctype producer(chan inputs, outputs)
{
mtype command;
int v;
do
:: true ->
atomic {
inputs!IS_FULL(false, PRODUCER_UID) ->
outputs?IS_FULL(v, PRODUCER_UID);
}
if
:: v == 1 ->
skip
:: else ->
select(v: 0..16);
printf("P[%d] - produced: %d\n", _pid, v);
access_fifo:
atomic {
inputs!PUSH(v, PRODUCER_UID);
outputs?command(v, PRODUCER_UID);
}
assert(command == PUSH);
fi;
od;
}
proctype consumer(chan inputs, outputs)
{
mtype command;
int v;
do
:: true ->
atomic {
inputs!IS_EMPTY(false, CONSUMER_UID) ->
outputs?IS_EMPTY(v, CONSUMER_UID);
}
if
:: v == 1 ->
skip
:: else ->
access_fifo:
atomic {
inputs!POP(v, CONSUMER_UID);
outputs?command(v, CONSUMER_UID);
}
assert(command == POP);
printf("P[%d] - consumed: %d\n", _pid, v);
fi;
od;
}
init {
chan inputs = [0] of { mtype, int, int };
chan outputs = [0] of { mtype, int, int };
run fifo(inputs, outputs); // pid: 1
run producer(inputs, outputs); // pid: 2
run consumer(inputs, outputs); // pid: 3
}
Now you should have enough material to work on and be ready to write your own properties. On this regard, in your question you write:
I do not know how to access the full, empty, wr_idx, rd_idx, depth on the fifo process in the properties ltl fifo_no_write_when_full {[] (full -> ! wr_idx)}
First of all, please note that in my code rd_idx corresponds to head, depth (should) correspond to count and that I did not use an explicit wr_idx because the latter can be derived from the former two: it is given by (head + count) % FIFO_SIZE. This is not just a choice of code cleanliness, because having fewer variables in a Promela model actually helps with memory consumption and running time of the verification process.
Of course, if you really want to have wr_idx in your model you are free to add it yourself. (:
Second, if you look at the Promela manual for ltl properties, you find that:
The names or symbols must be defined to represent boolean expressions on global variables from the model.
So in other words, it's not possible to put local variables inside an ltl expression. If you want to use them, then you should take them out from the process's local space and put them in the global space.
So, to check fifo_no_write_when_full* you could:
move the declaration of count out in the global space
add a label fifo_write: here:
:: command == PUSH ->
if
:: count >= FIFO_SIZE ->
outputs!IS_FULL(true, src_uid);
:: else ->
fifo_write:
data[(head + count) % FIFO_SIZE] = tmp;
count = count + 1;
outputs!PUSH(data[(head + count - 1) % FIFO_SIZE], src_uid);
fi
check the property:
ltl fifo_no_write_when_full { [] ( (count >= FIFO_SIZE) -> ! fifo#fifo_write) }
Third, before any attempt to verify any of your properties with the usual commands, e.g.
~$ spin -a fifo.pml
~$ gcc -o fifo pan.c
~$ ./fifo -a -N fifo_no_write_when_full
you should modify producer and consumer so that neither of them executes for an indefinite amount of time and therefore keep the search space at a small depth. Otherwise you are likely to get an error of the sort
error: max search depth too small
and have the verification exhaust all of your hardware resources without reaching any sensible conclusion.
*: actually the name fifo_no_write_when_full is quite generic and might have multiple interpretations, e.g.
the fifo does not perform a push when it is full
the producer is not able to push if the fifo is full
In the example I provided I chose to adopt the first interpretation of the property.
The Data:
A list of integers increasing in order (0,1,2,3,4,5.......)
A list of values that belong to those integers. As an example, 0 = 33, 1 = 45, 2 = 21, ....etc.
And an incrementing variable x which represent a minimum jump value.
x is the value of each jump. For example if x = 2, if 1 is chosen you cannot choose 2.
I need to determine the best way to choose integers, given some (x), that produce the highest total value from the value list.
EXAMPLE:
A = a set of 1 foot intervals (0,1,2,3,4,5,6,7,8,9)
B = the amount of money at each interval (9,5,7,3,2,7,8,10,21,12)
Distance = the minimum distance you can cover
- i.e. if the minimum distance is 3, you must skip 2 feet and leave the money, then you can
pick up the amount at the 3rd interval.
if you pick up at 0, the next one you can pick up is 3, if you choose 3 you can
next pick up 6 (after skipping 4 and 5). BUT, you dont have to pick up 6, you
could pick up 7 if it is worth more. You just can't pick up early.
So, how can I programmatically make the best jumps and end with the most money at the end?
So I am using the below equation for computing the opt value in the dynamic programming:
Here d is distance.
if (i -d) >= 0
opt(i) = max (opt(i-1), B[i] + OPT(i-d));
else
opt(i) = max (opt(i-1), B[i]);
Psuedo-code for computing the OPT value:
int A[] = {integers list}; // This is redundant if the integers are consecutive and are always from 0..n.
int B[] = {values list};
int i = 0;
int d = distance; // minimum distance between two picks.
int numIntegers = sizeof(A)/sizeof(int);
int opt[numIntegers];
opt[0] = B[0]; // For the first one Optimal value is picking itself.
for (i=1; i < numIntegers; i++) {
if ((i-d) < 0) {
opt[i] = max (opt[i-1], B[i]);
} else {
opt[i] = max (opt[i-1], B[i] + opt[i-d]);
}
}
EDIT based on OP's requirement about getting the selected integers from B:
for (i=numIntegres - 1; i >= 0;) {
if ((i == 0) && (opt[i] > 0)) {
printf ("%d ", i);
break;
}
if (opt[i] > opt[i-1]) {
printf ("%d ", i);
i = i -d;
} else {
i = i - 1;
}
}
If A[] does not have consecutive integers from 0 to n.
int A[] = {integers list}; // Here the integers may not be consecutive
int B[] = {values list};
int i = 0, j = 0;
int d = distance; // minimum distance between two picks.
int numAs = sizeof(A)/sizeof(int);
int numIntegers = A[numAs-1]
int opt[numIntegers];
opt[0] = 0;
if (A[0] == 0) {
opt[0] = B[0]; // For the first one Optimal value is picking itself.
j = 1;
}
for (i=1; i < numIntegers && j < numAs; i++, j++) {
if (i < A[j]) {
while (i < A[j]) {
opt[i] = opt[i -1];
i = i + 1:
}
}
if ((i-d) < 0) {
opt[i] = max (opt[i-1], B[j]);
} else {
opt[i] = max (opt[i-1], B[j] + opt[i-d]);
}
}
I'm struggling with implementing a robust ray sphere intersection routine in 2d. I hacked a rather hudge function together which I'm unable to properly debug since it runs on the GPU. I got my inspiration from:
Circle line-segment collision detection algorithm?
and http://paulbourke.net/geometry/sphereline/. I have no idea where I should look for the error. Am I missing something obvious? The case where I check if the circle encloses the line is returned as a intersection since I'm interested in actual circle segment collision.
Here's the relevant code snippet:
bool CircleSegmentIntersection2d(float2 x0, float2 x1, float2 center, float r) {
float2 d = x1-x0;
float2 f = x0-center;
float a = dot2d(d,d);
float b = 2*dot2d(f,d);
float c = dot2d(f,f)-r*r;
float discriminant = b*b-4*a*c;
if( discriminant < 0 ) {
// no intersection
return false;
} else {
discriminant = sqrt(discriminant);
// either solution may be on or off the ray so need to test both
float sol1 = (-b + discriminant)/(2*a);
float sol2 = (-b - discriminant)/(2*a);
float t0 = min(sol1, sol2);
float t1 = max(sol1, sol2);
if (t1 < 0)
return false;
// Line segment doesn't intersect and on outside of sphere, in which case both values of t will either be less than 0 or greater than 1.
if (0 < t0 && 0 < t1 || t0 > 1 && t1 > 1)
return false;
// Line segment doesn't intersect and is inside sphere, in which case one value of t will be negative and the other greater than 1.
if (t0 < 0 && t1 > 1) {
return true;
}
// Line segment intersects at one point, in which case one value of t will be between 0 and 1 and the other not.
if (t0 < 0 && 0 <= t1 && t1 <= 1) {
return true;
}
// Line segment intersects at two points, in which case both values of t will be between 0 and 1.
if (0 <= t1 && t1 <= 1 && 0 <= t0 && t0 <= 1) {
return true;
}
// Line segment is tangential to the sphere, in which case both values of t will be the same and between 0 and 1.
if (length(t0-t1) < 0.005f) {
return true;
}
}
return false;
}
where dot2d is defined by:
float dot2d(float2 a, float2 b) {
return a.x*b.x+a.y*b.y;
}
Thanks for your time!
I'm writing a Conway's life game for school. In the program I am having trouble with the arrays taking the values I am assigning them. At one point in the program they print out the value assigned to them (1) yet at the end of the program when I need to print the array to show the iterations of the game it shows an incredibly low number. The other trouble was I was encountering difficulties when putting in a loop that would ask if it wants you to run another iteration. So I removed it until the previous errors were fixed.
Im writing this with C++
#include <stdio.h>
int main (void)
{
int currentarray [12][12];
int futurearray [12][12];
char c;
char check = 'y';
int neighbors = 0;
int x = 0; // row
int y = 0; //column
printf("Birth an organism will be born in each empty location that has exactly three neighbors.\n");
printf("Death an organism with four or more organisms as neighbors will die from overcrowding.\n");
printf("An organism with fewer than two neighbors will die from loneliness.\n");
printf("Survival an organism with two or three neighbors will survive to the next generation.\n");
printf( "To create life input x, y coordinates.\n");
while ( check == 'y' )
{
printf("Enter x coordinate.\n");
scanf("%d", &x ); while((c = getchar()) != '\n' && c != EOF);
printf("Enter y coordinate.\n");
scanf("%d", &y ); while((c = getchar()) != '\n' && c != EOF);
currentarray [x][y] = 1;
printf ("%d\n", currentarray[x][y]);
printf( "Do you wish to enter more input? y/n.\n");
scanf("%c", &check); while((c = getchar()) != '\n' && c != EOF);
}
// Note - Need to add a printf statement showing the array before changes are made after input added.
// check for neighbors
while(check == 'y')
{
for(y = 0; y <= 12; y++)
{
for(x = 0; x <= 12; x++)
{
//Begin counting number of neighbors:
if(currentarray[x-1][y-1] == 1) neighbors += 1;
if(currentarray[x-1][y] == 1) neighbors += 1;
if(currentarray[x-1][y+1] == 1) neighbors += 1;
if(currentarray[x][y-1] == 1) neighbors += 1;
if(currentarray[x][y+1] == 1) neighbors += 1;
if(currentarray[x+1][y-1] == 1) neighbors += 1;
if(currentarray[x+1][y] == 1) neighbors += 1;
if(currentarray[x+1][y+1] == 1) neighbors += 1;
//Apply rules to the cell:
if(currentarray[x][y] == 1 && neighbors < 2)
futurearray[x][y] = 0;
else if(currentarray[x][y] == 1 && neighbors > 3)
futurearray[x][y] = 0;
else if(currentarray[x][y] == 1 && (neighbors == 2 || neighbors == 3))
futurearray[x][y] = 1;
else if(currentarray[x][y] == 0 && neighbors == 3)
futurearray[x][y] = 1;
}
}
}
// Set the current array to the future and change the future to 0
{
for(y = 0; y < 12; y++)
{
for(x = 0; x < 12; x++)
{
//Begin the process
currentarray [x][y] = futurearray [x][y];
futurearray [x][y] = 0;
}
}
}
{
for(y = 0; y < 12; y++)
{
for(x = 0; x < 12; x++)
{
//print the current life board
printf("%d ", currentarray[x][y]);
}
}
}
// Have gone through one iteration of Life
//Ask to do another iteration
printf("Do you wish to continue y/n?\n");
scanf("%c", &check); while((c = getchar()) != '\n' && c != EOF);
return 0;
}
You are defining your arrays as [12][12].
In your generation loop you walk from i = 0 to i <= 12, which is 13 steps instead of the 12 of the array. Additionally you are trying to access x-1 and y-1, which can be as low as -1. Again not inside your array.
Sometimes you get semi-useful values from within your array, but on some borders you are just accessing random data.
Try to correct your border.
You forgot to set neighbors to 0 before counting them.
Since this is C++ (not C), you might as well declare neighbors inside the loop body. Makes these kinds of issues easier to spot, too.
Also, is it me, or is that while loop never going to finish? Your braces are a mess, in general, as is your indentation. You could do yourself and us a favour by cleaning those up.
Obviously agree with all the above suggestions. One nice trick you might want to implement with Life is to create an extra border around your area. So if the user wants a 12x12 grid (and you should allow width/height to be specified and allocate memory dynamically) internally you hold a 14x14 grid corresponding to a border around the actual grid. Before running the calculation copy the top row to the bottom border, bottom row to the top border etc. Now you can run the main algorithm on the inner 12x12 grid without worrying about edge cases. This will enable your patterns to re-appear on the other side if they fall off the edge.
You're also forgetting to set the values of both arrays to zero. This will take care of the ridiculous number issue you're having. you can do that by copying this for loop:
for(y = 0; y < 12; y++)
{
for(x = 0; x < 12; x++)
{
//Begin the process
currentarray [x][y] = futurearray [x][y];
futurearray [x][y] = 0;
}
}
and pasting it before the while loop but instead of setting currentarray[x][y] = futurearray[x][y], set it to 0. Also, if the coordinates are viewable locations instead of array co-ordinates, you'll want to change this:
printf ("%d\n", currentarray[x][y]);
to this:
printf ("%d\n", currentarray[x-1][y-1]);
I would also recommend putting a printf with a newline (\n) after each row has been printed and a tab (\t) after each item so that the formatting looks cleaner.