2

I'm converting a Monte Carlo simulation of certain random geometries from Python to Rust. The freedom I had in Python allowed me to be somewhat sloppy about storing references to other objects all throughout my code, but this seems to be trickier to implement in Rust.

In my current Python implementation, the main object is a Geometry. It contains a dictionary of Vertexes with a unique ID (the ID is also its lookup key in the dictionary) and a dictionary of Triangles (same scenario as for Vertex). Every Triangle contains a list of three Vertexes (no dictionary this time, here it's an ordered list), and every Vertex contains a dictionary of all the Triangles that it appears in (again indexed by the Triangle's unique ID).

This leads to a whole lot of cross-references, but it does make it very easy to find things. For example, it is straightforward to find all the neighbouring Vertexes of a specific Vertex by simply looping through all the Triangles it appears in and collecting all the Vertexes that are contained in these Triangles.

For convenience, here is a summary of the data structures:

class Geometry(object):
    def __init__(self):
        self.vertices = {}
        self.triangles = {}

class Vertex(object):
    counter = 0
    def __init__(self):
        self.index = Vertex.counter
        Vertex.counter += 1
        self.triangles = {}

class Triangle(object):
    counter = 0
    def __init__(self, vertices):
        self.index = Triangle.counter
        Triangle.counter += 1
        self.vertices = vertices # list of length 3

In Rust, this will not work because of the ownership model. The most straightforward alternative I could come up with would be to give the Geometry object a member HashMap of Vertexes and Triangles, just like in my Python code (again indexed by ID). The Vertex and Triangle objects would then contain a vector/array of the IDs of their 'members'. This ID can then be used to find the appropriate object in the HashMap.

For example, if a certain Triangle contains the Vertexes with IDs 1, 2, and 3, I could set the variable 'vertices' in the Triangle object to the array [1,2,3]. However, in order to actually work with the Vertex objects afterwards, I'd have to subsequently look up the object in the HashMap. This would lead to a lot of repetition all throughout the code. Furthermore, since the Triangle and Vertex structs are not aware of the struct Geometry, it will be impossible to add a method to either Triangle or Vertex that will encapsulate this process - after all, they cannot access the appropriate HashMap.

I've been thinking about a way of making this work with borrows, so that the Triangle and Vertex objects can in fact store a reference to one another. However, my experience with Rust is severely lacking, so I'm not getting very far. Some initial naive approaches always ran into problems with lifetimes and I'm even starting to doubt whether my current setup is workable at all in the Rust paradigm.

All feedback on any part of my question would be very welcome. Ideally I'm looking for a concrete suggestion on how to implement something along my line of thinking, but if you get the idea that I should rethink my entire approach, then I'd also be very happy to hear that.

JorenB
  • 1,831
  • 2
  • 16
  • 27
  • 1
    Have you seen [`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html)? Are you familiar with the data structure known as a [*graph*](https://crates.io/crates/petgraph)? *a lot of repetition all throughout the code* — why do you think so? *since the `Triangle` and `Vertex` structs are not aware of the struct `Geometry`* — why is that a constraint that must be upheld? *so that the `Triangle` and `Vertex` objects can in fact store a reference to one another* — Have you read [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/q/32300132/155423). – Shepmaster Aug 01 '17 at 13:02
  • Do you ever plan to delete Vertex/Triangle or not? And if you do, do you plan to do it in batch or incrementally? – Matthieu M. Aug 01 '17 at 14:29
  • @Shepmaster: I will take a look at Rc, that might be fitting for my purposes. I don't think a graph structure will resolve my problems, but I'll also look into that briefly. Currently, Triangle and Vertex are not aware of Geometry because they are in some sense member objects. Are you saying I could in principle do a borrow of the Geometry object to all member Vertex'es and Triangles? I'll also take a look at your last link and see whether it's relevant for me. Thank you! – JorenB Aug 02 '17 at 10:01
  • @MatthieuM. Vertex'es and Triangles are created and destroyed continuously throughout the simulation, which is the main difficulty. At every Monte Carlo step, only a handful can be created or destroyed (on the order of 5). Why are you asking? – JorenB Aug 02 '17 at 10:03
  • @JorenB: If destruction is infrequent, or batched, then an Arena would have solved the ownership issue (basically, after a batch of deletions, you copy the whole live set to another arena, which is equivalent to a moving GC). This can still work with frequent destruction, but it's not as obvious *when* to make the copy. – Matthieu M. Aug 02 '17 at 11:17

0 Answers0