2

I wonder if anyone can help with this question for which I am a bit lost. I have turtles with three-dimensional boolean lists [a b c] where a, b, c in {0, 1}. I would like each turtle to create a link with another one who has 1 on all the same positions of the list. A turtle should thus identify where in its list it has 1 and look for another turtle that has 1 in the every same position. Where the original turtle has 0, the second one can have either 1or 0.

That is:

Turtle 1 [0 1 0]

Turtle 2 [1 1 1]

Turtle 3 [1 0 1]

Turtle 4 [0 1 1]

Turtle 1 should create links with Turtle 2 or Turtle 4 (because both have 1 on item 1, the second position) but not with Turtle 3 since it has a 0in that position. Turtle 4 should create a link with Turtle 2 only (1 in the second and third positions), as should Turtle 3 (1in the first and third position), and Turtle 2 should be unable to create links (no turtles with 1 in all three positions).

What I have is

let candidate one-of turtles with [list1 = [list1] of myself]
create-link-with candidate

Which of course doesn't work since the turtle will look for another one that has exactly the same list (including zeros) and not one that has the same positions for 1 only. I know this should be related to foreach, map, reduceand filterbut I can't quite get the syntax right...

Happy end of year to everyone

JenB
  • 17,620
  • 2
  • 17
  • 45
lomper
  • 379
  • 1
  • 12
  • Hi @JenB Thanks for the comment. I think I understand your point but if I subtract Turtle 1 from Turtle 4, then I'll get `[0 0 -1]`, `[0 0 1]` in `abs`. The problem then is that I cannot differenciate the first zero from the second, and what I need is the turtle to be able to tell that they have the second element in common... Unless I am not understanding properly. Turtle 3 linking with Turtle 2 can work because it will give `[0 -1 0]`but I don't think there's an easy way to see when 0 happens because both have 1 or 0... – lomper Dec 28 '19 at 16:39
  • Thanks again @JenB. I have rewritten my question, hope it's clearer now... I'll try also the two-step idea :) – lomper Dec 28 '19 at 17:56
  • don't try the two step - it was not previously clear that ALL 1s had to match. I have edited the question slightly, but the two step is not relevant with that requirement. – JenB Dec 28 '19 at 19:35

2 Answers2

2

I'm sure someone who is better at lists will be able to do this with reduce or other clever tools. However, since position only gives the first position, I can't see any vectorised way to do this. So I have iterated with foreach instead.

to testme
  let list1 [0 1 0]
  let list2 [1 1 1]
  let list3 [1 0 1]
  let list4 [0 1 1]
  type "check 1, 2: " print match-ones list1 list2
  type "check 1, 3: " print match-ones list1 list3
  type "check 1, 4: " print match-ones list1 list4
  type "check 2, 1: " print match-ones list2 list1
  type "check 2, 3: " print match-ones list2 list3
  type "check 2, 4: " print match-ones list2 list4
  type "check 3, 1: " print match-ones list3 list1
  type "check 3, 2: " print match-ones list3 list2
  type "check 3, 4: " print match-ones list3 list4
  type "check 4, 1: " print match-ones list4 list1
  type "check 4, 2: " print match-ones list4 list2
  type "check 4, 3: " print match-ones list4 list3
end

to-report match-ones [#source #target]
  foreach range length #source
  [ x -> if item x #source = 1 and item x #target != 1
    [ report false
    ]
  ]
  report true
end

The reporting procedure takes the first list and simply runs through checking each item. If it's a 1 and the other list doesn't have a 1 then the procedure reports false (and ends without testing the others). If that never happens, the the procedure reports true.

The testme procedure is simply there to call the procedure and check your test data. The code is a complete model.

JenB
  • 17,620
  • 2
  • 17
  • 45
  • yes that does exactly like what I'm after! Tanks a lot, I'll get back if I struggle with it but I think I should be able to adapt it to my issue. Have a great 2020! – lomper Dec 29 '19 at 07:32
  • see my answer for a couple of alternate versions – Seth Tisue Dec 30 '19 at 19:34
1

Here's a recursive solution:

to-report match-ones [source target]
  if empty? source [ report true ]
  if first source = 1 and first target != 1 [ report false]
  report match-ones butfirst source butfirst target
end

and a version that uses foreach without using indexing:

to-report match-ones [source target]
  (foreach source target [[?s ?t] ->
    if ?s = 1 and ?t != 1 [ report false ]
  ])
  report true
end

I think this last version is probably clearest, but it's a matter of personal preference.

Seth Tisue
  • 29,985
  • 11
  • 82
  • 149
  • Thanks a lot Seth, I am away from my computer but that is indeed a clear way to solve the problem (on paper the second one does indeed look clearer to me). I'll try it out asap. Best wishes for 2020 – lomper Jan 01 '20 at 15:12