How do I save and restore agent breeds in a file? - io

I want to save and restore a set of turtles in a file. I have something like this:
breed [squares square]
breed [circles circle]
squares-own [side-length]
circles-own [radius]
to save-agents
file-open "test"
file-write count turtles
ask turtles [
file-write xcor
file-write ycor
file-write breed
]
ask squares [
file-write side-length
]
ask circles [
file-write radius
]
file-close
end
to restore-agents
file-open "test"
let n file-read
crt n
ask turtles [
set xcor file-read
set ycor file-read
set breed file-read ;; Right here I get an error "Expected a constant. (line number 1,
] ;; character x) error while turtle y running FILE-READ"
ask squares [
set side-length file-read
]
ask circles [
set radius file-read
]
Looking at the file, I see the breeds are stored as unquoted character strings. It doesn't matter what I try to read the breed variable as; I get an error just manually going through a bunch of file-read statements.
I suppose I could intentionally code the breed as a string that I later interpret using a whole bunch of nested ifelse blocks (yuk). But it appears that the way NetLogo writes the breed variable is the same way it writes other constants like true and false. Is this a NetLogo bug? Is there an (elegant) work-around?
On further thought, I could count and store each kind of agent individually so when I go to restore I could create squares number-of-squares, etc. but I was really hoping not to have to handle every possible kind of breed this way. Suggestions?
Thanks,
Glenn

The runresult primitive can help you here: it allows to run code stored in a string.
If you save your breed using
file-write (word breed)
to make sure that NetLogo puts quotes around it, you can later restore it like this:
let breed-as-string file-read
set breed runresult breed-as-string
There are also other possible approaches for saving and restoring turtles:
export-world and import-world might be overkill here, since they save and restore the whole state of the NetLogo world, but they may be useful in other circomstances.
The nw:save-graphml and nw:load-graphml from the NW extension can also be used for that. Their primary purpose is to deal with networks (i.e., turtles and links) but they won't complain if you have only turtles to save and restore.
Edit:
Here is a full example using runresult:
breed [squares square]
breed [circles circle]
to save-and-restore-breeds
clear-all
create-squares 2
create-circles 2
if file-exists? "test" [ file-delete "test" ]
; save agents:
file-open "test"
file-write count turtles
ask turtles [ file-write (word breed) ]
file-close
clear-all
; restore agents:
file-open "test"
let n file-read
crt n [
let breed-as-string file-read
set breed runresult breed-as-string
]
file-close
show [ breed ] of turtles
end

Related

Netlogo: issue with patches attributes as input variable to procedure

thanks to a fellow stack-overflower, i have recently learned how to use 'run-result' to pass patch attributes as input variables to a procedure. However, i am struggling using the same approach when i want to modify the patch attribute. To clarify, in the code below, i am successfully passing the attribute 'attr1' to Export.List.to.file, but when I pass it to Import.List.from.file, i get an 'this isn't something you can use set on' error in the line 'ask datum [set (run-result #attr) file-read]]'
can anyone help?
to setup
clear-all
let patch-list sort patches
ask patches [set attr1 random 10]
Export.List.to.file "attr1" patch-list "attr1.txt"
Import.List.from.file "attr2" patch-list "attr1.txt"
end
to Export.List.to.file [#attr #patch-list #filename]
let list1 map [ p -> [run-result #attr] of p ] #patch-list
carefully [file-delete #filename] []
file-open #filename
foreach list1 [?datum -> file-print ?datum]
file-close
end
to Import.List.from.file [#attr #patch-list #filename]
file-open #filename
foreach #patch-list [datum -> ask datum [set (run-result #attr) file-read]]
file-close
end
To be perfectly honest, I can't explain exactly why it doesn't work in the second case and does work in the first case. My best guess is that in the first case, the attribute is treated as a reporter, something to be used by other processes. In the second case, the attribute is treated as a property, for which different rules apply.
The workaround I would use is to turn the entire set command into a single string, and then turning it back into a command by using run. To combine the different parts of the command into a single string, you can use word: let commandstring (word "set " #attr-name " random 5"). Notice how I use quotation marks for "set " and " random 5" but I don't use them for #attr-name, since I don't want #attr-name in the final string, but rather the string contained within #attr-name. In my case that would be "attr3".
to go-3
change-attribute "attr3" patches
end
to change-attribute [#attr-name patchset]
let commandstring (word "set " #attr-name " random 5")
show commandstring
; this gives "set attr3 random 5"
ask patchset [run commandstring ]
end

Azure KQL Regex capture of sentence with extract_all() for named capture groups

I am trying to extract multiple values from a log with the following format by using the extract_all() function:
v1=value1 v2=May 18 2021 v3=value3 v4=The dog jumps over the fence v5=192.168.1.1
The extract_all() formatting is the following:
extract_all(#"(?P<key>\w+)?=(?P<value>\S*)?", dynamic(["key","value"]), restconvert)
I have tried multiple ways in order to capture the full sentence of v4, but I haven't been able to. Among others, I have used (?P<value>\w+)?, (?P<value>\S* \d* \d*)?. The latter was able to capture the date without causing any problem to the string continuity. I have also tried the logical or in the second part of the regex in order to distinguish between cases with no success.
\w+( \w+)* and similar variations messed up with other values, such as IP addresses and with the continuity of the string.
I am not using the parse operator because the fields change through time.
Any hints?
This would have been a lot easier with negative lookahead, but RE2 doesn't support it apparently. This handles many spaces between words and skips spaces, but does include an extra space on the value, sometimes, if there are multiple spaces between value and the next key token.
print text="v1=value1 v2=May 18 2021 v3=value3 v4=The dog jumps over the fence"
| extend values = extract_all(#"(?P<key>\w+)=(?P<value>(?:\w+(?:\s?|\z))+)(?:\s|\z)", dynamic(["key","value"]
Results:
[
[
""v1"",
""value1 ""
],
[
""v2"",
""May 18 2021 ""
],
[
""v3"",
""value3 ""
],
[
""v4"",
""The dog jumps over the fence""
]
]

Netlogo hide-turtle

Here's a Netlogo-beginner question. I created a model where birds shall fly on a certain route. I created this route by placing 10 turtles I called "rasts" (resting place) on patches an linking them with each other. Now, I want to make the birds fly on these routes and when a resting place disappears (by using an "on/off"-switch), they shall take another route.
My problem: At the moment I have 5 rasts but only the first one can be shut off by using the switch. Has anybody an idea, how to fix this?
Here's my code:
breed [rasts rast]
breed [birds bird]
to setup
setup-rasts
hide-rasts1
hide-rasts2
hide-rasts3
hide-rasts4
hide-rasts5
end
to setup-rasts
set-default-shape rasts "circle"
create-rasts 1 [setxy -12 36 ]
end
to hide-rasts1
ifelse rast-1? [ ask rast (number-of-birds + 0) [ set hidden? true] ]
[ ask rast (number-of-birds + 0) [ set hidden? false] ]
end
For the first question:
Isn't it possible to make more than 1 turtle hide itself by using the
following code?
you can ask a list of turtles to hide:
; hide all turtles
ask turtles [ hide-turtle ]
; hide all your "rasts"
ask rasts[ hide-turtle ]
; hide random 4 of your turtles
ask n-of 4 turtles [ hide-turtle ]
As for the 2. question
Is it possible to make turtles (birds) follow a route an change it,
when there's another turtle (rast) in there way?
the answer is of course it is possible, but the question is somehow to general to suggest a precise solution. You can use the face command to point the turtle in the right direction. For sensing the nearest turtles check the turtles with min distance. For example (in turtle's context):
set nearest-rast min-one-of (other rasts) [ distance myself ]

Searching for Number of Term Appearances in Mathematica

I'm trying to search across a large array of textual files in Mathematica 8 (12k+). So far, I've been able to plot the sheer numbers of times that a word appears (i.e. the word "love" appears 5,000 times across those 12k files). However, I'm running into difficulty determining the number of files in which "love" appears once - which might only be in 1,000 files, with it repeating several times in others.
I'm finding the documentation WRT FindList, streams, RecordSeparators, etc. a bit murky. Is there a way to set it up so it finds an incidence of a term once in a file and then moves onto the next?
Example of filelist:
{"89001.txt", "89002.txt", "89003.txt", "89004.txt", "89005.txt", "89006.txt", "89007.txt", "89008.txt", "89009.txt", "89010.txt", "89011.txt", "89012.txt", "89013.txt", "89014.txt", "89015.txt", "89016.txt", "89017.txt", "89018.txt", "89019.txt", "89020.txt", "89021.txt", "89022.txt", "89023.txt", "89024.txt"}
The following returns all of the lines with love across every file. Is there a way to return only the first incidence of love in each file before moving onto the next one?
FindList[filelist, "love"]
Thanks so much. This is my first post and I'm largely learning Mathematica through peer/supervisory help, online tutorials, and the documentation.
In addition to Daniel's answer, you also seem to be asking for a list of files where the word only occurs once. To do that, I'd continue to run FindList across all the files
res =FindList[filelist, "love"]
Then, reduce the results to single lines only, via
lines = Select[ res, Length[#]==1& ]
But, this doesn't eliminate the cases where there is more than one occurrence in a single line. To do that, you could use StringCount and only accept instances where it is 1, as follows
Select[ lines, StringCount[ #, RegularExpression[ "\\blove\\b" ] ] == 1& ]
The RegularExpression specifies that "love" must be a distinct word using the word boundary marker (\\b), so that words like "lovely" won't be included.
Edit: It appears that FindList when passed a list of files returns a flattened list, so you can't determine which item goes with which file. For instance, if you have 3 files, and they contain the word "love", 0, 1, and 2 times, respectively, you'd get a list that looked like
{, love, love, love }
which is clearly not useful. To overcome this, you'll have to process each file individually, and that is best done via Map (/#), as follows
res = FindList[#, "love"]& /# filelist
and the rest of the above code works as expected.
But, if you want to associate the results with a file name, you have to change it a little.
res = {#, FindList[#, "love"]}& /# filelist
lines = Select[res,
Length[ #[[2]] ] ==1 && (* <-- Note the use of [[2]] *)
StringCount[ #[[2]], RegularExpression[ "\\blove\\b" ] ] == 1&
]
which returns a list of the form
{ {filename, { "string with love in it" },
{filename, { "string with love in it" }, ...}
To extract the file names, you simply type lines[[All, 1]].
Note, in order to Select on the properties you wanted, I used Part ([[ ]]) to specify the second element in each datum, and the same goes for extracting the file names.
Help > Documentation Center > FindList item 4:
"FindList[files,text,n]
includes only the first n lines found."
So you could set n to 1.
Daniel Lichtblau

Why are local variables variable is not respected?

In this code snippet, fields-types in the end is modified by the to-camel-case function, vs. being passed as a local variable to the parent function:
fields-types: ["First Name" "string" "Last Name" "string" "Age" "int"]
to-camel-case: function [name] [
name/1: lowercase name/1
replace/all name space ""
]
fill-template-body: func [
field-labels-types [block!] /local vars fields-names-types
] [
vars: [member-name member-type]
field-names-types: copy []
foreach [field-label field-type] field-labels-types [
append field-names-types to-camel-case field-label
append field-names-types field-type
]
]
fill-template-body fields-types
Execution gives:
>> fill-template-body fields-types
== ["firstName" "string" "lastName" "string" "age" "int"]
>> fields-types
== ["firstName" "string" "lastName" "string" "age" "int"]
>>
Whereas I would want that fields-types to stay invariant:
fields-types: ["First Name" "string" "Last Name" "string" "Age" "int"]
Of course I can try to circumvent this by modifying to-camel-case to use a copy of name, but that is not something I think I should have to do.
Is there something like the var and val keywords in Scala?
Variable is an ugly word in REBOL, everything - even words - are values. This isn't some semantic newspeak, it's helpful in understanding the way in which REBOL flows.
I think of values as being contained within one giant array in memory, where REBOL (the language) uses words and their contexts to reference and interact with the values. Most REBOL functions operate without duplicating these values:
head lowercase next uppercase str: "abcd"
remove back tail str
This is one of REBOL's most efficient features - you don't need copies for intermediary processes, to require such is wasteful. Think of that array growing where every time you use replace, uppercase or to-camel-case a value is duplicated. Whole processes can be built on the premise of modification rather than duplication - indeed a context can be built without necessarily having to return a value:
remove-spaces: use [space mark][
space: charset " ^-"
[any [mark: space (remove mark) | skip]]
]
parse/all str: "Should Be No Spaces" remove-spaces
The trick then becomes knowing where to copy values, and I think happens to intersect with REBOL's gift for concise expression:
parse/all link: copy title: "An Article on REBOL" remove-spaces
print ["(" link ")" title]
to-camel-case copy field-label
And of course, modification has its limitations. Sometimes it is cleaner building from scratch.
Your camel case function operates on the original value so if you want to preserve the original value, you need to copy it, and return the altered value. Since your function acts on a template it needs to copy the template right??
So, something like this should work:
fill-template-body: func[ labels [block!] /local field-labels-types vars fields-names-types][
field-labels-types: copy labels
..

Resources