In NetLogo 6.1.1 I have one breed (rangers) looking for another breed (snares) in green patches (bush).
The behaviour that I can't get is this:
if a snare is found, remove the snare with 80% success rate; then
repeat the same procedure (hotspot-search; recursive call).
if the snare is not found (20% probability) then repeat the same
procedure (hotspot-search; the commented out section -> causes an endless loop) 5 times.
if no snares are removed in these 5 times, resume normal behaviour (move by random right turn and forward 1).
How can I do this?
;; globals =========================
breed [rangers ranger]
breed [snares snare]
rangers-own [snare-found?]
;; initialise ========================
to setup
resize-world -4 4 -4 4
clear-all
create-rangers 1 [set color blue]
ask patches [
if random 100 < 20 [set pcolor green]]
ask patches with [pcolor = green] [
sprout-snares random 5]
ask snares [
set size 0.5
set shape "dot"
fd 0.25
]
reset-ticks
end
;; main ==================================
to go
ask rangers [
rt random 181 - 90
fd 1
if any? snares-here [hotspot-search]
hotspot-search
]
end
;; functions ===============================
to hotspot-search
move-to patch-here
let target one-of snares-here
if (random 100 < 20) and (target != nobody) [
ask target [die]
set snare-found? true
hotspot-search
]
;;if snare-found? = true [
;; repeat 5 [hotspot-search]
;;]
end
One observation I'd make is that if you're wanting the rangers to search 5 times at a 20% chance of success, but there is no cost for searching, like lost time or energy, you can just do a single check at a 67% chance of success (1.00 - 0.80^5) = 0.67.
But if you do need have a cost or need to track the number of searches or something like that, below is how I'd write the code. Sorry for writing from scratch rather than updating yours, I was just trying to keep things as simple as possible.
breed [ rangers ranger ]
breed [ snares snare ]
to setup
create-snares 100 [
set shape "circle"
set color blue
set size 0.5
move-to one-of patches
]
create-rangers 10 [
set color red
move-to one-of patches
]
end
to go
ask rangers [
move-to one-of neighbors4
; call our procedure with the starting limit of 5
hunt-snares 5
]
end
to hunt-snares [ search-limit ]
; the recursive base case is search-limit of 0
if ( search-limit > 0 ) [
; can only find a snare if one exists here
ifelse random 100 < 20 and any? snares-here [
; found one
ifelse random 100 < 80 [
; disabled
ask one-of snares-here [ die ]
; restart the search
hunt-snares 5
] [
; we found a snare but failed to disable it, unclear what to do?
hunt-snares 5
]
] [
; failed to find one, move towards the base case
hunt-snares (search-limit - 1)
]
]
end
Edit to add: Sorry, I thought your original code was more complicated, it actually looks relatively simple and I probably should've just modified your version. The reason your hotspot-search procedure is going into an infinite loop is because snare-found? is never set to false anywhere in your code. The typical way to handle recursion is to have one parameter of the recursive procedure progress towards a base case where the last recursive call can quit and the whole chain of calls will end, too.
In this case we have two complications: 1) an implicit base-case that isn't a parameter - that there are still snares on the patch to try to disarm, and 2) that we can reset our parameter farther from the base case, knowing that item 1 means we won't loop over.
Related
I want to delete a collection in smalltalk so when the user selects the option again it is newly created.
This is my code:
"opcion 7"
/opc = 7) ifTrue: [
masDeUno:= OrderedCollection new.
cant:= b1 tam.
1 to: cant do: [:cta |
comp := cta verNumero.
i:= 1.
(i+1) to: cant do: [:cta |
(comp = cta verApellido) ifTrue: [
masDeUno add: comp.
break.
] "fin condicion"
] "fin todo interno"
]. "fin todo"
Transcript show: (masDeUno)printString .
"eliminar la coleccion para la proxima vez"
]. "fin op7"
With automatic garbage collection any unreferenced object will be automatically deleted if there are no references to the object. In your code the variable masDeUno is not referenced after the ifTrue: block finishes so you don't need to "delete" it (in fact, there is no way to explicitly delete Smalltalk objects).
What does this do, and is there a simpler way to write it?
Collection>>into: a2block
| all pair |
all := ([:allIn :each| allIn key key: allIn value. each])
-> (pair := nil -> a2block).
pair key: all.
self inject: all
into: [:allIn :each| allIn value: (allIn key value: allIn value value: each). allIn].
^all value
If you want to find out, the best way is to try it, possibly step by step thru debugger.
For example, try:
(1 to: 4) into: #+.
(1 to: 4) into: #*.
You'll see a form of reduction.
So it's like inject:into: but without injecting anything.
The a2block will consume first two elements, then result of this and 3rd element, etc...
So we must understand the selector name as inject:into: without inject:: like the implementation, it's already a crooked way to name things.
This is implemented in Squeak as reduce:, except that reduce: would be well too obvious as a selector, and except that it would raise an Error if sent to an empty collection, contrarily to this which will answer the strange recursive artifact.
The all artifact contains a block to be executed for reduction as key, and current value of reduction as value. At first step, it arranges to replace the block to be executed with a2block, and the first value by first element. But the recursive structure used to achieve the replacement is... un-necessarily complex.
A bit less obfuscated way to write the same thing would be:
into: a2block
| block |
self ifEmpty: [self error: 'receiver of into: shall not be empty'].
block := [:newBlock :each| block := newBlock. each].
^self inject: a2block into: [:accum :each| block value: accum value: each]
That's more or less the same principle: at first iteration, the block is replaced by the reduction block (a2block), and first element is accumulated.
The reduction only begins at 2nd iteration.
The alternative is to check for first iteration inside the loop... One way to do it:
into: a2block
| first |
self ifEmpty: [self error: 'receiver of into: shall not be empty'].
first := Object new.
^self inject: first into: [:accum :each |
accum == first
ifTrue: [each]
ifFalse: [a2block value: accum value: each]].
There are many other ways to write it, more explicitely using a boolean to test for first iteration...
I am dealing with a directed weighted graph and have a question about how to initialize a set a defined in the following:
Assume that the graph has the following nodes, which are subdivided into three different subsets.
//Subsets of Nodes
{int} Subset1= {44,99};
{int} Subset2={123456,123457,123458};
{int} Subset3={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
{int} Nodes=Subset1 union Subset2 union Subset3;
Now there is a set of H_j arcs, where j is in Nodes. H_j gives all arcs outgoing from Node j.
The arcs are stored in an excel file with the following structure:enter image description here
For node 44 in Nodes (Subset 1), there are the arcs <44,123456>, <44,123457>, <44,123458>. For 66 in Nodes (Subset 2), there is no arc. Can somebody help me how to implement this?
Important is that the code uses the input from the excel because in my real case there will be too much data to make a manual input... :(
Maybe there is a real easy solution for that. I would be very thankful!
Thank you so much in advance!
enter image description here
This addition refers to the answer from #Alex Fleischer:
Your code seems to work also in the overall context.
I am trying to implement the following constraints within a Maximization optimization ( The formulations (j,99) and (j,i) in the lower sum boundaries represent arcs):
enter image description here
I tried to implement it like this:
{int} TEST= {99};
subject to {
sum(m in M, j in a[m])x[<44,j>]==3;
sum(j in destPerOrig[99], t in TEST)x[<j,t>]==3;
forall(i in Nodes_wo_Subset1)
sum(j in destPerOrig[i],i in destPerOrig[i])x[<j,i>]==1;
}
M is a set of trains and a[M] gives a specific cost value for each indiviudal train. CPLEX shows 33 failure messages.
The most frequent one is that it cannot extract x[<j,i>], sum(in in destPerOrig[i]), sum(j in destPerOrig[i] and that x and destPerOrig are outside of the valid area.
Most probably the problem is that I implement the constraints in the wrong manner. Again, it is a directed graph.
Referring to the mathematical formulation in the screenshot: Could the format of destPerOrig[i] be a problem?
At the moment destPerOrig[44] gives {2 3 4}. But should´t it give:
{<44 2> <44 3> <44 4>} to work within the mathematical formulation?
I hope that this is enoug information for you to help me :(
I would be very thankful!
all arcs outgoing from Node j.
How to do this depends on how you store the adjacencies of the graph.
Perhaps you store a vector of arcs:
LOOP over arcs
IF arc source == node J
ADD to output
.mod
tuple arcE
{
string o;
string d;
}
{arcE} arcsInExcel=...;
{int} orig={ intValue(a.o) | a in arcsInExcel};
{int} destPerOrig[o in orig]={intValue(a.d) | a in arcsInExcel : intValue(a.o)==o && a.d!="" };
execute
{
writeln(orig);
writeln("==>");
writeln(destPerOrig);
}
/*
which gives
{44 66}
==>
[{2 3 4} {}]
*/
https://github.com/AlexFleischerParis/oplexcel/blob/main/readarcs.mod
.dat
SheetConnection s("readarcs.xlsx");
arcsInExcel from SheetRead(s,"A2:B5");
https://github.com/AlexFleischerParis/oplexcel/blob/main/readarcs.dat
I have a master variable generating numbers from 0 to 1000000 in sequence
I would like the first 0 to 200000 captured by a child variable that holds 0 counting up to 100000 (in sync with the master variable, and from the master's 100001 to 200000 , counts back down from 99999 to 0 backwards
my language is ksp ( c friendly ) and counting up looks like this
on init
declare $master (0,1000000) {**create master with it's range**)
declare $child (0,100000) {**create child with it's range**}
end on
on ui_control ($master) {**when the master generates numbers**}
if (in_range($master,0,100000))
$child := $master {**assign master's value to child when in range**}
end if
if (in_range($master,100001,200000))
$child := ??? {**count backwards from 99999 to 0 please**}
end if
end on
so my question is what code do I write to make the child treat 100001 to 200000 as 99999 to 0 counting backwards as the master generates 100001 to 200000? i have an abs operator available , i could use negative numbers without any issues, is that what I need to use somehow?
i've not had to solve this type of issue before..
as you probably realise, there will be other children for the rest of the values but if i can get this one right they will all follow the same pattern.
ok I'm going to go ahead and answer my own question here. If you are a ksp user and you come across this, here is an answer you can load up and watch it work.
on init
declare $new_value
declare ui_slider $master (0,1000000)
message("")
end on
on ui_control ($master)
$new_value := abs ($master - 1000000)
message ($master & " :::: " & $new_value)
end on
I'm just starting to fork() and I'm having some difficulties understanding the parallel execution. I've found this example code and I want to know if the first time it will go true or false (I know if pid1==0 it means it's a child, etc). I also want to know how many copies (children will be created) and some details on the general execution.
I have tried to run it and added the return 0; (my original source didn't have it) just to see if exits... but as you can see it "waits"
http://i.imgur.com/D3XEFgs.png
int main(void)
{
int pid1, pid2, pid3, pid4;
pid1=fork();
if (pid1!=0)
{
pid2=fork();
pid3=fork();
printf("\t\t IF(TRUE) pid1=%d and pid2=%d and pid3=%d\n",
pid1, pid2, pid3);
}
else
{
pid4=fork();
printf("\nIF(False) FATHER is talking with pid1=%d and pid4=%d\n",
pid1, pid4);
}
return 0;
}
This program creates five descendant processes, and makes six calls to printf, of which four will be the IF(TRUE) message and two will be IF(FALSE). Here is an ASCII-art diagram of the control flow; every time it branches, both sides are executed, with the parent going straight down and the child to the right. The numbers are the fork calls initializing the pid1, pid2, ... variables, the letters T and F are the IF(TRUE) and IF(FALSE) messages, and the _ is the return 0 at the end of the function. This program does not wait for anything; all control flow paths reach the return 0 eventually.
|
1
|\------\
2 4
|\--\ |\
3 3 | |
|\ |\ | |
T T T T F F
| | | | | |
_ _ _ _ _ _
The output messages may appear in any order. And it's possible that the topmost parent process will exit (returning control to the shell) before all of the descendant processes have written their messages, so (as is visible in your screeenshot) the shell prompt may get jumbled up with the messages, too.
Note that, going by the text of the messages, you have your if conditional backward: pid1 != 0 is true in the parent, not the child.
Both true and false will be used on the first time.
fork() copies the program (creates 1 child) and both programs continue execution from that point. The child process will take one branch and the parent the other.
The number of fork()s is as follows:
You start with 1 process
After pid1 -> +1 processes
Parent Branch
After pid4 -> +1 processes
Child Branch
After pid2 -> +1 processes
BOTH of the newly created processes run fork() for pid3, so after pid3 -> +2 processes
You get 5 children + the original process.