how to set constraints on a ternary relation - alloy

I have this model
sig Factor {}
sig Rule { rule : some Factor }
sig RuleSet { rules : some Rule }
sig EventRuleProperty {}
sig Event {
rulesets : some RuleSet,
rule_properties : rulesets -> Rule -> EventRuleProperty
}
How do I write a fact to restrict the rules in Event.rule_properties have to belong to Event.ruleset?
I declared as
rule_properties : rulesets -> rulesets.rules -> EventRuleProperty
but got a syntax error

Answered there. Please ask such questions in a single place for Alloy users (here on at the Alloy forum) unless you don't get any answer for several days.

Related

Puppet assign class parameters in multiple places

I'm learning puppet (v6), and trying to understand how to set class parameters when a specific node needs an additional parameter, but uses the same class. Maybe a little fuzzy on the terminology, but here's what I'm working on:
MyNode1 needs sshd configured to use a banner and timeout, so using ghoneycutt-ssh, I include the ssh class with parameters:
/modules/MyModule/manifests/MySSH.pp
# Configures SSH
class MyModule::MySSH {
# Using ssh module
class { '::ssh':
sshd_client_alive_count_max => 0,
sshd_client_alive_interval => 900,
sshd_config_banner => '/etc/MyBanner.txt',
}
}
Now I have a second node MyNode2, which requires MySSH above, and also needs to disable forwarding. I started with something like this, where I define only the additional parameter in its own class:
/modules/MyModule/manifests/MySSH_Node2.pp
class MyModule::MySSH_Node2 {
class { '::ssh':
sshd_allow_tcp_forwarding => 'no',
}
}
Then define MyNode2 to include both in my site definition, hoping that puppet merges my ::ssh definitions:
/manifests/site.pp
node MyNode1 {
include MyModule::MySSH
}
node MyNode2 {
include MyModule::MySSH
include MyModule::MySSH_Node2
}
I understand that the above example doesn't work due to error Duplicate declaration: Class[Ssh]. I also tried overriding the class with a new parameter:
class MyModule::MySSH_Node2 {
Class[ssh] {
sshd_allow_tcp_forwarding => 'no',
}
}
But it seems this is not allowed either: Error: Resource Override can only operate on resources, got: Class[ssh]-Type
I'm not sure what the best way to add parameters is. I know I can create a manifest that includes all the parameters needed for this node and apply that instead, but then I end up with duplicate code everywhere.
Is there a reasonable way in modern puppet to assign and merge class parameters like this in puppet?

How to model a bi-directional relationship and make it mandatory?

I'm developing a simple role-based authorization model, using https://profsandhu.com/journals/tissec/p207-ahn.pdf as an inspiration. The code so far is:
abstract sig Object {}
abstract sig Operation {}
sig User, Transaction extends Object {
by: some Permission
} {
by.on = this
}
one sig View, Update, Add, Delete extends Operation {}
sig Permission {
to: one Operation,
on: one Object
}
pred show {
#Permission > 0
}
run show
The first instance generated already shows two issues with my model:
When a permission has an "on" relationship to a user, the reverse relationship "by" must be there as well;
Two permissions on the same user can delete it, which doesn't make sense. There should be always zero or one permission for a particular operation on a user.
Any ideas on how to solve?
You can add these constraints as "facts":
fact {
all p: Permission, u: User | p.on = u implies p in u.by
all u: User | all disj p1,p2 : u.by | p1.to != p2.to
}
Now to verify the last fact, you might also want to check that two permission to the same operation are never owned by the same user:
assert sameOperationImpliesDifferentUser {
all disj p1, p2: Permission | p1.to = p2.to implies no (p1.on & p2.on & User)
}
check sameOperationImpliesDifferentUser
The first instance generated already shows two issues with my model:
When a permission has an "on" relationship to a user, the reverse relationship "by" must be there as well;
It is generally bad idea to have bidirectional links in Alloy since it is so easy to traverse in both directions. Models are significantly easier when you just make them in the most convenient direction. You can always use a function or macro to traverse them backwards. #wmeyer shows you correctly how to constrain the reverse link but your model gets a lot more complex and therefore harder to debug.
Two permissions on the same user can delete it, which doesn't make sense. There should be always zero or one permission for a particular operation on a user.
Why doesn't that make sense? These kind of constraints are hard to enforce and provide as far as I can see very little value. If you get roles in this model, I could see you could end up with multiple identical permissions for an Object. Constraining the model might then cause the model to have no solutions. Daniel Jackson also indicates that the best way to work is to minimize the constraints.
If you still want to enforce no duplicate permissions, I would introduce a Role object that holds the permissions.
I understand (I think) why you want a User to extend Object but it does make the model's solutions awkward to browse. A Role can also help here.
So my 2cts model would be:
abstract sig Object {}
enum Operation { View, Update, Add, Delete }
sig Transaction extends Object {}
sig User extends Object {
role : set Role
}
sig Role {
permit : Operation lone -> Object
}
With a solution:
┌─────────┬─────┐
│this/User│role │
├─────────┼─────┤
│User⁰ │Role²│
│ ├─────┤
│ │Role³│
├─────────┼─────┤
│User¹ │Role⁰│
│ ├─────┤
│ │Role¹│
│ ├─────┤
│ │Role³│
└─────────┴─────┘
┌─────────┬─────────────┐
│this/Role│permit │
├─────────┼───────┬─────┤
│Role⁰ │Delete⁰│User¹│
├─────────┼───────┼─────┤
│Role¹ │Update⁰│User⁰│
│ ├───────┼─────┤
│ │View⁰ │User¹│
├─────────┼────┬──┴─────┤
│Role² │Add⁰│User¹ │
├─────────┼────┴──┬─────┤
│Role³ │Add⁰ │User⁰│
│ ├───────┼─────┤
│ │Update⁰│User¹│
└─────────┴───────┴─────┘

Using captured types to type a class's attributes

I've followed the directions from the answers to the SO question
How can classes be made parametric in Perl 6?. However, I've hit some soft roadblock; I'm trying to type an internal class's attribute using the type capture and getting the following error:
Died with X::TypeCheck::Assignment
in submethod BUILDALL at ...
in method insert at ...
in block <unit> at ...
In the following example, I've typed the class BinaryNode's $.item attribute (with T) but doing so causes the above error:
class BinarySearchTree {
my role BTSImpl[::T] {
my class BinaryNode is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode.new(item => $x)
}
}
method ^parameterize(Mu:U \this, Mu \T) {
my $type := this.^mixin: BTSImpl[T];
$type.^set_name: this.^name ~ '[' ~ T.^name ~ ']';
$type
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
First off, there's almost no need to perform the class + ^parameterize + role trick. It appears in some of the internals because it helps deal with some bootstrapping problems (the kind of fun one has when defining a language in terms of itself). However, in normal Raku code, just write a parametric role instead of a class. From the point of view of the consumer, there's usually no difference; one can:
Call .new on it to make an instance (which actually creates a class, known as a "pun", behind the scenes and makes the instance of that)
In fact, call any method on the type object with the same result; new isn't special
Inherit from it (again, it works on the automatically produced class)
With the added bonus that somebody can also compose it instead of inheriting.
Secondly, there's no relationship between a class defined inside of a role and the enclosing role (this is a general principle: nesting of one package inside of another doesn't imply any relationship between them at an object model level). Thus we need to make that separately generic and instantiate it.
These two get us to:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[T].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
Which really should work, but the compiler seems to get the timing wrong on the BinaryNode[T]. We can work around that by just forcing it to delay the paramerterization until runtime; there's many ways we may do that, but writing BinaryNode[$(T)] compact and cheap (optimizes into pretty much no extra cost). Thus giving a working solution:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[$(T)].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);

This name is ambiguous due to multiple matches:

I have an Alloy model, that have 2 signatures which have a relation that have the same name.
sig Model {
components : set Component
}
sig Port extends Element {
belongsTo : Component
}
sig Component extends Element{
belongsTo : Model,
ports : set Port
}
When I try to access these relation threw join the solver throws me:
A type error has occured:
This name is ambiguous due to multiple matches:
field this/Port <: belongsTo
field this/Component <: belongsTo
Is there any way to specify explicitly that I want to access to the relation belongTo of component and not the port one, when I do:
all m : m.belongsTo |
and m are models?
Thanks.
You can say
all x: m.(Component <: belongsTo) | ...

How to add restrictions to fields of a signature when there are two instances in the model

I have the following Alloy model which describes a group of people. to simplify the problem. Here is a sample code snip.
sig groupofpeople {
member: set person,
country: Country
}{
#person=2
}
sig people {
teamleader: Bool,
position: String
}
So now we have two peoples in a group. Next I want to add some restrictions to the people in the group. For example, I want the two people in a group to always have one team leader and one team member. I use the following fact to do this:
fact {
all n: people , m: people - n {
n.teamleader not in m.teamleader
}
}
Now I encounter a problem which keep me from moving forward. The desired model I'm looking for is that if a group's country is "US", then the position of the teamleader is "US_TL" and position of the team member is "US_TM". If the country is "UK" then the position of teamleader is "UK_TL" and position of the team member is "UK_TM", and so on.
I tried to add something like:
all n: groupofpeople {
(n.country in US => (
n.member.position="US_TL" or
n.member.position= "US_TM")) or
(n.country in UK => (
n.member.position ="UK_TL" or
n.member.position = "UK_TM"))
}
But there are obviously something wrong with the prediction and the model can't generate correct solutions for me. Could you help me to identify the problem in my model?
The model you posted here doesn't compile, so I can't really pinpoint the problem (since there are many, so of which might be just typos). What seems to be incorrect for sure is the or between the two implications in the last all quantifiers: based on your description of the task, it should be and instead.
If I understood the desired properties of your model, here's how I would rewrite it (and if that's not what you intended to achieve, please clarify your question and post a model that is syntactically correct):
open util/boolean
abstract sig Country {}
one sig US extends Country {}
one sig UK extends Country {}
sig GroupOfPeople {
member: set Person,
country: one Country
}{
#member=2
}
sig Person {
teamleader: Bool,
position: String
}
fact {
all g: GroupOfPeople {
all n: g.member, m: g.member - n {
n.teamleader not in m.teamleader
}
}
}
run {
all n: GroupOfPeople {
(n.country in US => (
n.member.position="US_TL" or
n.member.position= "US_TM"))
(n.country in UK => (
n.member.position ="UK_TL" or
n.member.position = "UK_TM"))
}
} for 5
Would it not be nicer to replace the defn of sig Person above by
abstract sig Person{position : String}
sig Leader, Follower extends Person
fact one_leader {
all g : GroupOfPeople | one (g.member & Leader)
}
and even better to put this fact in the invariant of GroupOfPeople:
one (member & Leader)

Resources