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:
00017 Scaler() : demand_per_node(0) {}
00018
00019 void SetDemands(LinkGraphJob &job, NodeID from, NodeID to, uint demand_forw);
00020
00021 protected:
00022 uint demand_per_node;
00023 };
00024
00028 class SymmetricScaler : public Scaler {
00029 public:
00035 inline SymmetricScaler(uint mod_size) : mod_size(mod_size), supply_sum(0)
00036 {}
00037
00042 inline void AddNode(const Node &node)
00043 {
00044 this->supply_sum += node.Supply();
00045 }
00046
00051 inline void SetDemandPerNode(uint num_demands)
00052 {
00053 this->demand_per_node = max(this->supply_sum / num_demands, 1U);
00054 }
00055
00063 inline uint EffectiveSupply(const Node &from, const Node &to)
00064 {
00065 return max(from.Supply() * max(1U, to.Supply()) * this->mod_size / 100 / this->demand_per_node, 1U);
00066 }
00067
00075 inline bool HasDemandLeft(const Node &to)
00076 {
00077 return (to.Supply() == 0 || to.UndeliveredSupply() > 0) && to.Demand() > 0;
00078 }
00079
00080 void SetDemands(LinkGraphJob &job, NodeID from, NodeID to, uint demand_forw);
00081
00082 private:
00083 uint mod_size;
00084 uint supply_sum;
00085 };
00086
00090 class AsymmetricScaler : public Scaler {
00091 public:
00095 inline AsymmetricScaler() : demand_sum(0) {}
00096
00101 inline void AddNode(const Node &node)
00102 {
00103 this->demand_sum += node.Demand();
00104 }
00105
00110 inline void SetDemandPerNode(uint num_demands)
00111 {
00112 this->demand_per_node = max(this->demand_sum / num_demands, (uint)1);
00113 }
00114
00121 inline uint EffectiveSupply(const Node &from, const Node &to)
00122 {
00123 return max(from.Supply() * to.Demand() / this->demand_per_node, (uint)1);
00124 }
00125
00132 inline bool HasDemandLeft(const Node &to) { return to.Demand() > 0; }
00133
00134 private:
00135 uint demand_sum;
00136 };
00137
00146 void SymmetricScaler::SetDemands(LinkGraphJob &job, NodeID from_id, NodeID to_id, uint demand_forw)
00147 {
00148 if (job[from_id].Demand() > 0) {
00149 uint demand_back = demand_forw * this->mod_size / 100;
00150 uint undelivered = job[to_id].UndeliveredSupply();
00151 if (demand_back > undelivered) {
00152 demand_back = undelivered;
00153 demand_forw = max(1U, demand_back * 100 / this->mod_size);
00154 }
00155 this->Scaler::SetDemands(job, to_id, from_id, demand_back);
00156 }
00157
00158 this->Scaler::SetDemands(job, from_id, to_id, demand_forw);
00159 }
00160
00169 inline void Scaler::SetDemands(LinkGraphJob &job, NodeID from_id, NodeID to_id, uint demand_forw)
00170 {
00171 job[from_id].DeliverSupply(to_id, demand_forw);
00172 }
00173
00179 template<class Tscaler>
00180 void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler)
00181 {
00182 NodeList supplies;
00183 NodeList demands;
00184 uint num_supplies = 0;
00185 uint num_demands = 0;
00186
00187 for (NodeID node = 0; node < job.Size(); node++) {
00188 scaler.AddNode(job[node]);
00189 if (job[node].Supply() > 0) {
00190 supplies.push_back(node);
00191 num_supplies++;
00192 }
00193 if (job[node].Demand() > 0) {
00194 demands.push_back(node);
00195 num_demands++;
00196 }
00197 }
00198
00199 if (num_supplies == 0 || num_demands == 0) return;
00200
00201
00202
00203
00204 scaler.SetDemandPerNode(num_demands);
00205 uint chance = 0;
00206
00207 while (!supplies.empty() && !demands.empty()) {
00208 NodeID from_id = supplies.front();
00209 supplies.pop_front();
00210
00211 for (uint i = 0; i < num_demands; ++i) {
00212 assert(!demands.empty());
00213 NodeID to_id = demands.front();
00214 demands.pop_front();
00215 if (from_id == to_id) {
00216
00217 if (demands.empty() && supplies.empty()) return;
00218
00219 demands.push_back(to_id);
00220 continue;
00221 }
00222
00223 int32 supply = scaler.EffectiveSupply(job[from_id], job[to_id]);
00224 assert(supply > 0);
00225
00226
00227 int32 distance = this->max_distance - (this->max_distance -
00228 (int32)job[from_id][to_id].Distance()) * this->mod_dist / 100;
00229
00230
00231 int32 divisor = this->accuracy * (this->mod_dist - 50) / 100 +
00232 this->accuracy * distance / this->max_distance + 1;
00233
00234 assert(divisor > 0);
00235
00236 uint demand_forw = 0;
00237 if (divisor <= supply) {
00238
00239
00240
00241 demand_forw = supply / divisor;
00242 } else if (++chance > this->accuracy * num_demands * num_supplies) {
00243
00244
00245 demand_forw = 1;
00246 }
00247
00248 demand_forw = min(demand_forw, job[from_id].UndeliveredSupply());
00249
00250 scaler.SetDemands(job, from_id, to_id, demand_forw);
00251
00252 if (scaler.HasDemandLeft(job[to_id])) {
00253 demands.push_back(to_id);
00254 } else {
00255 num_demands--;
00256 }
00257
00258 if (job[from_id].UndeliveredSupply() == 0) break;
00259 }
00260
00261 if (job[from_id].UndeliveredSupply() != 0) {
00262 supplies.push_back(from_id);
00263 } else {
00264 num_supplies--;
00265 }
00266 }
00267 }
00268
00273 DemandCalculator::DemandCalculator(LinkGraphJob &job) :
00274 max_distance(MapSizeX() + MapSizeY() - 2)
00275 {
00276 const LinkGraphSettings &settings = job.Settings();
00277 CargoID cargo = job.Cargo();
00278
00279 this->accuracy = settings.accuracy;
00280 this->mod_dist = settings.demand_distance;
00281 if (this->mod_dist > 100) {
00282
00283 int over100 = this->mod_dist - 100;
00284 this->mod_dist = 100 + over100 * over100;
00285 }
00286
00287 switch (settings.GetDistributionType(cargo)) {
00288 case DT_SYMMETRIC:
00289 this->CalcDemand<SymmetricScaler>(job, SymmetricScaler(settings.demand_size));
00290 break;
00291 case DT_ASYMMETRIC:
00292 this->CalcDemand<AsymmetricScaler>(job, AsymmetricScaler());
00293 break;
00294 default:
00295
00296 break;
00297 }
00298 }