Answer Set Programming: how to assign students to a group such that no two students who dislike each other are in a same group - answer-set-programming

I am a beginner to Answer Set Programming. I want to group all students in a different groups such that:
1. Each group has 3 to 4 students
2. No two students who dislike each other are in the same group.
3. And we can not assign same student to different groups.
I have written like:
%suppose there are total 6 students
student(1..6).
%suppose there are 2 groups
group(1..2).
%1 and 4 like each other, 4 and 5 dislike each other
dislike(1,4). dislike(5,4).
% each group has 3 to 4 students
:- group(G), #count {S : in(S,G)} < 3.
:- group(G), #count {S : in(S,G)} > 4.
I have added the constraint for how many students each group can contain but have got no clue about how satisfy other two conditions.
Your help will be greatly appreciated. Thanks.

Try this:
student(1..6).
group(1..2).
dislike(1,4). dislike(5,4).
% each group has 3 to 4 students
:- group(G), #count {S : in(S,G)} < 3.
:- group(G), #count {S : in(S,G)} > 4.
%no two students who dislike each other are in the same group
:-in(X, G1), in(Y,G2), dislike(X,Y), group(G1), group(G2), G1==G2.
%each student should be assigned to only one group
1{in(S,G): group(G)}1 :- student(S).
#show in/2.

Related

Aggregate the columns based on a condition in SPSS modeler

I would like to add the values based on a column:
For example: The input table looks like this:
USERS Order_date Number_of_orders
alice 01-01-2014 2
alice 19-01-2014 5
alice 20-05-2014 8
bob 03-01-2014 1
bob 08-04-2014 9
The output should be like:
USERS Order_date Number_of_orders(NEW)
alice 01-01-2014 2
alice 19-01-2014 7
alice 20-05-2014 15
bob 03-01-2014 1
bob 08-04-2014 10
Number_of_orders(NEW) is the sum of total orders in the same day + the total number of previous orders of that user.
Please let me know how to do this with SPSS modeler.
I know this is fairly late but what I would do is:
1) create a conditional derive node if NAME /= #OFFSET(NAME,1) or #NULL(NAME) then Number_of_orders else null
2) create filler node if #NULL(Derive325) then #OFFSET(Derive325,1)+Number_of_orders
Just FYI, if I were to look for this, I would use the word cumulative, not aggregate

Best way to maintain an ordered list in PostgreSQL?

Say I have a table called list, where there are items like these (the ids are random uuids):
id rank text
--- ----- -----
x 0 Hello
x 1 World
x 2 Foo
x 3 Bar
x 4 Baz
I want to maintain the property that rank column always goes from 0 to n-1 (n being the number of rows)---if a client asks to insert an item with rank = 3, then the pg server should push the current 3 and 4 to 4 and 5, respectively:
id rank text
--- ----- -----
x 0 Hello
x 1 World
x 2 Foo
x 3 New Item!
x 4 Bar
x 5 Baz
My current strategy is to have a dedicated insertion function add_item(item) that scans through the table, filter out items with rank equal or greater than that of the item being inserted, and increment those ranks by one. However, I think this approach will run into all sorts of problems---like race conditions.
Is there a more standard practice or more robust approach?
Note: The rank column is completely independent of rest of the columns, and insertion is not the only operation I need to support. Think of it as the back-end of a sortable to-do list, and the user can add/delete/reorder the items on the fly.
Doing verbatim what you suggest might be difficult or not possible at all, but I can suggest a workaround. Maintain a new column ts which stores the time a record is inserted. Then, insert the current time along with rest of the record, i.e.
id rank text ts
--- ----- ----- --------------------
x 0 Hello 2017-12-01 12:34:23
x 1 World 2017-12-03 04:20:01
x 2 Foo ...
x 3 New Item! 2017-12-12 11:26:32
x 3 Bar 2017-12-10 14:05:43
x 4 Baz ...
Now we can easily generate the ordering you want via a query:
SELECT id, rank, text,
ROW_NUMBER() OVER (ORDER BY rank, ts DESC) new_rank
FROM yourTable;
This would generate 0 to 5 ranks in the above sample table. The basic idea is to just use the already existing rank column, but to let the timestamp break the tie in ordering should the same rank appear more than once.
you can wrap it up to function if you think its worth of:
t=# with u as (
update r set rank = rank + 1 where rank >= 3
)
insert into r values('x',3,'New val!')
;
INSERT 0 1
the result:
t=# select * from r;
id | rank | text
----+------+----------
x | 0 | Hello
x | 1 | World
x | 2 | Foo
x | 3 | New val!
x | 4 | Bar
x | 5 | Baz
(6 rows)
also worth of mention you might have concurrency "chasing condition" problem on highly loaded systems. the code above is just a sample
You can have a “computed rank” which is a double precision and a “displayed rank” which is an integer that is computed using the row_number window function on output.
When a row is inserted that should rank between two rows, compute the new rank as the arithmetic mean of the two ranks.
The advantage is that you don't have to update existing rows.
The down side is that you have to calculate the displayed ranks before you can insert a new row so that you know where to insert it.
This solution (like all others) are subject to race conditions.
To deal with these, you can either use table locks or serializable transactions.
The only way to prevent a race condition would be to lock the table
https://www.postgresql.org/docs/current/sql-lock.html
Of course this would slow you down if there are lots of updates and inserts.
If can somehow limit the scope of your updates then you can do a SELECT .... FOR UPDATE on that scope. For example if the records have a parent_id you can do a select for update on the parent record first and any other insert who does the same select for update would have to wait till your transaction is done.
https://www.postgresql.org/docs/current/explicit-locking.html#:~:text=5.-,Advisory%20Locks,application%20to%20use%20them%20correctly.
Read the section on advisory locks to see if you can use those in your application. They are not enforced by the system so you'll need to be careful of how you write your application.

Retrieve field based on record field

I have 3 tables
items,
item_units,
order_items
First table items has the list of items that can be ordered.
Second table item_units has units for the items as well as the amount of those items in this unit
Third table has items that were ordered... ie... item_code , unit, qty
Here are the columns for items
[item_code]
,[desc]
Here are the columns for item_units
,[item_code]
,[unit]
,[amount]
,[price]
,[default_sprd_sht]
Here are the columns for order_items
,[order_id]
,[item_code]
,[item_desc]
,[unit]
,[qty]
,[price]
Note the [default_sprd_sht]. This field is a boolean. If it's set to true this unit is never put into order_items table. This field will be used as calculation field.
For example:
If 1 customer orders 2 6 packs of bread and another orders 3 dozens of bread, the baker needs to know how many pans of bread to make.
Now a 6 pack unit has 6 breads as amount, meaning 2 * 6 = 12. And a dozen unit has 12 breads.. 12 * 3 = 36. A pan bread unit has 20 breads. So i need to add up all the bread units amounts and divide them by the pan amount like so
((2*6) + (12 * 3)) / 20 = 2.4
So the first thing I did to create a report for the baker was
Create a group for order_items.item_code and then order_item.unit.
This needs to be done since the same item and unit cobination will be repeated in different orders. The baker needs to see how many bagels or breads he needs to bake in total.
in the order_item.unit group header I created a formula field that multiplies the order_item.unit by item.amount
Sum ({order_items.qty}, {order_items.unit}) * {items_units.amount}
That was easy.
But I aslo need to group all order items if there exists a record in the items_units with the same item_code and with [default_sprd_sht] set to true
This would look like so
(Sum ({order_items.qty}, {order_items.unit}) * {items_units.amount}) / (get amount for unit with the same item_code and [default_sprd_sht] = 1)
I have two problems accomplishing this.
How to check if this order item has a unit with same item_code and
[default_sprd_sht] = 1?
How to further group order items only if there is a unit with same
item_code and [default_sprd_sht] = 1?

Calculate value based on existence of records matching given criteria - FileMaker Pro 13

How can I write a calculation field in a table that outputs '1' if there are other (related) records in the same table that meet a given set of criteria and '0' otherwise?
Here's my problem explained in more detail:
I have a table containing 'students' and another containing 'exam results'. The 'exam results' table looks like this:
StudentID SubjectID Level Result
3234 1 2 A-
3234 2 4 B+
4739 1 4 C+
A student can only pass a Level 4 exam in subject 2 if they have also passed a Level 2 exam in subject 1 with a B+ or higher. I want to define a field in the 'students' table that contains a '1' if there exists an exam result belonging to the right student that meets these criteria and a '0' otherwise.
What would be the best way to do this?
Let us take an example of a Results table where the results are also calculated as a numeric value, e.g.
StudentID SubjectID Level Result cResultNum
3234 1 2 A- 95
3234 2 4 B+ 85
4739 1 4 C+ 75
and an Exams table with the following fields (among others):
RequiredSubjectID
RequiredLevel
RequiredResultNum
Given these, you can construct a relationship between Exams and (another occurrence of) Results as:
Exams::RequiredSubjectID = Results 2::SubjectID
AND
Exams::RequiredLevel = Results 2::Level
AND
Exams::RequiredResultNum ≤ Results 2::cResultNum
This allows each exam record to calculate a list of students that are eligible to take that exam as =
List ( Results 2::StudentID )
I want to define a field in the 'students' table that contains a '1'
if there exists an exam result belonging to the right student that
meets these criteria and a '0' otherwise.
This request is unclear, because there are many exams a student may want to take, and a field in the Students table can calculate only one result.
You need to do a self-join in the table for the field you want to check, for example:
Exam::Level = Exam2::Level
Exam::Student = Exam2::Student
And for the "was passed" criteria I think you could do an "If" on the calculation like this:
If ( Last(Exam2::Result) = "D" and ...(all the pass values) ; 1 ; 0 )
Edit:
It could be just with the not pass value hehe I miss that it will be like this:
If ( Last(Exam2::Result) = "F" ; 0 ; 1 )
I hope this helps you.

how to get grouped query data from the resultset?

I want to get grouped data from a table in sqlite. For example, the table is like below:
Name Group Price
a 1 10
b 1 9
c 1 10
d 2 11
e 2 10
f 3 12
g 3 10
h 1 11
Now I want get all data grouped by the Group column, each group in one array, namely
array1 = {{a,1,10},{b,1,9},{c,1,10},{h,1,11}};
array2 = {{d,2,11},{e,2,10}};
array3 = {{f,3,12},{g,3,10}}.
Because i need these 2 dimension arrays to populate the grouped table view. the sql statement maybe NSString *sql = #"SELECT * FROM table GROUP BY Group"; But I wonder how to get the data from the resultset. I am using the FMDB.
Any help is appreciated.
Get the data from sql with a normal SELECT statement, ordered by group and name:
SELECT * FROM table ORDER BY group, name;
Then in code, build your arrays, switching to fill the next array when the group id changes.
Let me clear about GroupBy. You can group data but that time its require group function on other columns.
e.g. Table has list of students in which there are gender group mean Male & Female group so we can group this table by Gender which will return two set . Now we need to perform some operation on result column.
e.g. Maximum marks or Average marks of each group
In your case you want to group but what kind of operation you require on price column ?.
e.g. below query will return group with max price.
SELECT Group,MAX(Price) AS MaxPriceByEachGroup FROM TABLE GROUP BY(group)