Feature-Incremental Program Development

Corrections in RED (none yet)

Find a partner.  You are to work in groups of 2 in this (and other) programming assignments.

You are NOT to use MDELite in this assignment, except for the ErrorReport class and the RegTest regression pacakge.

Software Product Lines (SPLs) exemplify a fundamental way to build families of programs.  Ironically, SPLs are among the hardest ideas in software development to illustrate.  The reason is that even tiny examples of SPLs requires a deep knowledge of a family of programs -- deep meaning that one has to understand these programs and expertise in coding such programs.  Further, to develop an impressive SPL with many takes months, if not years of work.  Good luck, as they say.

In a classroom setting, we have to resort to basics, assuming no expertise on creating (or even knowing) what a program family is.  In this assignment, you will develop a program family, starting with a base program, and incrementally adding features, until you have a "complete" program.  After each increment, you have created another program in a this program family.  You will build a Logic Circuit program from the ground up, incrementally with these features:

In the end, you'll have one big fat program.  (Well, perhaps not that big and not that fat, but you get the idea).  But along the way, you'll see feature-based subsets of these programs. In a following assigment, you'll convert your program into a feature-based SPL.

Logic Circuit Program Family

A logic circuit is shown below. It consists of 4 input ports (A,B,C,D -- whose names are capital letters) and 2 output ports (α,β -- whose names are lower-case greek letters).   The name of this circuit is XX (for lack of anything better).

Database Design

Here is a class diagram of a Logic Circuits metamodel and the tables that encode circuit XX above:

Notice the use of the following naming convention: box ("encapsulated circuit") XX has 4 input pins (drawn as lines on the left of the XX) and 2 output pints (drawn as lines on the right of the XX box).  Input pins are numbered, from top to bottom, as the integer interval [1,2,3,4].  Output pins are numbered similarly [1,2].   If there are more/fewer pins, pin numbers will be in the integer interval [1...].

BASE Feature

The BASE (or first) feature allows you to encode circuits as graphs of Java objects.  One way that the XX circuit is the Java code:
Circuit xx = new Circuit("XX");         // create a new circuit object xx called "XX"

Gate A = xx.new Gate("A",0,1,"input"); // add the following gates and wires to xx
Gate B = xx.new Gate("B",0,1,"input");
Gate C = xx.new Gate("C",0,1,"input");
Gate D = xx.new Gate("D",0,1,"input");
Gate α = xx.new Gate("α",1,0,"output");
Gate β = xx.new Gate("β",1,0,"output");

Gate nor = xx.new Gate("n1",2,1,"nor");
Gate inv = xx.new Gate("i1",1,1,"inv");
Gate and = xx.new Gate("a1",3,1,"and");
Gate or = xx.new Gate("o1",2,1,"or");

new Wire(xx,A,1,nor,1);
new Wire(xx,B,1,nor,2);
new Wire(xx,nor,1,and,1);
new Wire(xx,C,1,or,1);
new Wire(xx,D,1,or,2);
new Wire(xx,C,1,inv,1);
new Wire(xx,inv,1,and,2);
new Wire(xx,or,1,and,3);
new Wire(xx,or,1,β,1);
new Wire(xx,and,1,α,1);

xx.print(); // print out the circuit as tables
You are to write a BASE Java program that implements the functionality.  (Yes, all you can do is define circuits, and because there are no constraints, just yet, circuits are meaningless).  But what you are writing is the core foundation of a LogicCircuit program.


You may have already noticed that specifying a circuit is tedious.  The BEAUTIFY feature simplifies specifications in two ways: First, the Gates class becomes an abstract class and all Gates now become concrete subclasses of Gates.  Doing so, gate constructors, such as And and Inv, hide details that can be inferred:
public And(Circuit xx, String name, int nInputs) {
super(xx, name,nInputs,1, "and");

public Inv(Circuit xx, String name) {
super(xx, name,1,1, "inv");
All Gate classes should be stored in a sub package of your LogicCircuits package.

Second, Wire constructors are simplified again by removing constructor information that can be inferred.  You end up adding extra constructors to the Wire class:
public Wire(Circuit circuit, Gate from, int fromPin, Gate to) {
this(circuit, from, fromPin, to, 1);

public Wire(Circuit circuit, Gate from, Gate to, int toPin) {
this(circuit, from, 1, to, toPin);

public Wire(Circuit circuit, Gate from, Gate to) {
this(circuit, from, 1, to, 1);
Doing so, circuit XX is a bit cleaner:
Gate A = new Input(xx,"A");
Gate B = new Input(xx,"B");
Gate C = new Input(xx,"C");
Gate D = new Input(xx,"D");
Gate α = new Output(xx,"α");
Gate β = new Output(xx,"β");

Gate nor = new Nor(xx,"nor",2);
Gate inv = new Inv(xx,"inv");
Gate and = new And(xx,"and", 3);
Gate or = new Or(xx,"or", 2);

new Wire(xx,A,nor,1);
new Wire(xx,B,nor,2);
new Wire(xx,nor,and, 1);
new Wire(xx,C,or, 1);
new Wire(xx,D,or, 2);
new Wire(xx,C,inv, 1);
new Wire(xx,inv,and, 2);
new Wire(xx,or,and, 3);
new Wire(xx,or,β);
new Wire(xx,and,α);

Note: I key idea in feature-based development is that just because you add a new feature, doesn't mean that the previous functionality and regression tests of the earlier features must change.  That is, if you have regression test R for a program P-F (which is program P without feature F), R should still pass for program P+F.  This may require some revision of how you implemented all your features, so that you maintain this property.  Otherwise, you've missed a big point in product-line development.  This is very much the case that you polish ALL features as you add another so that they all work together correctly.

TABLE Feature

The TABLE feature extends the BASE program/feature by creating tables (not MDELite tables, but simply LinkedList<Gate> and LinkedList<Wire>) to represent the above circuit.  The BASE program literally contained only constructors and calls to those constructors.  Now you have to add the functionality to tie in constructor calls to object insertions into their corresponding linkedLists AND be able to print these tables using your own print method (whose output looks like that of MDELite).

The main rewrite that you use is add to Circut:
LinkedList<Gate> gates = new LinkedList<>();
LinkedList<Wire> wires = new LinkedList<>();
.And to use leaking constructors for the main constructor of Gates and Wires (something like):

protected Gate(Circuit circuit, String name, int nInputPins, int nOutputPins, String type) {
   this.circuit = circuit;
   this.name = name;
   this.nInputPins = nInputPins;
   this.nOutputPins = nOutputPins;
   this.type = type;
   circuit.gates.add(this); //<-- leaking constructor

After you create your circuit, you should print it out:

new Wire(xx,and,α);

xx.print() // <--new


Before you can do anything useful with a circuit (like evaluate it), you must ensure that the circuit graph of gate and wire objects (i.e., your version of a circuit database) makes sense semantically.  You are to:
public static void main(String... args) {
Circuit xx = new Circuit("XX");

Gate A = new Input(xx,"A");

xx.validate(); //<-- new


EVAL Feature

EVAL allows you to assign boolean values to gate input pins (in particular pins of input ports) and read the output at gate output pins (in particular, pins of output ports). The EVAL feature uses 3-valued logic (True, False, Unknown).  You know how to compute boolean functions (And, Or, ...) using True and False.  If you encounter an Unknown value at a an input port, flag it as an error -- the circuit was not initialized properly.
public enum Value { T, U, F }  // T=true, U=unknown, F=false
Clearly, for each gate type, you will need to define an eval function that reads the value at its input pins (which may require you follow a wire back to its output gate origin and get its value, recursively), and compute each output value.  So for the And gate class that you added in the BEAUTIFY feature, you will need to add a method, get(), which computes the boolean output given the inputs of the And gate.  You do the same for all other primitive gate classes. You will also need extend your main program functionality by initializing the value of all pins to "Unknown", setting values of input ports, and reading the value from output ports and reporting those values:
public static void main(String... args) {
Circuit xx = new Circuit("XX");

Gate A = new Input("A");
new Wire(...);



xx.initValues(); //<-- new
System.out.println("Value at
α output port is " + α.get());
System.out.println("Value at
β output port is " + β.get()); //<-- new

Of course, you'll need to extend the Gates and Wires classes with methods that implement the Eval feature.

Getting Started

The more everyone conforms to something similar, the easier it will be to discuss your results and for the TA to understand your program.  So I created a shell of a Netbeans project for you to begin with.  I also included a regression test for you to be (more) convinced that your program works. You are free to implement whatever as long as it satisfies the regression tests.  Here is the NetBeans program shell.

Here are two extra logic circuits I implemented in the shell regression tests:

  --- and ---   

What to Submit to Canvas

  1. A single zip file
  2. Evidence that you built your program one feature at a time (ex. shapshots of program texts,etc.).
  3. A program that implements the provided regression tests.
  4. Remember to put your name and email address at the top of your submitted PDF file.

All of the below in a zip file (including your Netbeans or Eclipse Project). 

The zip file must unzip into <YourName>/<YourFilesAndDirectories> folder containing

  1. Your program needs to run correctly on Linux machines, even though you may have developed them on Macs and Windoze.  The TA will grade your program running on Linux.

  2. A short description that the Grader needs to know to run your program, other than the above. 

  3. Run your tool on all "test/logiccircuits/CircuitTest.java" given in the Netbeans Shell.

  4. A short writeup explaining any additional tests that you have added to your program to verify that it works.

  5. A PDF file (in the required format) that the Grader should read to provide any information that is not obvious.  The contents of the PDF file can be minimal.

A critical part of any design is clarity and understandability.   Hence, you will be graded on the clarity of your project and its ability to work correctly.  Sloppy code, documentation, or anything that makes grading or understanding your program difficult will cost you points.  Beware, some of these "beauty" points are subjective. 

Remember: No late assignments/submissions will be accepted.