Is it possible in Red to test value? for a variable inside a context not in global context? - red

In last example, probe value? 'a returns true as it detects 'a has value in global context. But I'd like to test 'a exclusively in local context, is there a syntax to do so ?
context [
probe value? 'a; false
]
context [
a: 1
probe value? 'a; true
]
; would like false instead of true
a: 1
context [
probe value? 'a; true
]

I think the simplest check would be
context [
probe in self 'a ; none
]
It returns none instead of false, but that is the only other falsy value anyway, so it's totally appropriate to check against. If you need it to be false, you can put to-logic in front.

Is it possible in Red to test value? for a variable inside a context not in global context?
By definition, no. Because there is no such thing as "the global context".
Remember that "Rebol (Red) actually does not have scope at all" ... "Rebol (Red) fakes it."
(See: Is there a overall explanation about definitional scoping in Rebol and Red)
Rebol has BIND? for asking an arbitrary ANY-WORD! where it's bound to (if anywhere). Red calls this CONTEXT?. So what you can do is ask if the binding of a word is to a context you care about.
ctx1: context [a: 10]
ctx2: context [a: 20]
word: bind 'a ctx1
print ctx1 = context? word ; true
print ctx2 = context? word ; false
So if what you mean by "global context" is actually the so-called SYSTEM/WORDS object, then that can be your test:
context [
probe value? 'a ; false
]
context [
a: 1
probe system/words <> context? 'a ; true
]
a: 1
context [
probe system/words <> context? 'a ; false
]
As to whether this is appropriate for your purposes, I don't know. Just remember there's no scope in Rebol/Red, unless you rig up some fake approximation that works well enough for what you're doing.

Here a solution without searching in the 'global' system/words, but in the 'local' self
>> a: 1
== 1
>> context [
[ probe all [
[ find words-of self 'a
[ value? pick find words-of self 'a 1
[ ]
[ probe value? 'a
[ ]
none
true
== make object! []
>>
>> context [
[ probe all [
[ find words-of self 'a
[ value? pick find words-of self 'a 1
[ ]
[ probe value? 'a
[ a: 2
[ ]
none
false
== make object! [
a: 2
]
>>
>> context [
[ a: 2
[ probe all [
[ find words-of self 'a
[ value? pick find words-of self 'a 1
[ ]
[ probe value? 'a
[ ]
true
true
== make object! [
a: 2
]

Related

How to access the first turtle of a code sequence in NetLogo 6.2?

I have the following doubts:
I have several individuals of 9 turtle codes.
The turtle codes are: R1M1 R2M1 R3M1 R1M2 R2M2 R3M2 R1M3 R2M3 R3M3. And I have 10 individuals of each code.
As the code is structured in a loop sequence and the order that the code exits in the result exported in .csv, I would like to ask the first individual of the first code (R1M1) to print the output header. But, I'm only getting it using one-of, and then the header often doesn't come out in the first line of the output. And I don't know how I can access the first turtle from the R1M1 code. Does anyone have any ideas?
What I thought of is calling turtle 0 which has the code R1M1. But, I still don't know how to do this in NetLogo.
OBS.: I tried to use only turtle 0, but in the other codes, too, there is turtle 0 and then the header appears.
Thanks in advance
let n count turtles with [ profiles-code = "R1M1" ]
if n > 0
[
ask one-of turtles with [ profiles-code = "R1M1" ]
[
prepare-header-output;; CALL A PROCEDURE
]
]
An example of how the header is coming out (has 3 individuals from each of the 9 codes)
I would use a flag / semaphore variable to indicate if a header is needed. You'll need to adapt the below if you have your turtles outputting the data, but hopefully this will get you pointed in the right direction- more details in comments:
globals [ need-headers? ]
turtles-own [ class ]
to setup
ca
random-seed 1
set need-headers? true
if file-exists? "test_output.csv" [ file-delete "test_output.csv" ]
crt 10 [
set class item random 5 "ABCDE"
]
reset-ticks
end
to go
if count turtles < 1 [ stop ]
ask turtles [
if random-float 1 < 0.25 [ die ]
]
; Toy output example
file-open "test_output.csv"
foreach range length "ABCDE" [ i ->
; Output headers if needed
if need-headers? [
file-print "turtle-type, count, ticks"
; Change the need-headers? to false so this step will only happen once
set need-headers? false
]
let ltr item i "ABCDE"
let n-type count turtles with [ class = ltr ]
file-print ( word ltr "," n-type "," ticks )
]
file-close
tick
end
Output here looks something like:
but if I don't change need-headers? to false, it looks like:

How to loop in NetLogo?

I have the following problem. I need to loop through the code. However, it doesn't work.
Contextualizing the problem: I have 3 files (in .asc) that represent data referring to 3 ages of the turtles (age 2, age 4 and age 8). I would like if the user puts the value 1 in num-user, it would only do the simulation with only one file (L_2) that would represent [ "2" ] ; if the user puts the value 2 in num-user, he would do the simulation with the files (L_2 and L_4) that would represent [ "2" "4" ] and finally, if the user puts the value 3 in num-use, it would simulate the files (L_2 , L_4 and L_8) that would represent [ "2" "4" "8" ]. The problem is that the loop is not working and gives various errors. Like:
Extension exception: ascii file ./L_8.asc not found or Can't find element 3 of the list [2 4 8], which is only of length 3 or go runs more than 3 simulations.
I was unable to attach the .ascii files here in the question. But if anyone can look at the code and identify the error I would be very grateful. I can't use BehaviouSpace to solve the situation, I need this loop in the code.
Thanks in advance!
extensions [ gis ]
globals [ num turtle-ages num-ages files random-seeds num-user repetitions ]
to setup
ca
set random-seeds 1
random-seed random-seeds
set num 0
set turtle-ages [ "2" "4" "8" ]
set num-ages item num turtle-ages
setup-asc
setup-turtles
reset-ticks
end
to setup-2
clear
random-seed random-seeds
set num-ages item num turtle-ages
setup-asc
setup-turtles
reset-ticks
end
to setup-turtles
ask n-of 5 patches [ sprout 1 ]
end
to clear
set files 0
clear-ticks
clear-turtles
end
to setup-asc
let number1 num-ages
set files gis:load-dataset ( word "./L_" number1 ".asc" ) ;; this loads a one raster file. There are 3 files in the folder with the names: (L_2.asc ; L_4.asc and L_8.asc
end
to go
move
tick
let n count turtles
if n = 0 or ticks = 10
[
set random-seeds random-seeds + 1
set repetitions 1
if random-seeds = repetitions + 1
[
set random-seeds 1
set num num + 1
;; if the user puts the value 1 in num-user, it would only do the simulation with only one file (L_2) that would represent [ "2" ]
;;; if the user puts the value 2 in num-user, he would do the simulation with the files (L_2 and L_4) that would represent [ "2" "4" ]
;;;; and finally, if the user puts the value 3 in num-use, it would simulate the files (L_2 , L_4 and L_8) that would represent [ "2" "4" "8" ]
set num-user 1 ;;
if num = num-user [ stop ]
]
setup-2
]
end
to move
ask turtles [
right random 360
fd 1
if ticks = 5 [ die ]
]
end
Whenever possible, I'd suggest paring down your code to a MRE to a) make sure that users here can run your code (without your files, for example, this is not really viable) and b) to see if reframing your question / goals in simpler terms would help get things working- at least that's what works for me!
I think that you might find foreach useful here as a way to loop through your desired simulations instead of manually tracking the number of iterations. For this example, assuming num-user is a numeric input widget on the interface, the setup below will determine which of the ages to process:
globals [ ages-to-run ]
to base-setup
ca
; Determine how many simulations to run, based on user input into
; 'num-user' numerical input widget on the interface
ifelse num-user < 1 or num-user > 3 [
print "Incorrect number of simulations indicated"
] [
let possible-sims [ "2" "4" "8" ]
set ages-to-run sublist possible-sims 0 num-user
]
reset-ticks
end
After running the above, the ages-to-run variable will contain ["2"], ["2" "4"], or ["2" "4" "8"]. Next, you can iterate over those desired ages to run your simulations (a little more detail in comments):
to run-simulations
if ages-to-run = 0 [
print "Simulation setup not complete"
]
foreach ages-to-run [
; This is the loop proper where each "age" is iterated.
; All of your simulation calls (manual variable resetting,
; etc) should all go within this loop.
current-age ->
print word "Running simulations for age: " current-age
let file-to-load ( word "./L_" current-age ".asc" )
print file-to-load
clear-turtles
ask n-of 5 patches [
sprout 1 [
pd
set color runresult current-age + 55
]
]
repeat 20 [
ask turtles [
rt random 60 - 30
fd 1
]
tick
]
print ( word "Simulations complete for age: " current-age "\n" )
]
end
Running that code above with 3 entered into num-user will run a simulation for each age (different colors indicate different runs):
So to run simulations proper, all your per-age code should go within that foreach loop indicated above- and be careful, as you were in your question, to not reset global variables.

ITEM expected input to be a string or list but got the number 0 instead error. How would I fix this?

I am trying to make a model in netlogo that can simulate various versions of langton's ant. I have the basic code already (which is not polished up yet, apologies for that). from a chooser in the interface, the user chooses a path that the ant (the turtle) takes, and turns either left or right depending on the color of the patch he is on. to turn the strings in the chooser into a usable code, I am using the following code (only partially included the walk execution, if you want the entire thig
to make-state-sequence
if mychoice = "[own input]"
[
ifelse 2 <= length own-LR-string and length own-LR-string <= 12 and remove "L" remove "R" own-LR-string = ""[
set state-sequence own-LR-string][print "Invalid, can only contain L and R, and must be 2-12 symbols" stop]
] set N length state-sequence
if mychoice = "[Random sequence]"
[
let random-length 2 + random 10
let random-sequence n-values random-length [one-of ["L" "R"]]
set state-sequence random-sequence
]
set N length state-sequence
if table:has-key? instruction-table mychoice [
set state-sequence table:get instruction-table mychoice]
set N length state-sequence
end
to walk
ask turtles [
if bumped? = true [stop]
let direction item [state] of patch-here state-sequence
if direction = "L" [
left 90
]
if direction = "R" [
right 90
]
here, the state-sequence is important; it is the string that is chosen in the chooser used in the interface.
doing this will make the setup button work fine, but using the walk button gives the following error:
ITEM expected input to be a string or list but got the number 0 instead.
I have tried turning the let direction item [state] of patch-here state-sequence portion into an ifelse statement; because if the symbol is not an L, it would automatically be an R. it didn't change the error.
I suspect the state-sequence is not recognised as a string. is there a possible fix for this? I also tried using a to-report in combination with reduce, but we got stuck on that as well.
for good measure, here are some snippets of the widgets in the interface:
the interface
the chooser editor
the info tab, if you would like to see it. has some deeper explanation on how langton's ant works.
As JenB commented above, it seems likely that "state-sequence" for "patch-here" was never initialized or set, so it has defaulted to the number 0.
You could check whether state-sequence was a list or string as the first real step in your ask turtles [ ] section and to throw an informative error if it is not.
Incidentally, your sequence of if-statements in make-state-sequence is a risky coding structure as zero or more than one of the conditions could fire. Possibly in your case zero of them were matched.
;; This structure may fire multiple conditions
;; with later actions possibly overriding earlier actions
;; and has the possibility that none of the conditions are met
;; If TWO conditions are matched, BOTH fire in that order and the SECOND one
;; may overwrite the FIRST one.
( condition1 ) [ action1 ]
( condition2 ) [ action2 ]
;; ...
( conditionn ) [ actionn ]
;; The following structure exits after the first succeessful condition is met.
;; and guarantees that there is always exactly one case matched
;; which might be the default case .
;; if a second condition might have been matched is unknown because the
;; code never gets that far.
;;
;; This is slightly obscurely hidden in the dictionary under "ifelse"
;; and further confused if you believe "choice" is a reserved word or the
;; only way you can test a condition. I tested the following and it works.
(
ifelse
( condition1 ) [ action1 ]
( condition2 ) [ action2 ]
;; ...
( conditionn ) [ actionn ]
;; else
[ default action ]
)
Here's sample code that demonstrates testing what value you have and showing that the zero value resulting from not having set the patches sequence could be detected by the
?is-string and ?is-list tests. It also demonstrates using the CHOICE structure.
patches-own [ x ]
to setup
clear-all
let z n-values 8 [one-of ["L" "R"]]
if is-list? z[ print "it's a list" ]
if is-string? z [ print "it's a string" ]
let a 46
let b 43
let c "dog"
let d "cat"
(
ifelse
( a = 4 ) [ print "a is 4 " ]
( b = 4 ) [ print "b is 4 " ]
( c = "dog" and d = "cat") [ print "strange choice "]
; else
[ print "I fell through to the else condition" ]
)
create-turtles 1
ask turtles [
print ( word "\n x = " x )
print ( word "is x a number? " is-number? x )
print ( word "is x a list? " is-list? x )
print ( word "is x a string? " is-string? x )
]
ask patch 0 0 [ set x n-values 8 [one-of ["L" "R"]]]
ask turtles [
print ( word "\n x = " x )
print ( word "is x a number? " is-number? x )
print ( word "is x a list? " is-list? x )
print ( word "is x a string? " is-string? x )
]
reset-ticks
end

compose and compose/deep for parse rule in red?

How to keep (print text) as it disappears when using compose ?
s: {hello test1 parse test2}
t1: "test1"
t2: "test2"
rule: compose [ thru (t1) mark: copy text to (t2) (print text)]
parse s rule
same question for compose/deep if it's different answer:
s: {hello test1 parse test2. hello second test for test1 parse test2.}
t1: "test1"
t2: "test2"
rule: compose/deep [ any [thru (t1) mark: copy text to (t2) (print text)]]
parse s rule
You aren't limited to what's in the box, so you could make your own COMPOSE-like construct that does other patterns.
For instance, here's a composeII which only substitutes for cases where there are nested parentheses. So it will leave (x) alone but evaluate ((x)).
composeII: function [block /only /deep] [
collect [
foreach item block [
case [
all [
paren? :item
1 = length? item
paren? first item
][
either only [
keep/only do first item
][
keep do first item
]
]
all [
deep
block? :item
][
either only [
keep/only composeII/deep/only item
][
keep/only composeII/deep item
]
]
true [
keep/only :item
]
]
]
]
]
So for your case:
>> t1: "test1"
>> t2: "test2"
>> composeII/deep [
any [thru ((t1)) mark: copy text to ((t2)) (print text)]
]
== [
any [thru "test1" mark: copy text to "test2" (print text)]
]
You can either convert block to paren, or quote paren:
>> compose [something here (to paren! [print text])]
== [something here (print text)]
>> compose [something here (quote (print text))]
== [something here (print text)]
It's the same for compose/deep .
As blocks shield their content from evaluation of compose you can also use
>> rule: compose [ thru (t1) mark: copy text to (t2) (first [(print text)] )]
== [thru "test1" mark: copy text to "test2" (print text)]

How to update 'myself' variables from within a block

In netlogo 5.3.1, assume:
marketmakers-tier1-own [ trading-capital ]
I want to do this:
ask other marketmakers-tier1 [
let T-capital [ trading-capital ] of myself
let T-cost some-amount
;; do some stuff
; now update myself's trading-capital
set [ trading-capital ] of myself ( T-capital - T-cost )
]
Produces this error on the set command:
This isn't something you can use "set" on.
Any suggestions I will appreciate.