In general, hard-coded objects (and their members and member functions)
are treated just as they would be in C or C++. Objects that have been
created (i.e., Networks, Units, etc) can be referred to by their
path names, which start with the root object (PDPRoot).
While you could type root.projects[0]
, for example, to refer to
the first project, it is easier to use the abbreviation of a preceding
period to stand for root
, resulting in: .projects[0]
.
The following examples were performed on the XOR example project in
Bp++. In order to examine the project in CSS, one could simply use the
print
command on the path of this object:
bp++> print .projects[0] .projects[0] Proj (refn=1) { ta_Base* owner = .projects; String name = Proj; WinBase* win_owner = root; WinGeometry win_pos = {lft=4: bot=74: wd=535: ht=24: }; WinGeometry root_win_pos = {lft=9: bot=79: wd=161: ht=23: }; TypeDefault_MGroup defaults = Size: 5 (TypeDefault); BaseSpec_MGroup specs = Size: 3 (BaseSpec); Network_MGroup networks = Size: 1 (Network); Environment_MGroup environments = Size: 1 (Environment); Process_MGroup processes = Size: 5 (SchedProcess); PDPLog_MGroup logs = Size: 2 (TextLog); Script_MGroup scripts = Size: 1 (Script); }
The first network within this project would then be referred to as
.projects[0].networks[0]
:
bp++> print .projects[0].networks[0] .projects[0].networks[0] XOR (refn=15) { ta_Base* owner = .projects[0].networks; String name = XOR; WinBase* win_owner = .projects[0]; WinGeometry win_pos = {lft=4: bot=3: wd=536: ht=390: }; WinView_MGroup views = Size: 1 (NetView); Layer_MGroup layers = Size: 3 (Layer); Project* proj = .projects[0]; TDGeometry pos = {x=0: y=0: z=0: }; TDGeometry max_size = {x=2: y=2: z=3: }; int epoch = 0; Network::Layer_Layout lay_layout = THREE_D; }
You can also use a shortcut by just typing .networks[0]
, which
finds the first member with the name networks
in a search
starting at the root object and scanning down the first branch of
the tree of objects (i.e., looking in the first element of every group
along the way).
Scoped types such as Network::Layer_Layout
which appear in the
above class are referred to just as they would be in C++:
bp++> .networks[0].lay_layout = Network::TWO_D;
As you can see, setting the values of hard-coded object variables simply amounts to typing in the appropriate C/C++ statement.
Type information (obtained via the TypeAccess system) about hard-coded
objects can be obtained with the type
command:
bp++> type Network class Network : PDPWinMgr : WinMgr : WinBase : ta_NBase : ta_Base { // The Network // sub-types enum Layer_Layout { // Visual mode of layer position/view TWO_D = 0; // all z = 0, no skew THREE_D = 1; // z = layer index, default skew } // members ta_Base* owner; // pointer to owner String name; // name of the object . . TDGeometry max_size; // max size in each dim int epoch; // epoch counter Network::Layer_Layout lay_layout; // Visual mode of layer // functions void UnSafeCopy(ta_Base* na); ta_Base* GetOwner(TypeDef* tp); . . . void InitWtState(); // Initialize the weights . . void Compute_dWt(); // update weights for whole net void Copy_Weights(const Network* src); void Enforce_Layout(Network::Layer_Layout layout_type); }
This shows the inheritance of this object, any sub-types that are defined within it, and all of its members and functions (including those it inherits from other classes).
In addition, there is Tab-completion for path names and types in the CSS prompt-level script interface. Thus, as you are typing a path, if you hit the Tab key, it will try to complete the path. If there are multiple completions, hitting Tab twice will display them.
In order to call member functions of hard-coded classes, simply give the path to the object, followed by the member function, with any arguments that it might require (or none).
bp++> .networks[0].InitWtState(); bp++>
It is possible to create pointers to hard-coded objects. Simply declare a pointer variable with the appropriate type, and assign it to the given object by referring to its path:
bp++> Unit* un; bp++> un = .networks[0].layers[1].units[0]; bp++> print un .projects[0].networks[0].layers[1].units[0] hid_1 (refn=6) { ta_Base* owner = .projects[0].networks[0].layers[1].units; String name = hid_1; UnitSpec_SPtr spec = {type=BpUnitSpec: spec=.specs[0]: }; TDGeometry pos = {x=0: y=0: z=0: }; Unit::ExtType ext_flag = NO_EXTERNAL; float targ = 0; float ext = 0; float act = 0; float net = 0; Con_Group recv = Size: 0.1.2 (BpCon); Con_Group send = Size: 0.1.1 (BpCon); BpCon bias = BpCon; float err = 0; float dEdA = 0; float dEdNet = 0; }
There are two ways to create new hard-coded objects. The preferred way
is to call one of the New
functions on the group-like objects
(List
or Group
, see section 8.2 Groups), which will create
the object and add it to the group, so that it can be referred to by its
path as just described.
bp++> .layers[1].units.List(); Elements of List: (2) hid_1 hid_2 bp++> .layers[1].units.New(1); bp++> .layers[1].units.List(); Elements of List: (3) hid_1 hid_2 bp++> .layers[1].units[2].name = "new_guy"; bp++> .layers[1].units.List(); Elements of List: (3) hid_1 hid_2 new_guy
Finally, it is possible to create new instances of hard-coded object
types through the C++ new
operator, which is especially useful in
order to take advantage of some of the handy built-in types like arrays
(see section 8.3 Arrays):
bp++> float_RArray* ar = new float_RArray; bp++> print ar [0]; bp++> ar.Add(.25); bp++> ar.Add(.55); bp++> ar.Add(.11); bp++> print ar [3] 0.25 0.55 0.11; bp++> print ar.Mean(); (Real) = 0.303333 bp++> print ar.Var(); (Real) = 0.101067 bp++> ar.Sort(); bp++> print ar [3] 0.11 0.25 0.55;
Remember to delete
those objects which you have created in this
fashion:
bp++> delete ar; bp++> print ar (float_RArray) ar = 0
(the ar = 0
means that it is a null pointer). Be sure not
to use the delete
operator on those objects which were created
with the group's New
function, which should be Remove
d
from the group, not deleted directly (see section 8.2 Groups).