private SparseArray <float> GetWarmBalancingFactors(SparseArray <float> attraction, out string balanceFileName) { SparseArray <float> balanceFactors = null; if (BalanceFactors.ContainsFileName()) { balanceFileName = BalanceFactors.GetFileName() + CurrentMultiSetIndex + ".bin"; if (File.Exists(balanceFileName)) { balanceFactors = LoadBalanceFactors(balanceFileName); } else { balanceFactors = attraction.CreateSimilarArray <float>(); var flatFactors = balanceFactors.GetFlatData(); // initialize the factors to 1 for (int i = 0; i < flatFactors.Length; i++) { flatFactors[i] = 1.0f; } } } else { balanceFileName = null; } return(balanceFactors); }
public SparseTwinIndex <float> ProcessFlow(SparseArray <float> O, SparseArray <float> D, int[] validIndexes, SparseArray <float> attractionStar = null) { int length = validIndexes.Length; Productions = O; Attractions = D; if (attractionStar == null) { AttractionsStar = D.CreateSimilarArray <float>(); } else { AttractionsStar = attractionStar; } FlowMatrix = Productions.CreateSquareTwinArray <float>(); if (Friction == null) { InitializeFriction(length); } var flatAttractionStar = AttractionsStar.GetFlatData(); float[] oldTotal = new float[flatAttractionStar.Length]; var flatAttractions = Attractions.GetFlatData(); for (int i = 0; i < length; i++) { flatAttractionStar[i] = 1f; oldTotal[i] = flatAttractions[i]; } int iteration = 0; float[] columnTotals = new float[length]; var balanced = false; do { if (ProgressCallback != null) { // this doesn't go to 100%, but that is alright since when we end, the progress // of the calling model should assume we hit 100% ProgressCallback(iteration / (float)MaxIterations); } Array.Clear(columnTotals, 0, columnTotals.Length); if (Vector.IsHardwareAccelerated) { VectorProcessFlow(columnTotals, FlowMatrix.GetFlatData()); } else { ProcessFlow(columnTotals); } balanced = Balance(columnTotals, oldTotal); } while((++iteration) < MaxIterations && !balanced); if (ProgressCallback != null) { ProgressCallback(1f); } return(FlowMatrix); }
private void AverageAttractionAndProduction(ref SparseArray <float> production, ref SparseArray <float> attraction) { var newAttraction = attraction.CreateSimilarArray <float>(); var newProduction = production.CreateSimilarArray <float>(); var flatAttraction = attraction.GetFlatData(); var flatProduction = production.GetFlatData(); var newFlatProduction = newProduction.GetFlatData(); var newFlatAttraction = newAttraction.GetFlatData(); var productionTotal = VectorHelper.Sum(flatProduction, 0, flatProduction.Length); var attractionTotal = VectorHelper.Sum(flatAttraction, 0, flatAttraction.Length); var totalAverage = productionTotal + attractionTotal / 2.0f; var ratio = totalAverage / attractionTotal; if (float.IsNaN(ratio) || float.IsInfinity(ratio)) { ratio = 0.0f; } VectorHelper.Multiply(newFlatAttraction, flatAttraction, ratio); ratio = totalAverage / productionTotal; if (float.IsNaN(ratio) || float.IsInfinity(ratio)) { ratio = 0.0f; } VectorHelper.Multiply(newFlatProduction, flatProduction, 1.0f / ratio); attraction = newAttraction; production = newProduction; }
private void WriteParallel(int[] validZones, SparseArray <IPerson[]> population, StreamWriter writer, int length) { var output = population.CreateSimilarArray <StringBuilder>(); var flatOutput = output.GetFlatData(); var flatPop = population.GetFlatData(); int current = 0; Parallel.For(0, length, delegate(int i) { var popInZone = flatPop[i]; if (popInZone == null) { return; } StringBuilder builder = new StringBuilder(); foreach (var person in popInZone) { builder.Append(validZones[i]); if (person == null) { builder.AppendLine(", PERSON MISSING!"); continue; } builder.Append(','); builder.Append(person.Age); builder.Append(','); builder.Append(person.Household != null ? person.Household.Cars : 0); builder.Append(','); builder.Append(person.SchoolZone != null ? person.SchoolZone.ZoneNumber : -1); builder.Append(','); builder.Append(person.WorkZone != null ? person.WorkZone.ZoneNumber : -1); builder.Append(','); builder.Append(person.EmploymentStatus); builder.Append(','); builder.Append(person.StudentStatus); builder.Append(','); builder.Append(person.Occupation); builder.Append(','); builder.Append(person.DriversLicense ? 1 : 0); builder.Append(','); builder.Append(person.ExpansionFactor); builder.AppendLine(); } flatOutput[i] = builder; Interlocked.Increment(ref current); Progress = (float)current / length; }); for (int i = 0; i < length; i++) { var sbuilder = flatOutput[i]; if (sbuilder != null) { writer.Write(sbuilder.ToString()); } } Progress = 1; }
public SparseTwinIndex<float> ProcessFlow(SparseArray<float> O, SparseArray<float> D, int[] validIndexes, SparseArray<float> attractionStar = null) { int length = validIndexes.Length; Productions = O; Attractions = D; if(attractionStar == null) { AttractionsStar = D.CreateSimilarArray<float>(); } else { AttractionsStar = attractionStar; } FlowMatrix = Productions.CreateSquareTwinArray<float>(); if(Friction == null) { InitializeFriction(length); } var flatAttractionStar = AttractionsStar.GetFlatData(); float[] oldTotal = new float[flatAttractionStar.Length]; var flatAttractions = Attractions.GetFlatData(); for(int i = 0; i < length; i++) { flatAttractionStar[i] = 1f; oldTotal[i] = flatAttractions[i]; } int iteration = 0; float[] columnTotals = new float[length]; var balanced = false; do { if(ProgressCallback != null) { // this doesn't go to 100%, but that is alright since when we end, the progress // of the calling model should assume we hit 100% ProgressCallback(iteration / (float)MaxIterations); } Array.Clear(columnTotals, 0, columnTotals.Length); if(Vector.IsHardwareAccelerated) { VectorProcessFlow(columnTotals, FlowMatrix.GetFlatData()); } else { ProcessFlow(columnTotals); } balanced = Balance(columnTotals, oldTotal); } while((++iteration) < MaxIterations && !balanced); if(ProgressCallback != null) { ProgressCallback(1f); } return FlowMatrix; }
private SparseArray <int> SplitAndClear(int pop, SparseArray <float> splitPercentages, Random rand) { var flatSplitPercentages = splitPercentages.GetFlatData(); var length = flatSplitPercentages.Length; var ret = splitPercentages.CreateSimilarArray <int>(); var flatRet = ret.GetFlatData(); var flatRemainder = new float[length]; float remainderTotal = 0; int total = 0; for (int i = 0; i < length; i++) { float element = (flatSplitPercentages[i] * pop); total += (flatRet[i] = (int)Math.Floor(element)); flatRemainder[i] = element - flatRet[i]; } int notAssigned = pop - total; // Make sure that we do not over assign remainderTotal = notAssigned; for (int i = 0; i < notAssigned; i++) { var randPop = rand.NextDouble() * remainderTotal; float ammountToReduce = 0; int j = 0; for ( ; j < length; j++) { randPop -= (ammountToReduce = flatRemainder[j]); if (randPop <= 0) { remainderTotal -= ammountToReduce; flatRemainder[j] = 0; flatRet[j] += 1; break; } } if (j == length) { for (j = 0; j < length; j++) { if (flatRemainder[j] >= 0) { remainderTotal -= flatRemainder[j]; flatRemainder[j] = 0; flatRet[j] += 1; break; } } } } return(ret); }
private void MatchAttractionToProduction(ref SparseArray <float> production, ref SparseArray <float> attraction) { var newAttraction = attraction.CreateSimilarArray <float>(); var flatAttraction = attraction.GetFlatData(); var flatProduction = production.GetFlatData(); var newFlatAttraction = newAttraction.GetFlatData(); var ratio = VectorHelper.Sum(flatProduction, 0, flatProduction.Length) / VectorHelper.Sum(flatAttraction, 0, flatAttraction.Length); if (float.IsNaN(ratio) || float.IsInfinity(ratio)) { ratio = 0.0f; } VectorHelper.Multiply(newFlatAttraction, flatAttraction, ratio); attraction = newAttraction; }
private void InitializeFlows() { Progress = 0; // we are going to need to split based on this information ZoneArray = Root.ZoneSystem.ZoneArray; var validZones = ZoneArray.ValidIndexies().ToArray(); //Generate the place of work place of residence OD's SparseArray <float> o = ZoneArray.CreateSimilarArray <float>(); SparseArray <float> d = ZoneArray.CreateSimilarArray <float>(); var numCat = Categories.Count; // Start burning that CPU Thread.CurrentThread.Priority = ThreadPriority.Highest; SparseTwinIndex <float> workplaceDistribution = null; SparseTwinIndex <float> prevWorkplaceDistribution = null; float[] friction; float[] nextFriction = null; for (int i = 0; i < numCat; i++) { CurrentOccupationIndex = i; Task assignToPopulation = null; if (i > 0) { assignToPopulation = new Task(delegate { if (prevWorkplaceDistribution != null) { // We actually are assigning to the previous category with this data so we need i - 1 AssignToWorkers(prevWorkplaceDistribution, Categories[i - 1]); prevWorkplaceDistribution = null; } }); assignToPopulation.Start(); } Task computeNextFriction = null; if (i + 1 < numCat) { computeNextFriction = new Task(delegate { nextFriction = ComputeFriction(ZoneArray.GetFlatData(), Categories[i + 1], nextFriction); }); computeNextFriction.Start(); } Categories[i].Generate(o, d); GravityModel gravityModel = new GravityModel(ImpedenceFunction, (progress => Progress = (progress / numCat) + ((float)i / numCat)), Epsilon, MaxIterations); workplaceDistribution = gravityModel.ProcessFlow(o, d, validZones); Progress = ((float)(i + 1) / numCat); if (assignToPopulation != null) { assignToPopulation.Wait(); assignToPopulation.Dispose(); } if (computeNextFriction != null) { computeNextFriction.Wait(); computeNextFriction.Dispose(); } prevWorkplaceDistribution = workplaceDistribution; friction = nextFriction; nextFriction = friction; } nextFriction = null; prevWorkplaceDistribution = null; AssignToWorkers(workplaceDistribution, Categories[numCat - 1]); // ok now we can relax Thread.CurrentThread.Priority = ThreadPriority.Normal; GC.Collect(); }
private void Pass1(SparseArray <IZone> zoneArray, IZone[] zones, int[] basePopulation, int[] zonalDifferences, List <KeyValuePair <int, int> >[] results, List <ITashaHousehold>[] remainingHouseholds, List <int>[] lookupsForRegion) { SparseArray <List <int> > householdsByZoneIndexToRegion = zoneArray.CreateSimilarArray <List <int> >(); SetupSpatialListByElement(householdsByZoneIndexToRegion.GetFlatData()); Console.WriteLine("Preparing household Index"); Parallel.For(0, HouseholdsByZone.Count, (int i) => { var list = householdsByZoneIndexToRegion.GetFlatData()[i]; var total = HouseholdsByZone.GetFlatData()[i].Count; for (int j = 0; j < total; j++) { list.Add(-1); } }); Console.WriteLine("Building household index"); Parallel.For(0, HouseholdsByRegion.Count, (int flatRegionIndex) => { if (flatRegionIndex == 0) { return; } var region = HouseholdsByRegion.GetFlatData()[flatRegionIndex]; var householdIndexArray = householdsByZoneIndexToRegion.GetFlatData(); var householdArray = HouseholdsByZone.GetFlatData(); for (int i = 0; i < region.Count; i++) { var currentHousehold = region[i]; var flatZone = zoneArray.GetFlatIndex(currentHousehold.HomeZone.ZoneNumber); var household = householdArray[flatZone]; var householdIndex = householdIndexArray[flatZone]; int index = household.IndexOf(currentHousehold); householdIndex[index] = i; } }); Console.WriteLine("Starting Pass 1"); Parallel.For(0, HouseholdsByRegion.Count, (int flatRegionIndex) => { if (flatRegionIndex == 0) { return; } var regionNumber = HouseholdsByRegion.GetSparseIndex(flatRegionIndex); var zonesToProcess = zones.Where(z => z.RegionNumber == regionNumber).ToArray(); var regionLookup = HouseholdsByRegion.GetFlatData()[flatRegionIndex]; var remaining = remainingHouseholds[flatRegionIndex]; var resultsForRegion = results[flatRegionIndex]; for (int z = 0; z < zonesToProcess.Length; z++) { int attempts = 0; int flatZone = zoneArray.GetFlatIndex(zonesToProcess[z].ZoneNumber); var householdIndex = householdsByZoneIndexToRegion.GetFlatData()[flatZone]; // the difference is negative so we need to add not subtract int populationToAdd = zonalDifferences[flatZone] >= 0 ? basePopulation[flatZone] : basePopulation[flatZone] + zonalDifferences[flatZone]; var zonalHouseholds = HouseholdsByZone.GetFlatData()[flatZone]; int i = 0; List <int> tossedHouseholds = new List <int>(); for (int pop = 0; pop < populationToAdd;) { if (attempts > 2) { throw new XTMFRuntimeException("In '" + Name + "' we were unable to assign a base population for zone '" + zonesToProcess[z].ZoneNumber + "'!"); } for (i = 0; i < zonalHouseholds.Count; i++) { var hhld = zonalHouseholds[i]; var newPop = pop + hhld.Persons.Length; if (newPop <= populationToAdd) { pop = newPop; resultsForRegion.Add(new KeyValuePair <int, int>(flatZone, householdIndex[i])); if (pop >= populationToAdd) { break; } } else { tossedHouseholds.Add(i); } } attempts++; } // if we didn't use everything add the rest of the households to the remaining list var lookupIndex = lookupsForRegion[flatRegionIndex]; // first add all the households we excluded to finish the zone foreach (var tossed in tossedHouseholds) { remaining.Add(zonalHouseholds[tossed]); lookupIndex.Add(householdIndex[tossed]); } // then add the rest of the households we haven't looked at if (attempts <= 1) { for (; i < zonalHouseholds.Count; i++) { remaining.Add(zonalHouseholds[i]); lookupIndex.Add(householdIndex[i]); } } } }); }
private SparseArray<float> GetWarmBalancingFactors(SparseArray<float> attraction, out string balanceFileName) { SparseArray<float> balanceFactors = null; if ( this.BalanceFactors.ContainsFileName() ) { balanceFileName = this.BalanceFactors.GetFileName() + this.CurrentMultiSetIndex + ".bin"; if ( File.Exists( balanceFileName ) ) { balanceFactors = LoadBalanceFactors( balanceFileName ); } else { balanceFactors = attraction.CreateSimilarArray<float>(); var flatFactors = balanceFactors.GetFlatData(); // initialize the factors to 1 for ( int i = 0; i < flatFactors.Length; i++ ) { flatFactors[i] = 1.0f; } } } else { balanceFileName = null; } return balanceFactors; }
private void WriteParallel(int[] validZones, SparseArray<IPerson[]> population, StreamWriter writer, int length) { var output = population.CreateSimilarArray<StringBuilder>(); var flatOutput = output.GetFlatData(); var flatPop = population.GetFlatData(); int current = 0; Parallel.For( 0, length, delegate(int i) { var popInZone = flatPop[i]; if ( popInZone == null ) return; StringBuilder builder = new StringBuilder(); foreach ( var person in popInZone ) { builder.Append( validZones[i] ); if ( person == null ) { builder.AppendLine( ", PERSON MISSING!" ); continue; } builder.Append( ',' ); builder.Append( person.Age ); builder.Append( ',' ); builder.Append( person.Household != null ? person.Household.Cars : 0 ); builder.Append( ',' ); builder.Append( person.SchoolZone != null ? person.SchoolZone.ZoneNumber : -1 ); builder.Append( ',' ); builder.Append( person.WorkZone != null ? person.WorkZone.ZoneNumber : -1 ); builder.Append( ',' ); builder.Append( (int)person.EmploymentStatus ); builder.Append( ',' ); builder.Append( (int)person.StudentStatus ); builder.Append( ',' ); builder.Append( (int)person.Occupation ); builder.Append( ',' ); builder.Append( person.DriversLicense ? 1 : 0 ); builder.Append( ',' ); builder.Append( person.ExpansionFactor ); builder.AppendLine(); } flatOutput[i] = builder; System.Threading.Interlocked.Increment( ref current ); this.Progress = (float)current / length; } ); for ( int i = 0; i < length; i++ ) { var sbuilder = flatOutput[i]; if ( sbuilder != null ) { writer.Write( sbuilder.ToString() ); } } this.Progress = 1; }
private SparseArray<int> SplitAndClear(int pop, SparseArray<float> splitPercentages, Random rand) { var flatSplitPercentages = splitPercentages.GetFlatData(); var length = flatSplitPercentages.Length; var ret = splitPercentages.CreateSimilarArray<int>(); var flatRet = ret.GetFlatData(); var flatRemainder = new float[length]; float remainderTotal = 0; int total = 0; for ( int i = 0; i < length; i++ ) { float element = ( flatSplitPercentages[i] * pop ); total += ( flatRet[i] = (int)Math.Floor( element ) ); flatRemainder[i] = element - flatRet[i]; } int notAssigned = pop - total; // Make sure that we do not over assign remainderTotal = notAssigned; for ( int i = 0; i < notAssigned; i++ ) { var randPop = rand.NextDouble() * remainderTotal; float ammountToReduce = 0; int j = 0; for ( ; j < length; j++ ) { randPop -= ( ammountToReduce = flatRemainder[j] ); if ( randPop <= 0 ) { remainderTotal -= ammountToReduce; flatRemainder[j] = 0; flatRet[j] += 1; break; } } if ( j == length ) { for ( j = 0; j < length; j++ ) { if ( flatRemainder[j] >= 0 ) { remainderTotal -= flatRemainder[j]; flatRemainder[j] = 0; flatRet[j] += 1; break; } } } } return ret; }