Curso de NS Rainer R. P. Couto ([email protected]) Sumário Arquitetura do Software Hierarquia de Objetos Principais Classes em OTcl e C++ Escalonador Temporizadores – Timers Geração de números aleatórios Arquitetura do software Arquitetura do Software Tcl “system language” Fortemente tipada “Core programming” OTcl TclCL C/C++ Componentes de rede Tcl C/C++ Tcl orientado a objetos TclCL (TclCLass) OTcl Tcl com suporte a “object oriented split-level programming” ns-2 Escalonador de eventos “script language” Fracamente tipada Configuração Estrutura Interna Arquitetura do NS Orientado a objetos Escrito em C++ Interpretador Tcl como Arquitetura do NS frontend Hierarquia C++ (compilada) Hierarquia OTcl (interpretada) Correspodência um para um pela perspectiva do usuário Pure OTcl objects Pure C++ objects C++ Duas hierarquias de objetos C++/OTcl split objects ns OTcl Split-level programming Por que duas linguagens? C++: execução rápida / alteração complexa OTcl: alteração simples / execução lenta + – Processamento de cada pacote, alteração de comportamento de objetos existentes em C++ (“dado”), estruturas e algotirmos complexos, código com alterações infreqüentes Configuração, setup, escalonamento de eventos periódicos e manipulação simples de objetos (“controle”), código com alterações freqüentes Tclcl provê a forma de unir as duas linguagens Compromisso entre composabilidade e velocidade Aprendizado e correção de erros grande Tamanho do programa complexidade C/C++ pequeno OTcl split objects Instructions/Statement O Mérito do OTcl 1000 Visual Basic 100 Tcl/Perl 10 Java Assembly 1 None Granularidade do código/script pode ser ajustada para compensar extensibilidade por performance. C C++ Degree of Typing John Ousterhout. Scripting: Higher-level programming for the 21st century IEEE Computer, 1998. Strong Principais classes da programação C++/OTcl Raiz da hierarquia de objetos do ns-2 TclObject TclClass Tcl bind(): realiza o “link” dos valores das variáveis compartilhadas entre C++ e OTcl command(): realiza o “link” entre métodos chamados no OTcl e implementados em C++ Cria e inicializa TclObject’s Métodos C++ para acessar o interpretador Tcl TclCommand Comandos globais EmbeddedTcl Inicialização do script ns Principais classes da programação C++/OTcl Raiz da hierarquia de objetos do ns-2 TclObject TclClass Tcl bind(): realiza o “link” dos valores das variáveis compartilhadas entre C++ e OTcl command(): realiza o “link” entre métodos chamados no OTcl e implementados em C++ Cria e inicializa TclObject’s Métodos C++ para acessar o interpretador Tcl TclCommand Comandos globais EmbeddedTcl Inicialização do script ns TclObject: Hierarquia e Shadowing TclObject Hierarquia de classes OTcl Hierarquia de TclObject classes C++ Agent Agent Agent/TCP TcpAgent _o123 Agent/TCP OTcl Objeto shadow *tcp Objeto Agent/TCP C++ TclObject::bind() “Une” variáveis membras de classes no C++ a variáveis no OTcl Duas referências para um mesmo objeto C++ TcpAgent::TcpAgent() { bind(“window_”, &wnd_); bind_bw(“taxa_", &taxa_); } bind_time(), bind_bool(), bind_bw() OTcl set tcp [new Agent/TCP] $tcp set window_ 200 $tcp set taxa_ 1.5Mb Inicialização de variáveis do “bind” Inicialização através de variáveis de classe do OTcl Agent/TCP set window_ 50 Faça toda a inicialização de variáveis de “bind” em ~ns/tcl/lib/ns-default.tcl Caso contrário, um aviso de alerta será mostrado quando o objeto “shadow” for criado Implementação de variáveis de “bind” Classe InstVar Um objeto por variável de “bind” – caro! InstVarInt, InstVarReal, ... Criados por TclObject::bind() Cria instância da variável na pilha OTcl Habilita “trap” de escrita/leitura para variável OTcl Conecta à variável C++ na ocorrência de “traps” TclObject::command() Implementa métodos do OTcl em C++ “Trap point”: Método cmd{} em OTcl Após chamado, cmd{} envia todos seus argumentos para TclObject::command() TclObject::command() OTcl set tcp [new Agent/TCP] $tcp advance 10 C++ int TcpAgent::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], “advance”) == 0) { int newseq = atoi(argv[2]); …… return(TCL_OK); } } return (Agent::command(argc, argv); } TclObject::command() $tcp send procedimento não existe OTcl space TclObject::unknown{} C++ space TcpAgent::command() Sim Processa e retorna implementa “send”? $tcp cmd send Não Chama o método do pai: return Agent::command() TclObject: Criação e Remoção Procedimentos globais: new{}, delete{} Exemplo set tcp [new Agent/TCP] … delete $tcp TclObject: Criação e Remoção construtor Agent/TCP chama cons_ trutor do pai completa inicialização construtor pai (Agent) chama cons_ trutor do pai completa Qual objeto C++ inicialização deve ser criado? construtor TclObject cria objeto C++ cria objeto shadow OTcl – TclClass construtor TclObject (C++) construtor pai (Agent) construtor AgentTCP Não faz nada, retorna chama cons_ trutor do pai realiza binds e retorna chama cons_ trutor do pai realiza binds e retorna OTcl C++ Principais classes da programação C++/OTcl Raiz da hierarquia de objetos do ns-2 TclObject TclClass Tcl bind(): realiza o “link” dos valores das variáveis compartilhadas entre C++ e OTcl command(): realiza o “link” entre métodos chamados no OTcl e implementados em C++ Cria e inicializa TclObject’s Métodos C++ para acessar o interpretador Tcl TclCommand Comandos globais EmbeddedTcl Inicialização do script ns TclClass C++ TclObject NsObject Agent TcpAgent Static class TcpClass OTcl : public TclClass { public: TcpClass() : TclClass(“Agent/TCP”) {} TclObject TclObject* create(int, const char*const*) { return (new TcpAgent()); ?? } } class_tcp; Agent Agent/TCP TclClass: Mecanismo Inicialização durante o “startup” da execução TcpClass::bind() TclClass::init() para cada TclClass definida estaticamente e.g. SplitObject::register{} Cria e registra Classe OTcl Agent/TCP Agent/TCP::create-shadow{} TclClass::create_shadow() Principais classes da programação C++/OTcl Raiz da hierarquia de objetos do ns-2 TclObject TclClass Tcl bind(): realiza o “link” dos valores das variáveis compartilhadas entre C++ e OTcl command(): realiza o “link” entre métodos chamados no OTcl e implementados em C++ Cria e inicializa TclObject’s Métodos C++ para acessar o interpretador Tcl TclCommand Comandos globais EmbeddedTcl Inicialização do script ns Classe Tcl Classe que possui a referência para o interpretador Tcl Uso Chamar procedimentos em OTcl Obter resultados de expressões em OTcl Passar um resultado para o OTcl Retornar um código de sucesso/falha para o Otcl Armazenar e realizar procuras por referências a TclObjects Obtendo uma referência para o interpretador Uma única referência ao intepretador está declarado no arquivo Tcl.cc (dentro do diretório tclclXXX) como um membro estático da classe Tcl. Antes de acessar qualquer método do intepretador, devemos obter essa referência. Comando Tcl& tcl = Tcl::instance(); Passandos comandos para o interpretador Tcl::eval(char *): passa string para o intepretador Tcl::evalc(const char *): preserva o string de entrada Tcl::eval(): supõe que o comando já está em tcl.buffer Tcl::evalf(char *, par1, par2, ...): “printf like” Exemplo: Tcl& tcl = Tcl::instance(); char wrk[128]; strcpy(wrk, "Simulator set NumberInterfaces_ 1"); tcl.eval(wrk); sprintf(tcl.buffer(), "Agent/SRM set requestFunction_ %s", "Fixed"); tcl.eval(); tcl.evalc("puts stdout \”hello world\”"); tcl.evalf("%s request %d %d", name_, sender, msgid); Coletando resultados Quanto o intepretador chama um comando em C++, espera-se um resultado na variável interna result. Comando: tcl.resultf() Similarmente, quando o C++ faz uma chamada a um método do interpretador, o resultado pode ser acessado através da mesma variável. Comando: tcl.result() Exemplo de métodos de Tcl Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], “now”) == 0) { tcl.resultf(“%g”, clock()); return TCL_OK; } tcl.error(“command not found”); return TCL_ERROR; } else if (argc == 3) { tcl.eval(argv[2]); clock_ = atof(tcl.result()); return TCL_OK; } Funções de Hash da classe Tcl O intepretador possui uma tabela hash com entradas para todos TclObjects criados durante a simulação. void Tcl::enter(TclObject* o) Utilizado para criar uma nova entrada para o novo TclObject TclObject* Tcl::lookup(const char* name) Utilizado para fazer uma procura por um TclObject Principais classes da programação C++/OTcl Raiz da hierarquia de objetos do ns-2 TclObject TclClass Tcl bind(): realiza o “link” dos valores das variáveis compartilhadas entre C++ e OTcl command(): realiza o “link” entre métodos chamados no OTcl e implementados em C++ Cria e inicializa TclObject’s Métodos C++ para acessar o interpretador Tcl TclCommand Comandos globais EmbeddedTcl Inicialização do script ns Class TclCommand Implementação em C++ de comandos globais em OTcl class RandomCommand : public TclCommand { public: RandomCommand() : TclCommand("ns-random") {} virtual int command(int argc, const char*const* argv); }; int RandomCommand::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 1) { ... } } Inicializar um novo objeto – new RandomCommand() – em misc.cc::init_misc Principais classes da programação C++/OTcl Raiz da hierarquia de objetos do ns-2 TclObject TclClass Tcl bind(): realiza o “link” dos valores das variáveis compartilhadas entre C++ e OTcl command(): realiza o “link” entre métodos chamados no OTcl e implementados em C++ Cria e inicializa TclObject’s Métodos C++ para acessar o interpretador Tcl TclCommand Comandos globais EmbeddedTcl Inicialização do script ns EmbeddedTcl Carrega OTcl scripts durante a inicialização do ns Carrega recursivamente ~ns/tcl/lib/ns-lib.tcl: source ns-autoconf.tcl source ns-address.tcl source ns-node.tcl ....... Carrega tudo em um único vetor de caracteres em C++ Executa esse string durante a inicialização EmbeddedTcl Como funciona tcl2c++: provido pelo TclCL, converte tcl scripts em vetores estáticos de caracteres em C++ Makefile.in: tclsh8.0 bin/tcl-expand.tcl tcl/lib/ns-lib.tcl | tcl2c++ et_ns_lib > gen/ns_tcl.cc Resumo TclObject TclClass Classe raiz das hierarquias compilada (C++) e interpretada (OTcl) Acesso transparente (chamadas de procedimento e acesso de variáveis) entre OTcl e C++ Mecanismo que torna possível TclObject Tcl Primitivas para acessar o interpretador Tcl Escalonador Utilizando-se o NS... Criação do simulador set ns [new Simulator] Escalonador de eventos [Habilitação do tracing] Criação da rede Configuração do roteamento ... # [Turn on tracing] # Create topology # Setup packet loss, link dynamics # Create routing agents # Create: # - multicast groups # - protocol agents # - application and/or setup traffic sources # Post-processing procs # Start simulation Escalonador O que é o escalonador? Controlador de eventos dentro do simulador Arquivos correspondentes: tcl/lib/ns-lib.tcl (class Simulator) common/scheduler(.h,.cc) (class Scheduler) heap.h (class Heap) Modelo do escalonador Modela mundo como eventos Simulador possui uma lista de eventos Processo: pega o primeiro evento da lista, executa até estar completo Cada evento acontece em um determinado instante do tempo virtual (tempo simulado), mas pode levar um tempo real arbitrátio Implementação muito simples uma thread de controle => não precisamos nos preocupar com condições de corrida ou “locking” (bem simples) Escalonador de Eventos time_, uid_, next_, handler_ head_ -> handler_ -> handle() insert time_, uid_, next_, handler_ class Event { class Handler { public: public: Event* next_; /* event list */ virtual void handle(Event* event) = 0; Handler* handler_; /* handler to call when event }; ready */ double time_; /* time at which event is ready */ scheduler_uid_t uid_; /* unique ID */ Event() : time_(0), uid_(0) {} }; Modelo do escalonador Modelo de filas simplificado: t=1 t=1.01 Considere dois nodos em uma rede Ethernet A coloca um pacote na fila da LAN LAN retira o pacote da fila e LAN e dispara um evento de recepção em B Modelo CSMA/CD detalhado: A B t=1.0 A envia pacote para NIC; NIC de A inicia “carrier sense” t=1.005 NIC de A conclui cs, inicia tx t=1.006 NIC de B começa a recepção do pacote t=1.01 NIC de B conclui recepção do pacote NIC de B passa pacote para agente/aplicação Criação do escalonador Criação do simulador de eventos set ns [new Simulator] Escalonamento de eventos $ns at <tempo> <evento> <evento>: qualquer comando legítimo no ns/tcl Ex: $ns at 5.0 “finish” Início da execução do escalonador $ns run Escalonador Calendar: default Escalonador Real-time Sincroniza com tempo real Emulação de redes set ns_ [new Simulator] $ns_ use-scheduler Heap $ns_ at 300.5 “$self halt” Simulador - métodos Simulator instproc use-scheduler type { $self instvar scheduler_ if [info exists scheduler_] { if { [$scheduler_ info class] == "Scheduler/$type" } { return } else { delete $scheduler_ } } set scheduler_ [new Scheduler/$type] $scheduler_ now } Simulator instproc at args { Simulator instproc run {} { $self instvar scheduler_ ... return [eval $scheduler_ at $args] return [$scheduler_ run] } } Simulator instproc init args { $self instvar useasim_ ..._ set slinks_(0:0) 0 ... $self create_packetformat $self use-scheduler Calendar #$self use-scheduler List ... } Escalonador - Tipos ListScheduler Lista simples O(N) HeapScheduler Baseado em um Heap O(logN) CalendarScheduler Baseado em Hash O(1) SplayScheduler RealTimerScheduler Modos do escalonador Modo interativo Modo batch: arara:/ns-> ns % set ns [new Simulator] _o3 % $ns at 1 “puts \“Hello World!\”” 1 % $ns at 1.5 “exit” 2 % $ns run Hello World! arara:/ns-> simple.tcl set ns [new Simulator] $ns at 1 “puts \“Hello World!\”” $ns at 1.5 “exit” $ns run arara:/ns-> ns simple.tcl Hello World! arara:/ns-> Temporizadores – Timers Temporizadores – Timers O que é um temporizador? Usado principalmente em agentes, mas pode ser utilizado em outros objetos Um temporizador (timer) é um elemento que dispara um determinado evento e que pode ser programado Ex: retransmissão no agente TCP Temporizadores podem ser implementados em C++ ou em OTcl. São baseados em uma classe abstrata definida em timer- handler.h Em OTcl um temporizador pode ser criado derivando a classe definida em tcl/mcast/timer.tcl. Temporizadores – Funções e atributos A classe abstrata TimerHandler contém os seguintes métodos públicos disponíveis: void sched(double delay) void resched(double delay) Re-escalona o temporizador (similar ao sched, mas o temporizador pode estar pendente) void cancel() Escalona um temporizador para disparar em “delay” segundos Cancela um temporizador pendente int status() Retorna o status do temporizador (TIMER_IDLE, TIMER_PENDING, ou TIMER_HANDLING) Temporizadores – Funções e atributos A classe abstrata TimerHandler contém os seguintes métodos protegidos disponíveis: virtual void expire (Event* e) = 0 virtual void handle (Event* e) Consome um evento; faz um chamada para expire() e atribui o valor adequado a status_ int status_ Este método deve ser preenchido com o código a ser executado no instante de disparo do evento Variável que mantém o atual status do temporizador Event event_ Evento que deve ser consumido Temporizadores – Funções e atributos O método virtual expire() deve ser defindo na classe derivada da classe abstrata Dois métodos privados “inline” são definidos: inline void _sched(double delay) inline void _cancel() { (void)Scheduler::instance().schedule(this, &event_, delay); } { (void)Scheduler::instance().cancel(&event_); } Esses códigos utilizam diretamente métodos do escalonador. Definindo um Temporizador class MyTimer : public TimerHandler { public: MyTimer(MyAgentClass *a) : TimerHandler() { a_ = a; } virtual double expire(Event *e); protected: MyAgentClass *a_; }; double MyTimer::expire(Event *e) { // executa a função // Opção 1: // =\> não re-escalona o temporizador // Opção 2: // =\> re-escalona temporizador para // =\> disparar novamente em “delay” // =\> segundos } Temporizadores criados em C++ não são diretamente acessíveis através do Otcl. Geralmente um temporizador será uma classe amiga da classe agente onde se encontra ou expire() chamará um método público deste agente. Exemplo – Retransmissão no TCPclass RtxTimer : public TimerHandler { public: RtxTimer(TcpAgent *a)no: TimerHandler() Existem três temporizadores declarados agente TCP Tahoe { definido em tcp.cc: a_ = a; rtx_timer_; } Temporizador de retransmissão protected: delsnd_timer_; Atrasa ovirtual envio do void pacoteexpire(Event por um pequeno tempo *e);aleatório, de forma a evitar efeitos cíclicos TcpAgent *a_; burstsnd_timer_; };o TCP no envio de uma grande janela de tranmissão dividida Auxilia em várias partes menores Em tcp.h existem três classes de temporizadores definidas: class RtxTimer class DelSndTimer class BurstSndTimer Exemplo – Retransmissão no TCP TcpAgent::TcpAgent() : Agent(PT_TCP), rtt_active_(0), rtt_seq_(-1), ... rtx_timer_(this), delsnd_timer_(this), burstsnd_timer_(this) { ... } void TcpAgent::newtimer (Packet* pkt) { hdr_tcp *tcph = (hdr_tcp*) pkt->access( off_tcp_ ); if ( t_seqno_ > tcph->seqno() ) set_rtx_timer(); else if ( rtx_timer_.status() == TIMER_PENDING ) rtx_timer_.cancel(); } void TcpAgent::set_rtx_timer() { rtx_timer_.resched(rtt_timeout()); } void TcpAgent::timeout( int tno ) { ... } void RtxTimer::expire( Event *e ) { a_->timeout( TCP_TIMER_RTX ); } /tcl/mcast/timer.tcl: ... Timer instproc sched delay { $self instvar ns_ $self instvar id_ $self cancel set id_ [$ns_ after $delay "$self timeout"] Diferença básica: ao contrário da implementação em C++, } a sched() para um temporizador pendente onde uma chamada causa um abort()... , sched e resched em OTcl possuem a mesma funcionalidade Temporizador em OTcl Nenhum estado é mantido para o temporizador As seguintes funções são definidas para o temporizador: $self sched $delay # programa o temporizador para $delay seg.; $self resched $delay # o memo que "$self sched $delay" ; $self cancel # cancela o temporizador (não há callback); $self destroy # o mesmo que "$self cancel"; $self expire # faz uma chamada a "$self timeout" imediatamente; “timeout” deve estar definida na subclasse Geração de Números Aleatórios Geração de Números Aleatórios Suporte Matemático. O NS possui uma pequena coleção de funções matemáticas usadas para implementar funções geradoras de números aleatórios e cálculos de integrais. Os procedimentos podem ser encontrados nos seguintes arquivos: tools/rng.{cc, h}. tools/random.{cc, h}. tools/ranvar.{cc, h}. tools/pareto.{cc, h}. tools/expoo.{cc, h}. tools/integrator.{cc, h}. tcl/lib/ns-random.tcl. Geração de números aleatórios A classe RNG possui a implementação de um gerador recursivomúltiplo-combinado de números aleatórios (combined multiple recursive random number generator), ou MRG32k3a, proposto por L'Ecuyer (para versões 2.1b9 e posteriores). Versões anteriores utilizam o minimal standard multiplicative linear congruential generator, proposto por Park and Miller O gerador MRG32k3a provê 1,8x1019 streams independentes de Pierresendo L'Ecuyer. números aleatórios, cada streams composto por 2,3x1015 S.K. Park and R.W. Miller. Good parameters and implementations Random number generation: substreams. for combined multiple recursive random ones22are hard to find. Cada substream possui um período Good de 7,6x10 numberCommunications generators. of the ACM, 57 O período do gerador é de 3,1x10 Operations Research, 1999 1988. Geração de números aleatórios PierrenoL'Ecuyer, Richard Simard, E. Jack Um gerador RNG default é criado início da simulação Chen, and W. David Kelton. (defaultRNG). An object-oriented random number Se múltiplas variáveis aleatórias são utilizadas durante uma package with many long streams and simulação, cada variável deve utilizar um objeto RNG distinto. substreams. Quando uma nova variável RNG é criada, à sua semente Operations Research, 2001. é atribuído um valor de modo a gerar o próximo stream independente de números aleatórios. E também em: A implementação permite umtools/rng.h número máximo de 1,8x1019 var. aleatórias. tools/rng.cc Geralmente são necessárias várias réplicas de um mesmo experimento (análise estatística) Para cada réplica, um substream diferente deve ser utilizado para garantir que as seqüências de números aleatórios sejam independentes. Esse processo limita o número de réplicas possíveis em, no máximo, 2,3x1015. Semente Semente default de defaultRNG: 12345 Somente a semente de defaultRNG necessita ser inicializada Cada RNG é inicializado de modo a produzir uma seqüência independente de números. A semente pode ser inicializada com qualquer valor entre 1 e MAXINT (2147483647). Para obter comportamento não-determinístico, basta inicializar a semente para 0. A nova semente é baseada na hora corrente e em um contador. Não deve ser usado para produzir uma seqüência independente de dados, já que não há garantia que as seqüências não irão se sobrepor. A única forma de garantir que duas seqüências não irão se sobrepor é utilizar substreams. Exemplo 1 - script # Usage: ns rng-test.tcl [replication number] $sizeRNG next-substream if {$argc > 1} { } puts "Usage: ns rng-test.tcl \[replication number\]" # arrival_ is a exponential random variable describing the time exit # between consecutive packet arrivals } set arrival_ [new RandomVariable/Exponential] set run 1 $arrival_ set avg_ 5 if { $argc == 1 } { set run [lindex $argv 0] } if { $run < 1 } { set run 1 } # seed the default RNG global defaultRNG $defaultRNG seed 9999 $arrival_ use-rng $arrivalRNG # size_ is a uniform random variable describing packet sizes set size_ [new RandomVariable/Uniform] $size_ set min_ 100 $size_ set max_ 5000 $size_ use-rng $sizeRNG # create the RNGs and set them to the correct substream # print the first 5 arrival times and sizes set arrivalRNG [new RNG] for {set j 0} {$j < 5} {incr j} { set sizeRNG [new RNG] puts [ format "%-8.3f %-4d" [ $arrival_ value ] \ for {set j 1} {$j < $run} {incr j} { $arrivalRNG next-substream [expr round([$size_ value])]] } Exemplo 1 - script # Usage: ns rng-test.tcl [replication number] $sizeRNG next-substream if {$argc > 1} { } puts "Usage: ns rng-test.tcl \[replication number\]" # arrival_ is a exponential random variable describing the time exit # between consecutive packet arrivals } set arrival_ [new RandomVariable/Exponential] set run 1 $arrival_ set avg_ 5 if { $argc == 1 } { set run [lindex $argv 0] } if { $run < 1 } { set run 1 } # seed the default RNG global defaultRNG $defaultRNG seed 9999 $arrival_ use-rng $arrivalRNG # size_ is a uniform random variable describing packet sizes set size_ [new RandomVariable/Uniform] $size_ set min_ 100 $size_ set max_ 5000 $size_ use-rng $sizeRNG # create the RNGs and set them to the correct substream # print the first 5 arrival times and sizes set arrivalRNG [new RNG] for {set j 0} {$j < 5} {incr j} { set sizeRNG [new RNG] puts [ format "%-8.3f %-4d" [ $arrival_ value ] \ for {set j 1} {$j < $run} {incr j} { $arrivalRNG next-substream [expr round([$size_ value])]] } Exemplo - saída % ns rng-test.tcl 1 % ns rng-test.tcl 5 6.358 5.828 1.469 0.732 4.002 0.691 0.204 8.849 2.111 3.200 4783 1732 2188 3076 626 1187 4924 857 4505 1143 Comandos OTcl Os seguintes comandos do RNG podem ser acessados através do OTcl e se encontram implementados em tools/rng.cc: seed <raiz>: atribui o parâmetro à raiz do gerador. O valor 0 indica uma raiz baseada na hora corrente e em um contador next-random: retorna próximo número aleatório seed: retorna o valor da raiz next-substream: avança para o próximo reset-start-substream: reinicia o substream para o início da seqüência de números aleatórios normal <avg> <stddev>: retorna um número aleatório de uma distribuição normal segundo os parâmetros de entrada lognormal <avg> <stddev>: retorna um número aleatório de uma distribuição lognormal segundo os parâmetros de entrada. Comandos OTcl Os seguintes comandos do RNG podem ser acessados através do OTcl e se encontram implementados em tcl/lib/ns-random.tcl: exponential <mean>: retorna um número aleatório retirado de uma distribuição exponencial segundo o parâmetro de entrada uniform <a> <b>: retorna um inteiro retirado de uma distribuição uniforme no intervalo [a , b] integer <k>: retorna um inteiro retirado de uma distribuição uniforme no intervalo [0 , k-1] Exemplo 2 - script # Usage: ns rng-test2.tcl [replication number] # print the first 5 arrival times and sizes if { $argc > 1 } { for { set j 0 } { $j < 5 } { incr j } { puts "Usage: ns rng-test2.tcl \[replication number\]" puts [format "%-8.3f %-4d" [$arrivalRNG lognormal 5 0.1] \ [expr round([$sizeRNG normal 5000 100])]] } exit } set run 1 if { $argc == 1 } { set run [lindex $argv 0] } if { $run < 1 } { set run 1 } # the default RNG is seeded with 12345 # create the RNGs and set them to the correct substream set arrivalRNG [new RNG] set sizeRNG [new RNG] for { set j 1 } { $j < $run } { incr j } { $arrivalRNG next-substream $sizeRNG next-substream } Saída % ns rng-test2.tcl 1 142.776 5038 174.365 5024 147.160 4984 169.693 4981 187.972 4982 Saída % ns rng-test2.tcl 5 160.993 4907 119.895 4956 149.468 5131 137.678 4985 158.936 4871 Comandos C++ Métodos da classe RNG O gerador de números aleatórios está implementado na classe RNGImplementation dentro de tools/rng(.h,.cc). Note: A classe Random em tools/random.h é uma interface para a classe RNG (compatibilidade com versões anteriores) Classe RNGImplementation: void set_seed (long seed): igual a OTcl long seed (void): retorna o valor da semente long next (void): próximo número entre [0,MAXINT] double next_double (void) próximo número entre [0,1] void reset_start_substream (void): reinicia substream void reset_next_substream (void): próximo substream Comandos C++ Métodos da classe RNG Classe RNGImplementation: int uniform (int k): retorna inteiro da dist. uniforme entre [0,k-1] double uniform (double r): dist. uniforme entre [0, r] double uniform (double a, double b): dist. uniforme entre [a,b] double exponential (void): dist. exponencial com valor médio 1.0 double exponential (double k): dist. exponencial com valor médio k double normal (double avg, double std): dist. normal com média e desvio padrões dados double lognormal (double avg, double std): dist. lognormal com média e desvio padrões dados Exemplo - código /* create new RNGs */ RNG arrival (23456); RNG size; /* set the RNGs to the appropriate substream */ for (int i = 1; i < 3; i++) { arrival.reset_next_substream(); size.reset_next_substream(); } /* print the first 5 arrival times and sizes */ for (int j = 0; j < 5; j++) { printf ("%-8.3f %-4d\n", arrival.lognormal(5, 0.1), int(size.normal(500, 10))); } Saída 161.826 506 160.591 503 157.145 509 137.715 507 118.573 496 Variáveis Aleatórias A classe RandomVariable provê uma abstração das funcionalidades do gerador de números aleatórios e da seqüência de números gerados. Arquivos: tools/ranvar(.h,.cc) class RandomVariable : public TclObject { public: virtual double value() = 0; int command(int argc, const char*const* argv); RandomVariable(); protected: RNG* rng_; }; Classes que derivam dessa classe abstrata implementam uma distribuição específica. Cada distribuição é parametrizada com os respectivos valores. O método virtual value é utilizado para retornar um número que segue a distribuição implementada. Variáveis Aleatórias As distribuições implementadas na versão atual e seus parâmetros são: UniformRandomVariable: min_, max_ ExponentialRandomVariable: avg_ ParetoRandomVariable: avg_, shape_ ParetoIIRandomVariable: avg_, shape_ ConstantRandomVariable: val_ HyperExponentialRandomVariable: avg_, cov_ NormalRandomVariable: avg_, std_ LogNormalRandomVariable: avg_, std_ Variáveis Aleatórias A classe RandomVariable está disponível em OTcl. Exemplo: criar uma variável randômica que gera números aleatórios uniformemente distribuídos no intervalor [10, 20] set u [new RandomVariable/Uniform] set rng [new RNG] $u set min_ 10 $rng seed 0 $u set max_ 20 set e [new RandomVariable/Exponential] $u value $e use-rng $rng Por default, um objeto RandomVariable utiliza o RNG default do NS. Para associar um novo RNG à variável deve-se utilizar o método use-rng. Integrais Ns possui uma classe para cálculos de integrais nos arquivos tools/integrator(.h,.cc) Aproximação da integral contínua através de somas discretas class Integrator : public TclObject { public: Integrator(); void set(double x, double y); void newPoint(double x, double y); int command(int argc, const char*const* argv); protected: double lastx_; double lasty_; double sum_; };