uia-sim
                                
                                
                                
                                    uia-sim copied to clipboard
                            
                            
                            
                        A Java port of SimPy, process-based discrete event simulation framework.
UIA-SIM for Java, DESim4J
DESim4J is a Java port of SimPy, process-based discrete event simulation framework.
DESim4J aims to port the concepts used in SimPy to the Java world. Because there is no yield keyword in Java, the framework also implements a yield-like API in package uia.cor to meet some coroutine scenarios.
The ROAD is a sub-project that build a abstract simulator of the manufacturing factory.
package uia.cor
The package provides yield-like API. The main concept is
Generator gen = Yield.accept(yield -> ::function);
- 
Yield
- yield.call(Object) - pass a value to paired 
Generator. - yield.close() - stop iteration.
 
 - yield.call(Object) - pass a value to paired 
 - 
Generator
- gen.next() - notify ::function to prepare next value.
 - gen.errorNext() - notify ::function to prepare next value.
 - gen.getValue() - Get the value from 
yield.setValue(Object) - gen.error(ex) - send back an exception.
 - gen.send(Object) - send back a value to yield.
 - gen.close() - stop yield iterable.
 
 
Below is a simple workflow of Yield-Generator:
public class YieldTest {
    @Test
    public void testCallFor() {
        // 1
        Generator<Integer> gen = Yield.accept(this::callFor); 
            // 2, 5
            while(gen.next()) {
                // 4
                System.out.println("value=" + gen.getValue());
        }
    }
    /**
     * iterable work
     */
    public void callFor(Yield<Integer> yield) {
        for(int i = 0; i < 10; i++) {
            // 3
            yield.call(i);
        }
    }
}
Generator<Integer> gen = Yield.accept(this::callFor)- Create aYieldobject and pass tocallFormethod. Return pairedGenerator.gen.next()- Ask if there is a new value or not.yield.call(i)- Pass a new value to the generator and block until invokinggen.next()again.gen.getValue()- Get the new value passed byyield.call(i).while(gen.next())- Repeat until completing theforloop.
Use Yield2Way if iteration needs to get a result from yield.call(value).
public class Yield2WayTest {
    @Test
    public void testSum2() {
        Generator2Way<Integer, Integer> gen = Yield2Way.accept(this::sum2);
        int i = 0;
        // 4
        while(gen.next()) {
            // 2
            i = gen.getValue();
            System.out.println("value=" + i);
            // 3
            gen.send(i * i);
        }
    }
    /**
     * iterable work
     */
    public void sum2(Yield2Way<Integer, Integer> yield) {
        int i = 1;
        int sum = 0;
        while(i <= 10) {
            // 1, 5
            int v = yield.call(i++);    // waiting a result
            sum += v;
        }
        System.out.println("  sum=" + sum);
    }
}
yield.call(i++)- Pass a new value to the generator and block until invokinggen.next()again.gen.getValue()- Get the new value passed byyield.call(i).gen.send(i * i)- Send back a result but step 1 is still blocking.gen.next()- Ask if there is a new value or not and release step 1 at the same time.int v = yield.call(i++)- Get the result passed bygen.send(i * i).
Class Diagram
classDiagram
    Generator --> Yield
    Consumer ..> Yield
    Yield <-- Yieldable
    <<Iterable>> Consumer
    Generator: next() boolean
    Generator: next(R) boolean
    Generator: getValue() T
    Yield: call(T)
    Yield: send(R)
    Yield: next(boolean stop) boolean
    Yield: getValue() T
    Consumer: accept(Yield)
    Yieldable: run()
Sequence Diagram
sequenceDiagram
    autonumber
    Controller --) Consumer: new()
    Controller ->> +Yield: accept()
    Yield -->> +Generator: new()
    Yield --) -Controller: generator
    Yield --) Consumer: accept()
    note over Yield: in a new Thread
    loop thread-iterable
        Consumer ->> +Yield: call(T)
        note right of Consumer: send a value to the Controller
        Yield ->> Yield: notifyAll()
        note over Yield: notify Step-14 to get next value
        Yield --) Yield: wait()
        Yield --) -Consumer: 
        note over Yield: wait Step-12 to notify
    end
    loop thread-main
        Controller ->> Generator: next()
        Generator ->> +Yield: next()
        Yield ->> Yield: notifyAll()
        note over Yield: notify Step-9 to build next value
        Yield --) Yield: wait()
        Yield --) -Generator: 
        note over Yield: wait Step-7 to notify
        Controller ->> Generator: T getValue()
        Generator ->> +Yield: T getValue()
        Yield --) -Generator: value
        note right of Controller: get last value from the Generator
    end    
package uia.sim
The package is core framework of process-based discrete event simulation.
Some documents
- Core Design
 - Examples
 
Core Concept
- Create a event stream
 
flowchart LR;
    id1[[*E00]]-->E20;
    E20-->E50;
    E50-->E90;
- Execute head event E00, and create a new event E55. The event stream becomes
 
flowchart LR;
    id1[[*E20]]-->E50;
    E50-->id2([E55]);
    id2([E55])-->E90;
- Execute head event E20, and create a new event E53. The event stream becomes
 
flowchart LR;
    id1[[*E50]]-->id2([E53]);
    id2([E53])-->id3([E55]);
    id3([E55])-->E90;
- Execute all events with ordering.
 
flowchart LR;
    id1[[*E53]]-->id2([E55]);
    id2([E55])-->E90;
flowchart LR;
    id1[[*E55]]-->E90;
flowchart LR;
    id1[[*E90]];
Class Diagram
classDiagram
    Env --* Job
    Initialize --|> Event
    Job --> Event
    Event <.. Yield
    Event -- * Callback 
    Callback -- Process
    Event <|-- Process
    Event <.. Processable
    Yield <-- Consumer
    Yield <-- Generator
    Consumer <|-- Processable
    Processable --> Process  
    Generator <-- Process
    <<coroutine>> Yield
    <<coroutine>> Generator
    <<coroutine>> Consumer
    <<case>> Processable
    Env: PriorityBlockingQueue~Job~ jobs
    Process: +resume(Event)
    Processable: +initial()
    Processable: +run()
    Event: List callables
    Event: +callback()
Sequence Diagram
- 
Work flow of events
sequenceDiagram autonumber loop Env ->> +Env: poll() Env ->> Event: callback() Event ->> Process: resume(Event) Process --) Processable: // notify Processable ->> Env: // schedule a new event if needed Env --) Event: // new Env ->> -Env: // add a new event into the queue Processable --) Process: // notify Process ->> Event: addCallable() end - 
Startup of a process
sequenceDiagram autonumber Env ->> Event["Initialize"]: callback() Event["Initialize"] ->> +Process: resume(Event) Process ->> Event["Initialize"]: getValue() Process ->> +Generator: next(Object) Generator ->> Yield: send(Object) Generator ->> Yield: next(Boolean) Yield --) Processable: notifyAll() Processable ->> +Env: // schedule a new event if needed Env --) Event: new Env ->> -Env: // add a new event into the queue Processable ->> Yield: call(Event) Yield --) Generator: notifyAll() Generator --) -Process: Process ->> Generator: getValue() Process ->> -Event: addCallable(Process::resume) // hook the Process and Event together 
Test Case
Below is a Java test case compares with Python version.
Python
class School:
    def __init__(self, env):
        self.env = env
        self.class_ends = env.event()
        self.pupil_procs = [env.process(self.pupil()) for i in range(3)]
        self.bell_proc = env.process(self.bell())
    def bell(self):
        while True:
            yield self.env.timeout(45)
            self.class_ends.succeed()
            self.class_ends = self.env.event()
            print()
    def pupil(self):
        while True:
            yield self.class_ends
            print(r' \o/', end='')
env = Environment()
school = School(env)
env.run(200)
Java
public class SchoolTest {
    private Env env;
    private Event classEnd;
    public SchoolTest() {
        this.env = new Env();
        this.classEnd = this.env.event("classEnd");
        env.process("pupil-1", this::pupil);
        env.process("pupil-2", this::pupil);
        env.process("pupil-3", this::pupil);
        env.process("bell", this::bell);
    }
    public void bell(Yield<Event> yield) {
        while(yield.isAlive()) {
            yield.call(env.timeout(45));
            this.classEnd.succeed(null);
            this.classEnd = this.env.event("classEnd");
            System.out.println(String.format("\n%3d> bell is ringing...", this.env.getNow()));
        }
    }
    public void pupil(Yield<Event> yield) {
        while(yield.isAlive()) {
            yield.call(this.classEnd);
            System.out.print("\\o/ ");
        }
    }
    @Test
    public void test1() throws Exception {
        this.env.run(200);
    }
}
The framework is still building and testing. The next tasks are
- Add 
resourcesimplementation. - More stable of 
uia.corpackage. - More reasonable Exception control.
 - More test cases to prove the framework.