public static BipartiteDeviceGraph LoadGraph(string filename)
        {
            BipartiteDeviceGraph graph = new BipartiteDeviceGraph();

            StreamReader reader = new StreamReader(filename);

            Dictionary <string, MMDevice> deviceFromID = new Dictionary <string, MMDevice>();

            //create ID dictionary to get the correct MMDevice
            foreach (MMDevice device in new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.All))
            {
                deviceFromID[device.ID] = device;
            }

            if (!int.TryParse(reader.ReadLine(), out int N))
            {
                return(new BipartiteDeviceGraph());
            }

            DeviceControl[] devices = new DeviceControl[N];

            //get array of verteces
            for (int i = 0; i < N; i++)
            {
                try
                {
                    MMDevice device = deviceFromID[reader.ReadLine()];
                    double[] pos    = reader.ReadLine().Split().Select(x => double.Parse(x)).ToArray();

                    DeviceControl control = new DeviceControl(device, graph);
                    control.Left = pos[0];
                    control.Top  = pos[1];
                    MainWindow.GraphMap.Children.Add(control);
                    graph.AddVertex(control);
                    devices[i] = control;
                }
                catch
                {
                    devices[i] = null;
                }
            }

            if (!int.TryParse(reader.ReadLine(), out int M))
            {
                return(new BipartiteDeviceGraph());
            }

            //add edges to graph
            for (int i = 0; i < M; i++)
            {
                int[]         adj  = reader.ReadLine().Split().Select(x => int.Parse(x)).ToArray();
                List <string> data = new List <string>();
                for (int j = 0; j < 8; j++)
                {
                    data.Add(reader.ReadLine());
                }

                DeviceControl capture = devices[adj[0]];
                DeviceControl render  = devices[adj[1]];

                if (capture == null || render == null)
                {
                    continue;
                }

                RepeaterInfo repeater = new RepeaterInfo(capture, render, graph);
                repeater.SetData(data);

                graph.AddEdge(capture, render, repeater);
            }

            reader.Close();

            return(graph);
        }