Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
Alnos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
Operations
Operations
Incidents
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Michele Volpato
Alnos
Commits
90600f0b
Commit
90600f0b
authored
Nov 24, 2015
by
Michele
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
working on existing methods to match new definitions
parent
ac26df47
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
101 additions
and
79 deletions
+101
-79
learning/learning.py
learning/learning.py
+1
-0
learning/observationtable.py
learning/observationtable.py
+100
-79
No files found.
learning/learning.py
View file @
90600f0b
...
...
@@ -382,6 +382,7 @@ class LearningAlgorithm:
if
label
in
self
.
_teacher
.
getInputAlphabet
():
hyp
.
addTransition
(
assignments
[
row
],
label
,
hyp
.
getChaosDelta
())
# TODO: getPossibleOutputs is deprecated
elif
label
in
self
.
_table
.
getPossibleOutputs
(
row
):
hyp
.
addTransition
(
assignments
[
row
],
label
,
hyp
.
getChaos
())
...
...
learning/observationtable.py
View file @
90600f0b
...
...
@@ -20,7 +20,7 @@
import
csv
import
os
,
inspect
from
itertools
import
permutations
,
product
from
itertools
import
permutations
,
product
,
combinations
import
logging
import
helpers.traces
as
th
import
helpers.deprecator
as
d
...
...
@@ -285,15 +285,12 @@ class Table:
return
modified
def
isNotQuiescenceReducible
(
self
):
newSuffixes
=
set
()
hMinusSuffixes
=
self
.
_isNotReducible
()
newSuffixes
=
newSuffixes
.
union
(
hMinusSuffixes
)
if
newSuffixes
!=
set
():
newSuffixes
=
self
.
_isNotReducible
()
if
newSuffixes
:
# priority to hMinus suffixes
return
newSuffixes
else
:
hPlusSuffixes
=
self
.
_isNotReducible
(
chaos
=
True
)
return
newSuffixes
.
union
(
hPlusSuffixes
)
return
self
.
_isNotReducible
(
chaos
=
True
)
def
_isNotReducible
(
self
,
chaos
=
False
):
# function used for filtering rows, we want only those which
...
...
@@ -301,7 +298,7 @@ class Table:
rowsWithQuiescence
=
lambda
x
:
self
.
_quiescence
in
self
.
_entries
[
x
][
0
]
# past contains the pair of rows already visited.
# If I visited already a pair for one loop
of the following for loop
,
# If I visited already a pair for one loop,
# I do not need to check it again for other loops. Thus past is outside
# the for loop.
past
=
set
()
...
...
@@ -313,21 +310,25 @@ class Table:
moreSpecific
=
lambda
x
:
lambda
y
:
self
.
_moreSpecificRow
(
y
,
x
,
chaos
)
listOfRows
=
list
(
filter
(
moreSpecific
(
row1Extended
),
self
.
_rowsInS
))
# I want the most specific one
row2
=
listOfRows
.
pop
()
for
row
in
listOfRows
:
if
self
.
_moreSpecificRow
(
row
,
row2
,
chaos
):
row2
=
row
if
row1
==
row2
:
# same row, simulation is trivial
continue
if
(
row1
,
row2
)
in
past
:
# I already visited this pair. Go to next state enabling quiescence
continue
rowsToCheck
=
set
()
# get representative of each equivalence class
eqClasses
=
self
.
getEquivalenceClasses
(
chaos
)
for
row
in
eqClasses
:
if
row
in
listOfRows
:
rowsToCheck
.
add
(
row
)
wait
=
set
()
wait
.
add
((
row1
,
row2
,
()))
for
row
in
rowsToCheck
:
if
row1
==
row
:
# same row, simulation is trivial
continue
if
(
row1
,
row
)
in
past
:
# I already visited this pair. Go to next state enabling quiescence
continue
wait
.
add
((
row1
,
row
,
()))
while
wait
:
current
=
wait
.
pop
()
past
.
add
((
current
[
0
],
current
[
1
]))
...
...
@@ -337,10 +338,9 @@ class Table:
# If we are in chaos_quiescence only quiescence is enabled
enabledRow2
.
add
(
self
.
_quiescence
)
else
:
# input enabledness
outputs
=
self
.
_entries
[
current
[
1
]][
0
]
outputs
=
self
.
getOutputs
(
current
[
1
])
enabledInputs
=
self
.
_possibleInputs
(
current
[
1
],
outputs
)
enabledRow2
=
self
.
_entries
[
current
[
1
]][
0
]
.
union
(
enabledInputs
)
enabledRow2
=
outputs
.
union
(
enabledInputs
)
for
label
in
enabledRow2
:
enabledRow1
=
set
()
if
current
[
0
]
==
"chaos_quiescence"
:
...
...
@@ -348,9 +348,9 @@ class Table:
# enabled
enabledRow1
.
add
(
self
.
_quiescence
)
else
:
outputs
=
self
.
_entries
[
current
[
0
]][
0
]
outputs
=
self
.
getOutputs
(
current
[
0
])
enabledInputs
=
self
.
_possibleInputs
(
current
[
0
],
outputs
)
enabledRow1
=
self
.
_entries
[
current
[
0
]][
0
]
.
union
(
enabledInputs
)
enabledRow1
=
outputs
.
union
(
enabledInputs
)
if
label
not
in
enabledRow1
:
suffixes
=
set
()
suffixes
.
add
(
current
[
2
])
...
...
@@ -365,13 +365,15 @@ class Table:
newRow1
=
"chaos_quiescence"
else
:
try
:
# the table is closed, there should be
a
row
# the table is closed, there should be
some
row
# more specific than current[0] + (label,) in S
listOfRows
=
list
(
filter
(
moreSpecific
(
current
[
0
]
+
(
label
,)),
self
.
_rowsInS
))
newRow1
=
listOfRows
.
pop
()
for
row
in
listOfRows
:
if
self
.
_moreSpecificRow
(
row
,
newRow1
,
chaos
):
newRow1
=
row
newRow1
=
set
()
# get representative of each equivalence class
eqClasses
=
self
.
getEquivalenceClasses
(
chaos
)
for
row
in
eqClasses
:
if
row
in
listOfRows
:
newRow1
.
add
(
row
)
except
IndexError
as
error
:
# current[0] + (label,) might not have
# corresponding row in S. This is the case when
...
...
@@ -393,10 +395,12 @@ class Table:
else
:
try
:
listOfRows
=
list
(
filter
(
moreSpecific
(
current
[
1
]
+
(
label
,)),
self
.
_rowsInS
))
newRow2
=
listOfRows
.
pop
()
for
row
in
listOfRows
:
if
self
.
_moreSpecificRow
(
row
,
newRow2
,
chaos
):
newRow2
=
row
newRow2
=
set
()
# get representative of each equivalence class
eqClasses
=
self
.
getEquivalenceClasses
(
chaos
)
for
row
in
eqClasses
:
if
row
in
listOfRows
:
newRow2
.
add
(
row
)
except
IndexError
as
error
:
# current[1] + (label,) might not have
# corresponding row in S. This is the case when
...
...
@@ -412,40 +416,39 @@ class Table:
self
.
_logger
.
error
(
"Table printed in ./tables/_error_table.csv"
)
self
.
_logger
.
error
(
error
)
raise
if
(
newRow1
,
newRow2
)
not
in
past
and
newRow1
!=
newRow2
:
wait
.
add
((
newRow1
,
newRow2
,
current
[
2
]
+
(
label
,)))
for
(
newSingle1
,
newSingle2
)
in
product
(
newRow1
,
newRow2
):
if
(
newSingle1
,
newSingle2
)
not
in
past
and
newSingle1
!=
newSingle2
:
wait
.
add
((
newSingle1
,
newSingle2
,
current
[
2
]
+
(
label
,)))
return
set
()
def
isNotGloballyConsistent
(
self
):
newSuffixes
=
set
()
hMinusSuffixes
=
self
.
_isNotConsistent
()
newSuffixes
.
union
(
hMinusSuffixes
)
newSuffixes
=
self
.
_isNotConsistent
()
if
newSuffixes
:
# priority to hMinus suffixes
return
newSuffixes
else
:
hPlusSuffixes
=
self
.
_isNotConsistent
(
chaos
=
True
)
return
newSuffixes
.
union
(
hPlusSuffixes
)
return
self
.
_isNotConsistent
(
chaos
=
True
)
def
_isNotConsistent
(
self
,
chaos
=
False
):
# TODO refactor entire method?
# get all combinations of rows in S, with repetitions
combi
=
permutations
(
self
.
_rowsInS
,
2
)
# get all combinations of rows in S, with repetitions for hPlus
combi
=
combinations
(
self
.
_rowsInS
,
2
)
if
not
chaos
:
combi
=
permutations
(
self
.
_rowsInS
,
2
)
newColumns
=
set
()
for
row1
,
row2
in
combi
:
# If the rows are in the same equivalence class
if
self
.
_moreSpecificRow
(
row1
,
row2
,
chaos
):
#row2 is in the equivalence class defined by row1
# get all possible (enabled) labels
# get all possible (enabled) labels
of row1
inputs
=
self
.
_possibleInputs
(
row1
)
outputs
=
self
.
_entries
[
row1
][
0
]
outputs
=
self
.
getOutputs
(
row1
)
labels
=
inputs
.
union
(
outputs
)
for
label
in
labels
:
rowExt1
=
th
.
flatten
(
row1
+
(
label
,),
self
.
_quiescence
)
rowExt2
=
rowExt1
=
th
.
flatten
(
row2
+
(
label
,),
self
.
_quiescence
)
rowExt2
=
th
.
flatten
(
row2
+
(
label
,),
self
.
_quiescence
)
# rowExt1 must be in Rows, because label is either an
# enabled input after row, or an observed output.
if
rowExt1
not
in
self
.
_rows
:
...
...
@@ -455,7 +458,6 @@ class Table:
# of _moreSpecificRow()
if
chaos
==
False
:
# if we are checking Hminus, then there is an error
# TODO: might be that I did not add a one letter extension when needed?
self
.
_logger
.
error
(
"Error while checking consistency for Hminus: the prefix "
+
str
(
rowExt1
)
+
" should be a row, but it is not."
)
self
.
printTable
(
prefix
=
"_error"
)
self
.
_logger
.
error
(
"Table printed in ./tables/_error_table.csv"
)
...
...
@@ -463,7 +465,7 @@ class Table:
else
:
# if we are checking Hplus (and label is an output)
# then there is a transition to a chaotic state
if
label
in
self
.
_possibleOutputs
(
row1
)
:
if
label
in
outputs
:
if
label
==
self
.
_quiescence
:
# rowExt1 is chaos_quiescence
rowExt1
=
"chaos_quiescence"
...
...
@@ -471,22 +473,30 @@ class Table:
# rowExt1 is chaos
rowExt1
=
"chaos"
else
:
# label is an input, error.
self
.
_logger
.
error
(
"Error while checking consistency for Hplus: the prefix "
+
str
(
rowExt1
)
+
" should be a row, but it is not."
)
self
.
printTable
(
prefix
=
"_error"
)
self
.
_logger
.
error
(
"Table printed in ./tables/_error_table.csv"
)
if
not
rowExt2
in
self
.
_rows
:
# rowExt2 is not in rows. If label is an input then
# row2 does not enable it: row1 should not be more
# specific than row2
if
label
in
inputs
:
self
.
_logger
.
error
(
"Error while checking consistency: the prefix "
+
str
(
rowExt2
)
+
" should be a row, but it is not."
)
if
chaos
==
False
:
# if we are checking Hminus, then there is an error
self
.
_logger
.
error
(
"Error while checking consistency for Hminus: the prefix "
+
str
(
rowExt2
)
+
" should be a row, but it is not."
)
self
.
printTable
(
prefix
=
"_error"
)
self
.
_logger
.
error
(
"Table printed in ./tables/_error_table.csv"
)
raise
# If label is an output, then ok (being less specific,
# this is allowed)
else
:
continue
# rowExt2 is not in rows. If label is an input then
# row2 does not enable it: row1 should not be more
# specific than row2
if
label
in
inputs
:
self
.
_logger
.
error
(
"Error while checking consistency: the prefix "
+
str
(
rowExt2
)
+
" should be a row, but it is not."
)
self
.
printTable
(
prefix
=
"_error"
)
self
.
_logger
.
error
(
"Table printed in ./tables/_error_table.csv"
)
raise
# If label is an output, then ok (being less specific,
# this is allowed)
else
:
continue
# rowExt1 in self._rows and rowExt2 in self._rows
# I could call self._moreSpecificRow() but then
...
...
@@ -498,9 +508,15 @@ class Table:
entry2
=
th
.
flatten
(
rowExt2
+
column
,
self
.
_quiescence
)
if
(
rowExt1
==
"chaos_quiescence"
or
rowExt1
==
"chaos"
):
#TODO: check if entry2+column has chaotic behaviour
print
(
erfefr
)
continue
# We are checking hPlus
# Does entry2 has chaotic behaviour?
extendedOutputs
=
self
.
_outputs
.
union
((
self
.
_quiescence
,))
if
self
.
_entries
[
entry2
]
!=
extendedOutputs
:
self
.
_logger
.
warning
(
"Checking chaotic behaviour of entry2: not chaotic"
)
newColumns
.
add
((
label
,)
+
column
)
break
else
:
continue
entry1
=
th
.
flatten
(
rowExt1
+
column
,
self
.
_quiescence
)
if
(
entry1
not
in
self
.
_entries
and
...
...
@@ -518,11 +534,11 @@ class Table:
newColumns
.
add
((
label
,)
+
column
)
break
if
newColumns
:
# TODO: o
nly one suffix per round, ok?
break
if
newColumns
:
break
#
if newColumns:
# # O
nly one suffix per round, ok?
#
break
#
if newColumns:
#
break
return
newColumns
...
...
@@ -565,7 +581,9 @@ class Table:
# is the entry final? If False, we can still observe some outputs
def
_isFinal
(
self
,
entry
):
# TODO: check if entries contains entry
if
entry
not
in
self
.
_entries
.
keys
():
self
.
_logger
.
warning
(
"Checking if entry is final: entry is not in the table."
)
return
False
return
self
.
_entries
[
entry
][
0
]
==
self
.
_entries
[
entry
][
1
]
# get a final entry with given set of outputs
...
...
@@ -575,7 +593,6 @@ class Table:
# Private method for creating entries from rows and columns
def
_createEntries
(
self
):
for
row
in
self
.
_rows
:
# Row should be flattened.
for
column
in
self
.
_columns
:
newEntry
=
row
+
column
# If there are multiple quiescence in sequence, reduce to
...
...
@@ -584,6 +601,7 @@ class Table:
# Check if the concatenation of the two tuples is
# already in _entries:
if
filteredEntry
not
in
self
.
_entries
.
keys
():
# Special cases:
if
(
len
(
row
)
>
0
and
row
[
-
1
]
==
self
.
_quiescence
and
len
(
column
)
>
0
and
column
[
0
]
in
self
.
_outputs
):
# If row ends in delta and column starts with an output,
...
...
@@ -599,7 +617,7 @@ class Table:
# if columns starts with output x (or quiescence) and
# x not in entry[row+()] then mark row+column as
# 'it could be impossible to obtain'
# if row + () is
true
, we will NEVER observe that
# if row + () is
final
, we will NEVER observe that
# output
self
.
_entries
[
filteredEntry
]
=
self
.
_emptyFinalEntry
(
filteredEntry
)
continue
...
...
@@ -627,10 +645,12 @@ class Table:
# quiescence, then the entry for row is the same as the
# entry for the proper prefix [VT15]
if
len
(
row
)
>
0
and
row
[
-
1
]
==
self
.
_quiescence
:
# TODO: check that entries contains row[:-1]
(
outputs
,
observed
)
=
self
.
_entries
[
row
[:
-
1
]]
if
self
.
_isFinal
(
row
[:
-
1
])
and
outputs
==
set
((
self
.
_quiescence
,)):
return
True
if
row
[:
-
1
]
not
in
self
.
_entries
.
keys
():
self
.
_logger
.
warning
(
"Checking delta loops: shorter trace is not in the table."
)
else
:
(
outputs
,
observed
)
=
self
.
_entries
[
row
[:
-
1
]]
if
self
.
_isFinal
(
row
[:
-
1
])
and
outputs
==
set
((
self
.
_quiescence
,)):
return
True
return
False
def
getDeltaTraces
(
self
,
trace
):
...
...
@@ -659,6 +679,7 @@ class Table:
# Return the set of outputs that can be observed after trace
# TODO: not clear the purpose of this method. rename?
@
d
.
deprecated
def
getPossibleOutputs
(
self
,
trace
):
if
trace
in
self
.
_entries
and
self
.
_entries
[
trace
][
1
]:
return
self
.
_entries
[
trace
][
0
]
...
...
@@ -666,6 +687,7 @@ class Table:
return
self
.
_possibleOutputs
(
trace
,
None
)
# Update an entry in the table. If it does not exist, create it
# observation is the answer of the observation orale
def
updateEntry
(
self
,
trace
,
output
=
None
,
observation
=
None
):
trace
=
th
.
flatten
(
trace
,
self
.
_quiescence
)
if
trace
in
self
.
_entries
:
...
...
@@ -682,10 +704,8 @@ class Table:
outputs
.
add
(
output
)
if
observation
==
None
or
observation
==
False
:
self
.
_entries
[
trace
]
=
self
.
_emptyEntry
(
trace
)
observed
=
self
.
_entries
[
trace
][
1
]
else
:
observed
=
outputs
self
.
_entries
[
trace
]
=
(
outputs
.
copy
(),
observed
.
copy
())
self
.
_entries
[
trace
]
=
self
.
_finalEntry
(
trace
,
outputs
)
# given a trace, query outputPurpose for the outputs that are possibly
# enabled after it
...
...
@@ -706,7 +726,8 @@ class Table:
# Given two entries, check if the former is more specific than the latter
# entry1 ⊑ entry2 => entry2.first is subset of entry1.first and entry1.second is subset of entry2.second
def
_moreSpecificEntry
(
self
,
entry1
,
entry2
,
plus
):
# TODO: check if entry1 and entry2 are in entries
if
(
entry1
not
in
self
.
_entries
.
values
()
or
entry2
not
in
self
.
_entries
.
values
()):
self
.
_logger
.
warning
(
"Checking relation between entries: one or both are not in the table."
)
if
not
plus
:
return
entry1
[
0
]
==
entry2
[
0
]
# equality
#return entry2[0].issubset(entry1[0]) # inclusion
...
...
@@ -717,7 +738,7 @@ class Table:
# row1 ⊑ row2 => for each column, row1[column] ⊑ row2[column]
def
_moreSpecificRow
(
self
,
row1
,
row2
,
plus
=
False
):
# First: if they do not enable the same inputs, they are not in such
# a relation
# a relation
TODO: should this check be in moreSpecificEntry instead?
outputs1
=
self
.
_entries
[
th
.
flatten
(
row1
,
self
.
_quiescence
)][
0
]
outputs2
=
self
.
_entries
[
th
.
flatten
(
row2
,
self
.
_quiescence
)][
0
]
inputs1
=
self
.
_possibleInputs
(
th
.
flatten
(
row1
,
self
.
_quiescence
),
outputs1
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment