Go to the documentation of this file.00001
00003 #include "../stdafx.h"
00004 #include "demands.h"
00005 #include <list>
00006
00007 typedef std::list<NodeID> NodeList;
00008
00012 class Scaler {
00013 public:
00014 void SetDemands(LinkGraphJob &job, NodeID from, NodeID to, uint demand_forw);
00015 };
00016
00020 class SymmetricScaler : public Scaler {
00021 public:
00027 inline SymmetricScaler(uint mod_size) : mod_size(mod_size), supply_sum(0),
00028 demand_per_node(0)
00029 {}
00030
00035 inline void AddNode(const Node &node)
00036 {
00037 this->supply_sum += node.Supply();
00038 }
00039
00044 inline void SetDemandPerNode(uint num_demands)
00045 {
00046 this->demand_per_node = max(this->supply_sum / num_demands, 1U);
00047 }
00048
00056 inline uint EffectiveSupply(const Node &from, const Node &to)
00057 {
00058 return max(from.Supply() * max(1U, to.Supply()) * this->mod_size / 100 / this->demand_per_node, 1U);
00059 }
00060
00068 inline bool HasDemandLeft(const Node &to)
00069 {
00070 return (to.Supply() == 0 || to.UndeliveredSupply() > 0) && to.Demand() > 0;
00071 }
00072
00073 void SetDemands(LinkGraphJob &job, NodeID from, NodeID to, uint demand_forw);
00074
00075 private:
00076 uint mod_size;
00077 uint supply_sum;
00078 uint demand_per_node;
00079 };
00080
00084 class AsymmetricScaler : public Scaler {
00085 public:
00090 inline void AddNode(const Node &)
00091 {
00092 }
00093
00098 inline void SetDemandPerNode(uint)
00099 {
00100 }
00101
00107 inline uint EffectiveSupply(const Node &from, const Node &)
00108 {
00109 return from.Supply();
00110 }
00111
00118 inline bool HasDemandLeft(const Node &to) { return to.Demand() > 0; }
00119 };
00120
00129 void SymmetricScaler::SetDemands(LinkGraphJob &job, NodeID from_id, NodeID to_id, uint demand_forw)
00130 {
00131 if (job[from_id].Demand() > 0) {
00132 uint demand_back = demand_forw * this->mod_size / 100;
00133 uint undelivered = job[to_id].UndeliveredSupply();
00134 if (demand_back > undelivered) {
00135 demand_back = undelivered;
00136 demand_forw = max(1U, demand_back * 100 / this->mod_size);
00137 }
00138 this->Scaler::SetDemands(job, to_id, from_id, demand_back);
00139 }
00140
00141 this->Scaler::SetDemands(job, from_id, to_id, demand_forw);
00142 }
00143
00152 inline void Scaler::SetDemands(LinkGraphJob &job, NodeID from_id, NodeID to_id, uint demand_forw)
00153 {
00154 job[from_id].DeliverSupply(to_id, demand_forw);
00155 }
00156
00162 template<class Tscaler>
00163 void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler)
00164 {
00165 NodeList supplies;
00166 NodeList demands;
00167 uint num_supplies = 0;
00168 uint num_demands = 0;
00169
00170 for (NodeID node = 0; node < job.Size(); node++) {
00171 scaler.AddNode(job[node]);
00172 if (job[node].Supply() > 0) {
00173 supplies.push_back(node);
00174 num_supplies++;
00175 }
00176 if (job[node].Demand() > 0) {
00177 demands.push_back(node);
00178 num_demands++;
00179 }
00180 }
00181
00182 if (num_supplies == 0 || num_demands == 0) return;
00183
00184
00185
00186
00187 scaler.SetDemandPerNode(num_demands);
00188 uint chance = 0;
00189
00190 while (!supplies.empty() && !demands.empty()) {
00191 NodeID from_id = supplies.front();
00192 supplies.pop_front();
00193
00194 for (uint i = 0; i < num_demands; ++i) {
00195 assert(!demands.empty());
00196 NodeID to_id = demands.front();
00197 demands.pop_front();
00198 if (from_id == to_id) {
00199
00200 if (demands.empty() && supplies.empty()) return;
00201
00202 demands.push_back(to_id);
00203 continue;
00204 }
00205
00206 int32 supply = scaler.EffectiveSupply(job[from_id], job[to_id]);
00207 assert(supply > 0);
00208
00209
00210 int32 distance = this->max_distance - (this->max_distance -
00211 (int32)job[from_id][to_id].Distance()) * this->mod_dist / 100;
00212
00213
00214 int32 divisor = this->accuracy * (this->mod_dist - 50) / 100 +
00215 this->accuracy * distance / this->max_distance + 1;
00216
00217 assert(divisor > 0);
00218
00219 uint demand_forw = 0;
00220 if (divisor <= supply) {
00221
00222
00223
00224 demand_forw = supply / divisor;
00225 } else if (++chance > this->accuracy * num_demands * num_supplies) {
00226
00227
00228 demand_forw = 1;
00229 }
00230
00231 demand_forw = min(demand_forw, job[from_id].UndeliveredSupply());
00232
00233 scaler.SetDemands(job, from_id, to_id, demand_forw);
00234
00235 if (scaler.HasDemandLeft(job[to_id])) {
00236 demands.push_back(to_id);
00237 } else {
00238 num_demands--;
00239 }
00240
00241 if (job[from_id].UndeliveredSupply() == 0) break;
00242 }
00243
00244 if (job[from_id].UndeliveredSupply() != 0) {
00245 supplies.push_back(from_id);
00246 } else {
00247 num_supplies--;
00248 }
00249 }
00250 }
00251
00256 DemandCalculator::DemandCalculator(LinkGraphJob &job) :
00257 max_distance(DistanceMaxPlusManhattan(TileXY(0,0), TileXY(MapMaxX(), MapMaxY())))
00258 {
00259 const LinkGraphSettings &settings = job.Settings();
00260 CargoID cargo = job.Cargo();
00261
00262 this->accuracy = settings.accuracy;
00263 this->mod_dist = settings.demand_distance;
00264 if (this->mod_dist > 100) {
00265
00266 int over100 = this->mod_dist - 100;
00267 this->mod_dist = 100 + over100 * over100;
00268 }
00269
00270 switch (settings.GetDistributionType(cargo)) {
00271 case DT_SYMMETRIC:
00272 this->CalcDemand<SymmetricScaler>(job, SymmetricScaler(settings.demand_size));
00273 break;
00274 case DT_ASYMMETRIC:
00275 this->CalcDemand<AsymmetricScaler>(job, AsymmetricScaler());
00276 break;
00277 default:
00278
00279 break;
00280 }
00281 }