LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sn_remove_class.h File Reference

Drop one job class from a model, port of ModelAdapter.removeClass. More...

#include <cstddef>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "line/lang/lang_types.h"
#include "line/lang/qn/network_struct.h"
#include "line/num/number.h"
#include "line/util/error.h"
#include "line/util/matrix.h"
Include dependency graph for sn_remove_class.h:

Go to the source code of this file.

Namespaces

namespace  line
namespace  line::api

Functions

template<class T>
qn::NetworkStruct< T > line::api::sn_remove_class (const qn::NetworkStruct< T > &sn, std::size_t cls)
 The model without class cls (1-based), leaving sn untouched.
template<class T>
qn::NetworkStruct< T > line::api::sn_remove_class (const qn::NetworkStruct< T > &sn, const std::string &name)
 The same, naming the class.

Detailed Description

Drop one job class from a model, port of ModelAdapter.removeClass.

The reference is matlab/src/lang/@@MNetwork/removeClass.m (the mutating form) with matlab/src/io/@@ModelAdapter/removeClass.m as its non-mutating wrapper; the JAR twins are Network.removeClass / Network.withoutClass and the python ones Network.remove_class / Network.without_class. This port has only the NON-MUTATING form, because a NetworkStruct is a value here rather than a handle: V = sn_remove_class(sn, r) leaves sn intact, which is what withoutClass buys the reference, and a caller who wants the mutating form assigns over its own struct.

WHAT IT IS FOR. Ablation studies (solve the model without class r and read off what r was contributing) and per-chain decomposition, where one class is peeled at a time. Both need the REST of the model to stay solvable, which is why every per-class table has to be re-indexed rather than merely blanked.

WHY THIS IS A SLICE AND NOT A DELETION. Every per-class table in the struct is POSITIONAL: service[i][r], st.schedparam[r], nd.routing[r], the (K x K) matrix of a ClassSwitch, the (r,s) key of a routing block. Blanking entry r and leaving the tables at width K would leave a model whose class list is one shorter than the tables that index it, and the refresh would then read class r+1's service under class r's name. That is the same defect the reference hit from the other side – MATLAB's removeClass used to leave the (K x K) class-switching mask at its old size, and refreshRoutingMatrix indexed sn.refstat out of range on the next getStruct – so every table is sliced here and the struct is then re-refreshed from the sliced stage-one data.

ONLY STAGE-ONE DATA IS TOUCHED. network_builder.h states the split: stage one constructs, stage two (refresh_*) derives. So this file slices the constructed tables (classes, service, the station and node per-class vectors, the ClassSwitch matrices, the routing blocks) and then calls refresh_struct(), which re-derives rates, scv, disabled, chains, inchain, visits, cap, rt, rtnodes and the rest at the new width. Nothing derived is patched by hand, so no derived field can be left stale.

WHAT IS REFUSED, and why refusing beats slicing. The reference removes a class from five node kinds (Node, Station, ServiceStation, Source, ClassSwitch) and REFUSES on a Cache, whose item state is indexed by class and lives in the model state rather than in the node. This port keeps that refusal verbatim and adds one for every other construct that carries a class INDEX in something other than a plain per-class vector – a fork's per-class matrices, a transition's modes, a region's per-class caps, a retrial or polling or PAS block, a signal's target class, a class-dependent scaling function whose argument is a population vector of width K. Those cannot be re-indexed by slicing, and slicing around them would hand back a model that looks well formed and is not. tag_chain refuses the same way and for the same reason.

ARITHMETIC: none. Structural.

Definition in file sn_remove_class.h.