vector command

The ::rbc::vector command creates and manages real or complex numeric vectors.

A vector can be accessed through:

  • its vector instance command

  • an associated Tcl array variable

  • the RBC C API.

Read-only vectors

Since 0.8.1, vectors can be protected against accidental data modification:

samples set {1 2 3}
samples readonly true
set result [rbc::vector expr -name #auto {samples * 2}]
samples readonly false

New vectors are writable by default. The state protects values, length and index offset; numeric type remains immutable independently. Reads, statistics, arithmetic that returns a list, expressions using the vector as input, and graph bindings remain available. Copies and newly created expression results are writable. Vector commands and C mutators targeting a read-only vector fail with error code RBC VECTOR READONLY (mapped-variable write errors use Tcl’s TCL WRITE VARNAME code). Multi-output operations check every destination before changing output values. Recreating an existing locked vector with vector create is rejected too.

Renaming preserves the state. Destruction, namespace cleanup, array mapping and cache clearing are allowed. In particular, VECINST clear clears the mapped-variable cache, not the vector values. Mapped-array writes fail without changing native values. Unsetting an array element also leaves the values intact; Tcl ignores errors from unset traces, so unset itself can succeed and a subsequent read reconstructs the element. Whole-array unset retains the existing -watchunset lifetime behaviour.

readonly false deliberately unlocks the vector. This is data protection, not exclusive ownership or a security boundary. Tcl callbacks may change the state: expression destinations are checked again after evaluation and before committing the result. Callback side effects are not rolled back.

Loading vectors without Tk

Use the rbc::vector package in a Tcl-only interpreter:

package require rbc::vector
::rbc::vector create samples
samples set {1 2 3}
samples expr {samples * 2}

This loads the same Rbc shared library but initializes only its vector commands and C API. It does not require Tk, a graphical display, argparse, or graphtoolbar. Real and complex vectors, expressions, array access, and vector client notifications use the same implementation as the full package. Graphs, winop, and spline are available through the full rbc package. The optional toolbar is loaded separately with package require rbc::graphtoolbar and requires argparse.

Loading package require rbc later adds the graphical components without recreating the vector command or existing vectors. Full loading also provides rbc::vector, so either order is supported. A failed Tk load leaves the vector core usable and full loading can be retried. Package versions match the shared library version. Use package commands for both paths; the package index handles the shared binary and its initialization order. Direct load and the C Rbc_Init entry point now initialize only the vector core; use package require rbc (or Rbc_InitStubs in a consumer) for full GUI initialization.

This is an initialization split, not a separate binary or reduced build. Building still requires Tcl/Tk headers and the selected backend dependencies. The shared library’s dynamic dependencies (for example Cairo or platform graphics libraries) must remain installed even for vector-only use. The private ::rbc::_initTk command is loader infrastructure, not a public application API.

Vector types

Each vector has an immutable numeric type:

  • real - the default type. Each vector value is a double-precision floating-point number.

  • complex - each vector value contains a double-precision real component and a double-precision imaginary component.

The type is selected when the vector is created:

::rbc::vector create x
::rbc::vector create z -type complex

The VECINST type operation returns the type of an existing vector.

Complex values are represented at the Tcl level as two-element lists:

{real imag}

For example:

::rbc::vector create z -type complex
z set {{1 2} {3 -4} {-2 0.5}}

z index 1
# -> 3.0 -4.0

A real scalar is also accepted where a complex value is expected and is promoted to a complex value with zero imaginary component. For example, 5 is equivalent to {5 0}.

A vector’s type cannot be changed after creation. Supplying -type for an existing vector is permitted only when the requested type is the same as its current type. Omitting -type when referring to an existing vector preserves its current type.

Real vectors whose names contain no parentheses retain the traditional automatic Tcl array mapping. ComplexD vectors do not receive an automatic array mapping, but one may be requested explicitly with -variable orDXS later with VECINST variable.

Graph and spline integration

Complex vectors are supported directly by Polar graph elements and by parametric spline interpolation.

Traditional graph, barchart, and stripchart element data remain real-valued. A complex vector supplied to their ordinary X/Y data options is rejected rather than being implicitly converted to a real part, magnitude, or another projection.

A widget created by polar can attach a complex vector directly with the element -cdata option:

::rbc::vector create gamma -type complex
gamma set {{0 0} {0.2 0.4} {0.5 0.2}}

::rbc::polar .p -representation smith
.p element create trace -cdata gamma

Polar complex elements support three data formats:

gamma
impedance
admittance

selected with -cdataformat.

The scalar spline interface remains real-valued:

spline natural x y splX splY
spline quadratic x y splX splY

The parametric spline interface operates directly on complex vectors:

spline parametric natural source result samples
spline parametric quadratic source result samples

For example:

::rbc::vector create z -type complex
z set {{0 0} {1 1} {0 2} {-1 1}}

spline parametric natural z smoothZ 100

When a real projection of a complex vector is required for a traditional graph or scalar spline, it can be derived explicitly with expression functions such as real, imag, abs, or arg:

::rbc::vector create magnitude
magnitude expr {abs(z)}

Vector creation forms

Vectors may be created with an initially empty value array:

::rbc::vector create x

A size may be included in the vector specification:

::rbc::vector create x(100)

This creates a vector containing 100 values.

An explicit external index range may also be specified:

::rbc::vector create x(-5:14)

This creates 20 values and sets the vector index offset so that its externally visible indices run from -5 through 14.

The special name #auto requests an automatically generated vector name.

Vector names may be namespace-qualified.

Parentheses in vector names

Vector names may contain balanced parentheses, including nested groups. This permits signal names such as v(out) and i(device) without encoding them. The other name-character restrictions remain unchanged.

::rbc::vector create v(out)
v(out) set {1 2 3 4}
v(out) index 1:2
# -> 2.0 3.0
::rbc::vector create selected
selected set v(out)(1:2)
selected expr {v(out)(1:2) * 2}

Name lookup selects the longest existing name before interpreting an optional final parenthesized group as an index or range. Thus v(out)(1:2) selects elements of v(out), unless a vector literally named v(out)(1:2) exists, in which case the exact name wins. Use the instance command’s index or range operation when a literal name and a range reference would otherwise be identical.

Creation preserves the legacy numeric suffix forms: x(100) creates x with 100 elements, and v(out)(2:4) creates v(out) with three elements at offset 2. A nonnumeric suffix such as (out) is part of the name. To create a literal numeric name, use -literal true and specify its length separately:

::rbc::vector create v(1) -literal true -length 100
v(1) index 0:9

The default is -literal false. An exact existing vector name takes precedence even without this option. The special name #auto still requests an automatically generated name. Numeric suffixes begin with a digit, sign or colon (ignoring leading whitespace); invalid numeric sizes and ranges remain errors. -literal true disables suffix interpretation for every supplied name.

Names containing parentheses do not receive an automatic Tcl array mapping, for either numeric type. Tcl interprets $v(out)(1:2) as array element v(out) followed by literal text (1:2), not as an element of an array named v(out). Use the vector command, or request a separate array name:

::rbc::vector create v(out) -variable outValues
v(out) set {1 2 3}
set samples $outValues(0:2)

Explicit mapped array names must not contain parentheses. -variable {} disables mapping. This rule also applies to VECINST variable; a rejected name leaves an existing mapping intact.

In vector expressions, known mathematical function calls retain precedence. If a vector is named sin(x), sin(x) still calls the function, while {sin(x)} or "sin(x)" inside the expression denotes the vector:

selected expr {{sin(x)} + 1}
selected expr {{sin(x)(0:2)} * 2}

The outer braces delimit the Tcl expression argument; the inner braces quote a vector reference for RBC. This quoting is also useful for names beginning with digits, which otherwise start numeric expressions.

Vector-producing instance operations such as dup, normalize, populate and split also accept literal destination names with parentheses and do not create automatic array mappings for them.

Vector instances

The examples and command descriptions below use VECINST to denote the Tcl command associated with an individual vector.

For example:

set x [::rbc::vector create x]
$x seq 0 10 0.5
puts [$x length]

Copyright (c) George Yashin