// No Cache
        private void GetFeatureMatrixNoCache(FeatureIndexSet indexes, List<Vector<double>[]> vectors)
        {
            IList<FeatureSet> list = null;

            if (indexes.Indexes != null)
            {
                list = new List<FeatureSet>(indexes.Indexes.Count);
                foreach (int idx in indexes.Indexes)
                {
                    try
                    {
                        list.Add(DataFeatureProvider[idx]);
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidOperationException("Cannot retrive item '" + idx + "' from " + DataFeatureProvider + ". See inner exception for details.", ex);
                    }
                }
            }
            else // if (indexes.IndexRange != null)
            {
                try
                {
                    list = DataFeatureProvider.GetItems(indexes.IndexRange.Value.MinValue, indexes.IndexRange.Value.MaxValue + 1);
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException("Cannot retrive items '" + indexes.IndexRange + "' from " + DataFeatureProvider + ". See inner exception for details.", ex);
                }
            }

            Debug.Assert(list.Count == vectors.Capacity);

            foreach (var set in list) vectors.Add(GetFeatureVectorsOf(set));
        }
        private FeatureMatrix GetFeatureMatrixInternal(FeatureIndexSet indexes)
        {
            Contract.Requires(!indexes.IsEmpty);

            var vectors = new List<Vector<double>[]>(indexes.Count);
            var cache = VectorCache.Cache;

            if (cache == null)
            {
                GetFeatureMatrixNoCache(indexes, vectors);
            }
            else
            {
                GetFeatureMatrixCache(indexes, vectors, cache);
            }

            if (indexes.Randomize) vectors = vectors.OrderByRandom().ToList();

            return ToFeatureMatrix(vectors);
        }
        // Cache
        private void GetFeatureMatrixCache(FeatureIndexSet indexes, List<Vector<double>[]> vectors, ICache cache)
        {
            //var sl = new SpinLock();
            //Parallel.ForEach(indexes, (index) =>
            //{
            //    string key = index.ToString() + uid;
            //    var cv = cache[key] as Vector<double>[];

            //    if (cv == null)
            //    {
            //        cv = GetFeatureVectorsOf(RetrieveFeatureSet(index));
            //        cache.Add(key, cv);
            //    }

            //    bool taken = false;
            //    try
            //    {
            //        sl.Enter(ref taken);
            //        vectors.Add(cv);
            //    }
            //    finally
            //    {
            //        if (taken) sl.Exit();
            //    }
            //});

            foreach (int index in indexes)
            {
                string key = index.ToString() + uid;
                var cv = cache[key] as Vector<double>[];

                if (cv != null)
                {
                    vectors.Add(cv);
                }
                else
                {
                    cv = GetFeatureVectorsOf(RetrieveFeatureSet(index));
                    cache.Add(key, cv);
                    vectors.Add(cv);
                }
            }
        }
        public FeatureMatrix GetFeatureMatrix(FeatureIndexSet indexes)
        {
            Contract.Requires(!indexes.IsEmpty);
            Contract.Ensures(Contract.Result<FeatureMatrix>() != null);

            lock (SyncRoot)
            {
                // Ensure initialization
                InitializeLocked();

                return GetFeatureMatrixInternal(indexes);
            }
        }