Skip to content

Commit

Permalink
Merge pull request #1915 from PrincetonUniversity/devel
Browse files Browse the repository at this point in the history
Devel
  • Loading branch information
kmantel authored Feb 19, 2021
2 parents 5bc0cf5 + 53363f7 commit aabefef
Show file tree
Hide file tree
Showing 26 changed files with 723 additions and 399 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pnl-ci-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
echo ::set-output name=pip_cache_dir::$(python -m pip cache dir)
- name: Wheels cache
uses: actions/[email protected].3
uses: actions/[email protected].4
with:
path: ${{ steps.pip_cache.outputs.pip_cache_dir }}/wheels
key: ${{ runner.os }}-python-${{ matrix.python-version }}-${{ matrix.python-architecture }}-pip-wheels-v2-${{ github.sha }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pnl-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
echo ::set-output name=pip_cache_dir::$(python -m pip cache dir)
- name: Wheels cache
uses: actions/[email protected].3
uses: actions/[email protected].4
with:
path: ${{ steps.pip_cache.outputs.pip_cache_dir }}/wheels
key: ${{ runner.os }}-python-${{ matrix.python-version }}-${{ matrix.python-architecture }}-pip-wheels-v2-${{ github.sha }}
Expand Down
64 changes: 64 additions & 0 deletions Scripts/Debug/Hebbian_Simon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import psyneulink as pnl
import numpy as np
import matplotlib.pyplot as plt
#sample Hebb

FeatureNames=['small','medium','large','red','yellow','blue','circle','rectangle','triangle']

# create a variable that corresponds to the size of our feature space
sizeF = len(FeatureNames)
small_red_circle = [1,0,0,1,0,0,1,0,0]
src = small_red_circle


Hebb_comp = pnl.Composition()

Hebb_mech=pnl.RecurrentTransferMechanism(
size=sizeF,
function=pnl.Linear,
#integrator_mode = True,
#integration_rate = 0.5,
enable_learning = True,
learning_rate = .1,
name='Hebb_mech',
#matrix=pnl.AutoAssociativeProjection,
auto=0,
hetero=0
)

Hebb_comp.add_node(Hebb_mech)

Hebb_comp.execution_id = 1

# Use print_info to show numerical values and vis_info to show graphs of the changing values

def print_info():
print('\nWeight matrix:\n', Hebb_mech.matrix.base, '\nActivity: ', Hebb_mech.value)


def vis_info():
ub=1#np.amax(np.amax(np.abs(Hebb_mech.matrix.modulated)))
lb=-ub
plt.figure()
plt.imshow(Hebb_mech.matrix.modulated,cmap='RdBu_r',vmin=lb,vmax=ub)
plt.title('PNL Hebbian Matrix')
plt.xticks(np.arange(0,sizeF),FeatureNames,rotation=35)
plt.yticks(np.arange(0,sizeF),FeatureNames,rotation=35)

plt.colorbar()
plt.show()

plt.figure()
plt.stem(Hebb_mech.value[0])
plt.title('Activation from Stimulus with PNL Hebbian Matrix')
plt.xticks(np.arange(0,sizeF),FeatureNames,rotation=35)
plt.xlabel('Feature')
plt.ylabel('Activation')
plt.show()

inputs_dict = {Hebb_mech:np.array(src)}
out=Hebb_comp.learn(num_trials=5,
# call_after_trial=vis_info,
inputs=inputs_dict)

print_info()
7 changes: 4 additions & 3 deletions docs/source/Core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ Core
- `CompositionFunctionApproximator`

* `Services`
- `Visualization`
- `Log`
- `Registry`
- `Preferences`
- `json`
- `Visualization`
- `Scheduling`
- `Compilation`
- `Log`
- `json`
13 changes: 7 additions & 6 deletions docs/source/Mechanisms.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
Mechanisms
==========

.. toctree::
:maxdepth: 3

.. container:: subclasses
*Subclasses*
ProcessingMechanisms
ModulatoryMechanisms

.. toctree::
:maxdepth: 3

*Subclasses:*
ProcessingMechanisms
ModulatoryMechanisms
8 changes: 6 additions & 2 deletions docs/source/Preferences.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ Standard prefereces:

- paramValidation (bool): enables/disables run-time validation of the execute method of a Function object

- reportOutput ([bool, str]): enables/disables reporting of execution of execute method:
True prints input/output, 'params' or 'parameters' includes parameter values
- reportOutput ([bool, str]): enables/disables reporting execution of `Component`\'s `execute <Component_Execution>`
method to console:
- ``True``: prints record of execution, including the input and output of the Component;
- 'params' or 'parameters': includes report of the Component's `parameter <Parameters>` values.
- 'terse': (Composition only) restricts output to just a listing of `trials <TimeScale.TRIAL>`, `time_steps
<TimeScale.TIME_STEP>` and `nodes <Composition_Nodes>` executed.

- log (bool): sets LogCondition for a given Component

Expand Down
3 changes: 3 additions & 0 deletions psyneulink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
from .core import *
from .library import *

# from rich import print, box
# print("Initializing...")

_pnl_global_names = [
'primary_registries', 'System', 'Process'
]
Expand Down
28 changes: 10 additions & 18 deletions psyneulink/core/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@
Execution
---------
A Component is executed when its `execute` method is called, which in turn calls its `function <Component_Function>`.
A Component is executed when its `execute <Component.execute>` method is called, which in turn calls its `function
<Component_Function>`.
.. _Component_Lazy_Updating:
Expand Down Expand Up @@ -486,7 +487,6 @@
import itertools
import logging
import numbers
import toposort
import types
import warnings

Expand Down Expand Up @@ -2024,7 +2024,7 @@ def _is_user_specified(parameter):
else:
param_defaults[p.source.name] = param_defaults[p.name]

for p in filter(lambda x: not isinstance(x, (ParameterAlias, SharedParameter)), self.parameters):
for p in filter(lambda x: not isinstance(x, (ParameterAlias, SharedParameter)), self.parameters._in_dependency_order):
# copy spec so it is not overwritten later
# TODO: check if this is necessary
p.spec = copy_parameter_value(p.spec)
Expand Down Expand Up @@ -2085,19 +2085,8 @@ def _instantiate_parameter_classes(self, context=None):
"""
from psyneulink.core.components.shellclasses import Function

parameter_function_ordering = list(toposort.toposort({
p.name: p.dependencies for p in self.parameters if p.dependencies is not None
}))
parameter_function_ordering = list(itertools.chain.from_iterable(parameter_function_ordering))

def ordering(p):
try:
return parameter_function_ordering.index(p.name)
except ValueError:
return -1

# (this originally occurred in _validate_params)
for p in sorted(self.parameters, key=ordering):
for p in self.parameters._in_dependency_order:
if p.getter is None:
val = p._get(context)
if (
Expand Down Expand Up @@ -2188,7 +2177,7 @@ def _create_justified_line(k, v, error_line_len=110):
self._override_unspecified_shared_parameters(context)

def _override_unspecified_shared_parameters(self, context):
for param_name, param in self.parameters.values(show_all=True).items():
for param in self.parameters._in_dependency_order:
if (
isinstance(param, SharedParameter)
and not isinstance(param.source, ParameterAlias)
Expand Down Expand Up @@ -2984,7 +2973,7 @@ def _update_default_variable(self, new_default_variable, context=None):
)
self._instantiate_value(context)

for p in self.parameters:
for p in self.parameters._in_dependency_order:
val = p._get(context)
if (
not p.reference
Expand Down Expand Up @@ -3028,6 +3017,9 @@ def reset(self, *args, context=None, **kwargs):

@handle_external_context()
def execute(self, variable=None, context=None, runtime_params=None):
"""Executes Component's `function <Component_Function>`. See Component-specific execute method for details.
"""

if context is None:
try:
context = self.owner.most_recent_context
Expand Down Expand Up @@ -3102,7 +3094,7 @@ def _execute(self, variable=None, context=None, runtime_params=None, **kwargs):

def is_finished(self, context=None):
"""
set by a Component to signal completion of its `execution <Component_Execution>` in a `TRIAL
Set by a Component to signal completion of its `execution <Component_Execution>` in a `TRIAL
<TimeScale.TRIAL>`; used by `Component-based Conditions <Conditions_Component_Based>` to predicate the
execution of one or more other Components on a Component.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1459,7 +1459,7 @@ def _gen_llvm_select_min_function(self, *, ctx:pnlvm.LLVMBuilderContext, tags:fr

# KDM 8/22/19: nonstateful direction here - OK?
direction = "<" if self.direction == MINIMIZE else ">"
replace_ptr = builder.alloca(pnlvm.ir.IntType(1))
replace_ptr = builder.alloca(ctx.bool_ty)

# Check the value against current min
with pnlvm.helpers.for_loop_zero_inc(builder, count, "compare_loop") as (b, idx):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out,
out_val_ptr = builder.gep(arg_out, [ctx.int32_ty(0), ctx.int32_ty(1)])

# Check retrieval probability
retr_ptr = builder.alloca(pnlvm.ir.IntType(1))
retr_ptr = builder.alloca(ctx.bool_ty)
builder.store(retr_ptr.type.pointee(1), retr_ptr)
retr_prob_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, RETRIEVAL_PROB)

Expand Down Expand Up @@ -844,7 +844,7 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out,
builder.store(selected_val, out_val_ptr)

# Check storage probability
store_ptr = builder.alloca(pnlvm.ir.IntType(1))
store_ptr = builder.alloca(ctx.bool_ty)
builder.store(store_ptr.type.pointee(1), store_ptr)
store_prob_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, STORAGE_PROB)

Expand All @@ -866,14 +866,14 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out,
with builder.if_then(store, likely=True):

# Check if such key already exists
is_new_key_ptr = builder.alloca(pnlvm.ir.IntType(1))
is_new_key_ptr = builder.alloca(ctx.bool_ty)
builder.store(is_new_key_ptr.type.pointee(1), is_new_key_ptr)
with pnlvm.helpers.for_loop_zero_inc(builder, entries, "distance_loop") as (b,idx):
cmp_key_ptr = b.gep(keys_ptr, [ctx.int32_ty(0), idx])

# Vector compare
# TODO: move this to helpers
key_differs_ptr = b.alloca(pnlvm.ir.IntType(1))
key_differs_ptr = b.alloca(ctx.bool_ty)
b.store(key_differs_ptr.type.pointee(0), key_differs_ptr)
with pnlvm.helpers.array_ptr_loop(b, cmp_key_ptr, "key_compare") as (b2, idx2):
var_key_element = b2.gep(var_key_ptr, [ctx.int32_ty(0), idx2])
Expand Down
94 changes: 15 additions & 79 deletions psyneulink/core/components/mechanisms/mechanism.py
Original file line number Diff line number Diff line change
Expand Up @@ -2532,13 +2532,18 @@ def execute(self,
if not self.parameters.execute_until_finished._get(context):
break

# REPORT EXECUTION
if self.prefs.reportOutputPref and (context.execution_phase & ContextFlags.PROCESSING | ContextFlags.LEARNING):
self._report_mechanism_execution(
self.get_input_values(context),
output=self.output_port.parameters.value._get(context),
context=context
)
# REPORT EXECUTION if called from command line
# If called by a Composition, it handles reporting.
if context.source == ContextFlags.COMMAND_LINE:
if self.prefs.reportOutputPref and (context.execution_phase & ContextFlags.PROCESSING | ContextFlags.LEARNING):
from psyneulink.core.compositions.composition import _report_node_execution
from rich import print
print(
_report_node_execution(self,
input_val=self.get_input_values(context),
output_val=self.output_port.parameters.value._get(context),
context=context)
)

return value

Expand Down Expand Up @@ -2965,7 +2970,7 @@ def _gen_llvm_invoke_function(self, ctx, builder, function, params, state, varia
return fun_out, builder

def _gen_llvm_is_finished_cond(self, ctx, builder, params, state):
return pnlvm.ir.IntType(1)(1)
return ctx.bool_ty(1)

def _gen_llvm_mechanism_functions(self, ctx, builder, params, state, arg_in,
ip_output, *, tags:frozenset):
Expand Down Expand Up @@ -3043,8 +3048,7 @@ def _gen_llvm_function(self, *, extra_args=[], ctx:pnlvm.LLVMBuilderContext, tag
ctx.get_input_struct_type(self).as_pointer(),
ctx.get_output_struct_type(self).as_pointer()]

builder = ctx.create_llvm_function(args, self,
return_type=pnlvm.ir.IntType(1),
builder = ctx.create_llvm_function(args, self, return_type=ctx.bool_ty,
tags=tags)
params, state = builder.function.args[:2]
finished = self._gen_llvm_is_finished_cond(ctx, builder, params, state)
Expand Down Expand Up @@ -3083,7 +3087,7 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out,
args_t = [a.type for a in builder.function.args]
internal_builder = ctx.create_llvm_function(args_t, self,
name=builder.function.name + "_internal",
return_type=pnlvm.ir.IntType(1))
return_type=ctx.bool_ty)
iparams, istate, iin, iout = internal_builder.function.args[:4]
internal_builder, is_finished = self._gen_llvm_function_internal(ctx, internal_builder,
iparams, istate, iin, iout, tags=tags)
Expand Down Expand Up @@ -3131,74 +3135,6 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out,

return builder

def _report_mechanism_execution(self, input_val=None, params=None, output=None, context=None):

if input_val is None:
input_val = self.get_input_values(context)
if output is None:
output = self.output_port.parameters.value._get(context)
params = params or {p.name: p._get(context) for p in self.parameters}

if 'mechanism' in self.name or 'Mechanism' in self.name:
mechanism_string = ' '
else:
mechanism_string = ' mechanism'

# FIX: kmantel: previous version would fail on anything but iterables of things that can be cast to floats
# if you want more specific output, you can add conditional tests here
try:
input_string = [float("{:0.3}".format(float(i))) for i in input_val].__str__().strip("[]")
except TypeError:
input_string = input_val

print("\n\'{}\'{} executed:\n- input: {}".format(self.name, mechanism_string, input_string))

try:
include_params = re.match('param(eter)?s?', self.reportOutputPref, flags=re.IGNORECASE)
except TypeError:
include_params = False

if include_params:
print("- params:")
# Sort for consistency of output
params_keys_sorted = sorted(params.keys())
for param_name in params_keys_sorted:
# No need to report:
# function_params here, as they will be reported for the function itself below;
# input_ports or output_ports, as these are inherent in the structure
if param_name in {FUNCTION_PARAMS, INPUT_PORTS, OUTPUT_PORTS}:
continue
param_is_function = False
param_value = params[param_name]
if isinstance(param_value, Function):
param = param_value.name
param_is_function = True
elif isinstance(param_value, type(Function)):
param = param_value.__name__
param_is_function = True
elif isinstance(param_value, (types.FunctionType, types.MethodType)):
param = param_value.__self__.__class__.__name__
param_is_function = True
else:
param = param_value
print("\t{}: {}".format(param_name, str(param).__str__().strip("[]")))
if param_is_function:
# Sort for consistency of output
func_params_keys_sorted = sorted(self.function.parameters.names())
for fct_param_name in func_params_keys_sorted:
print("\t\t{}: {}".
format(fct_param_name,
str(getattr(self.function.parameters, fct_param_name)._get(context)).__str__().strip("[]")))

# FIX: kmantel: previous version would fail on anything but iterables of things that can be cast to floats
# if you want more specific output, you can add conditional tests here
try:
output_string = re.sub(r'[\[,\],\n]', '', str([float("{:0.3}".format(float(i))) for i in output]))
except TypeError:
output_string = output

print("- output: {}".format(output_string))

@tc.typecheck
def _show_structure(self,
show_functions:bool=False,
Expand Down
Loading

0 comments on commit aabefef

Please sign in to comment.