/// <summary>
        /// Takes an INetworkMatrix instance and composes a new INetworkMatrix instance composed of only the collection of
        /// nodes given by memberNodeIds.  Cost of method is (n^2 + n), where n = memberNodesIds.Count.
        /// </summary>
        /// <param name="socialNetworkMatrix">The social network to be searched.</param>
        /// <param name="memberNodeIds">The collection of node IDs to be included in the subnetwork.</param>
        /// <returns>A tuple composed of the new subnetwork, a map of original node IDs to new node IDs, and an inverse map of
        /// new node IDs to original node IDs.</returns>
        private static Tuple<INetworkMatrix, IDictionary<int, int>, IDictionary<int, int>> CreateSubnetworkFromNodeIds(INetworkMatrix socialNetworkMatrix, ICollection<int> memberNodeIds)
        {
            var subnetwork = NetworkMatrixFactory.CreateModifiableMatrix(memberNodeIds.Count);
            var map = new Dictionary<int, int>(memberNodeIds.Count);
            var inverseMap = new Dictionary<int, int>(memberNodeIds.Count);
            var i = 1;

            foreach (var nodeId in memberNodeIds)
            {
                map.Add(nodeId, i);
                inverseMap.Add(i, nodeId);

                i++;
            }

            foreach (var nodeId in memberNodeIds)
            {
                var mappedNodeId = map[nodeId];

                foreach (var relatedNodeId in socialNetworkMatrix.GetNodeById(nodeId).RelatedNodes)
                {
                    // relationships to nodes not defined in the subnetwork are ignored
                    if (map.ContainsKey(relatedNodeId))
                        subnetwork.RelateNodes(mappedNodeId, map[relatedNodeId]);
                }
            }

            return new Tuple<INetworkMatrix, IDictionary<int, int>, IDictionary<int, int>>(subnetwork, map, inverseMap);
        }