Clingo: operation undefined - logic-programming

Adding the following rule to my code results in an error message (info: operation undefined (Max-Min)):
rank_difference(Room, Deck, Diff) :-
played(Room, Deck),
Min = #min {Rank: seat(Player, Room, Deck), rank(Player, Rank)},
Max = #max {Rank: seat(Player, Room, Deck), rank(Player, Rank)},
Diff = Max - Min.
played(Room, Deck) implies that there exists at least one seat(Player, Room, Deck) predicate (in fact that there exist exactly 3 or 4) while rank(Player, Rank) exists for each player so this isn't supposed to be an empty set issue.
Update - Runnable example (without any of the constraints):
#const nRounds = 4.
#const nPlayers = 13.
#const nRooms = 4.
#const nDecks = 10.
player(1..nPlayers).
room(1..nRooms).
deck(1..nDecks).
writer(1,1;2,2;3,3;4,4).
rank(Player, Player) :- player(Player).
nRounds { round(Player, 1..nDecks) } nRounds :- player(Player).
{ played(Room, Deck) } :- room(Room), deck(Deck).
3 { seat(Player, Room, Deck) : round(Player, Deck) } 4 :- played(Room, Deck).
rank_difference(Room, Deck, Diff) :-
played(Room, Deck),
Min = #min {Rank: seat(Player, Room, Deck), rank(Player, Rank)},
Max = #max {Rank: seat(Player, Room, Deck), rank(Player, Rank)},
Diff = Max - Min.

The grounder can not infer that the set inside your min/max aggregate isn't actually empty. Therefore valid solutions (at least during grounding) are also #sup for #min and #inf for #max.
https://en.wikipedia.org/wiki/Infimum_and_supremum
Doing arithmetic with these values is undefined.
You have to explicitly bound the result of the operation so in this case:
rank_difference(Room, Deck, Diff) :-
played(Room, Deck),
Min = #min {Rank: seat(Player, Room, Deck), rank(Player, Rank)},
Max = #max {Rank: seat(Player, Room, Deck), rank(Player, Rank)},
rank(_, Min), rank(_, Max),
Diff = Max - Min.

Related

How do I apply the modulo such that an index is never 0?

Suppose I index the days of the week starting with 1 as Monday and 7 as Sunday. I have four arrays x, y, z and r which store variables for each day of the week. For example, x[1] is the amount of revenue earned on Monday, y[7] is the amount of revenue carried over from Sunday and z[6] is the amount of revenue saved from Saturday.
The total revenue on Monday is x[1] + y[7] + z[6] = r[1]. Similarly, the total revenue on Tuesday is x[2] + y[1] + z[6] = r[2].
I am trying to write a for loop something like this:
for i in 1:7
x[i] + y[i-1] + z[i-2] = d[i]
end
Where when i = 1 and i = 2, the indexing does not become less than or equal to 0 (my indexing starts at 1 and if the result is 0 I get an out of bounds error).
I tried using the modulo function to assist with this, but I realize I am getting 0 in some cases, no matter what values I try. For example, adding 7 and then applying modulo 7 ensures that z[i-2] is z[6] when i = 1, but gives y[i-1] = y[0] when i = 1:
for i in 1:7
x[(i+7)%7] + y[(i-1+7)%7] + z[(i-2+7)%7] = d[(i+7)%7]
end
Is there an efficient solution for this?
Add 6 instead of 7 inside the modulo and add one outside.
( i + 6 ) % 7 + 1

Loops and output

I am trying to get a bit handy with my loop and output statements, currently I have a loan which amortizes like such:
data have;
input Payment2017 Payment2018 Payment2019 Payment2020;
datalines;
100 10 10 10;
run;
I'm trying to create a maturity and re-issuance profile that looks like this, I will explain the logic when I submit my current code:
data want;
input;
P2017 P2018 P2019 P2020 F1 F2 F3 MP2017 MP2018 MP2019 MP2020 NI2017 NI2018 NI2019 NI2020;
datalines;
100 10 10 10 0.1 0.1 0.1 100 10 10 10 0 0 0 0
100 10 10 10 0.1 0.1 0.1 0 10 1 1 0 10 0 0
100 10 10 10 0.1 0.1 0.1 0 0 11 1.1 0 0 11 0
100 10 10 10 0.1 0.1 0.1 0 0 0 12.1 0 0 0 12.1
;
run;
so the logic is that:
Payment2017 = the balance at the start of the year
Payment2018 - 2020 = the amount paid each period
F1-F3 is the fraction of the loan that is being paid each period.
MP2017-MP2020 is the amount of the loan that is paid back - essentially it is
mp(i) = p(i) *f(i)
NI2017-NI2020 is the amount that is newly issued if you assume that each time I pay off a bit of the loan , it is added back onto the loan. so the current code which I am using looks like this but i'm having some issues with the ouput and loops.
data want;
set have;
array MaturityProfile(4) MaturityProfile&StartDate-MaturityProfile&EndDate;
array NewIssuance(4) NewIssuance&StartDate - NewIssuance&EndDate;
array p(4) payment&StartDate-payment&EndDate;
array fraction(3); * track constant fraction determined at start of profile;
MaturityProfile(1) = P(1);
do i = 1 to 3;
fraction(i) = p(i+1) / p(1);
end;
iter=2;
do j = 1 to 2;
do i = iter to 4;
MaturityProfile(i) = P(j) * Fraction(i-j);
newissuance(i) = MaturityProfile(i);
end;
output;
iter=iter+1;
end;
output;
*MaturityProfile(4) = ( P(3) + MaturityProfile(2) ) * Fraction(1);
*output;
drop i;
drop j;
drop iter;
run;
I'm trying to find a way of for the first two rows, keeping it how it outputs currently but the third row needs the sum of the column for the second row ( or the newissuance2019) and then multiply that by fraction 1
so basically the output to look like the table I've put in the data want step.
TIA.
I managed to fix this by doing:
data want;
set have;
array MaturityProfile(4) MaturityProfile&StartDate-MaturityProfile&EndDate;
array NewIssuance(4) NewIssuance&StartDate - NewIssuance&EndDate;
array p(4) payment&StartDate-payment&EndDate;
array fraction(3); * track constant fraction determined at start of profile;
array Total(4) Total1-Total4;
MaturityProfile(1) = P(1);
do i = 1 to 3;
fraction(i) = p(i+1) / p(1);
end;
iter=2;
do j = 1 to 2;
do i = iter to 4;
MaturityProfile(i) = P(j) * Fraction(i-j);
Total(i)=MaturityProfile(i) + P(i);
end;
output;
iter=iter+1;
end;
MaturityProfile(4) = Total(3) * Fraction(1);
output;
drop i;
drop j;
drop iter;
run;

Embedded Implicit Loops in SAS with two Set Statements

I have the below code to track specific manufacturer coupon issuings. Each issue can have dollars in the redeemed, expired and remaining fields. I have an ISSUE table that gives all of the issuings and amounts and the REDEMPTIONS table that is an accounting of amounts redeemed or expired. The objective is to track all coupon dollars for each issue by putting the appropriate amounts in each category.
This code is supposed to loop through the ISSUE table and tie matching records from the REDEMPTIONS table to each record in the ISSUE table.
/*create sample tables*/
data ISSUE; input
Coupon_NBR $ AMOUNT REDEEMED EXPIRED REMAINING; datalines;
A 500 0 0 500
A 500 0 0 500
B 500 0 0 500
B 500 0 0 500
B 500 0 0 500
B 1250 0 0 1250
B 750 0 0 750
C 500 0 0 500
C 500 0 0 500
C 500 0 0 500
C 500 0 0 500
C 500 0 0 500
run;
data REDEMPTIONS; input
Redemp_coupon_NBR $ TRANS_AMOUNT TYPE $16.; datalines;
A -150 REDEMPTION
A -350 REDEMPTION
A -200 EXPIRATION
B -300 REDEMPTION
B -200 EXPIRATION
B -1000 REDEMPTION
C -1500 REDEMPTION
C -500 EXPIRATION
run;
/*begin looping code*/
data Tracking;
if _n_ = 1 then Link get_redemptions;
set issue;
if (remaining > 0) and (Coupon_NBR = Redemp_coupon_NBR) then do;
if trans_amount = 0 then
link get_redemptions;
if trans_amount + remaining >=0 then do;
remaining = remaining + trans_amount;
if type = 'EXPIRATION' then;
expired = expired - trans_amount;
if type = 'REDEMPTION' then;
redeemed = redeemed - trans_amount;
link get_redemptions;
end;
else do;
remaining = 0;
if type = 'EXPIRATION' then do;
expired = expired - trans_amount;
end;
else do;
redeemed = redeemed - trans_amount;
trans_amount = trans_amount + remaining;
remaining = 0;
end;
end;
end;
else do;
link get_redemptions;
end;
return;
get_redemptions:
set redemptions;
return;
run;
This is the output I'm getting:
Coupon_NBR AMOUNT REDEEMED EXPIRED REMAINING redemp_coupon_nbr trans_amount type
A 500 150 150 350 A -350 REDEMPTION
A 500 350 350 150 A -200 EXPIRATION
B 500 0 0 500 B -300 REDEMPTION
B 500 300 300 200 B -200 EXPIRATION
B 500 200 200 300 B -1000 REDEMPTION
B 1250 1000 1000 250 C -1500 REDEMPTION
B 750 0 0 750 C -500 EXPIRATION
In this example, the correct output is:
redemp_coupon_nbr AMOUNT REDEEMED EXPIRED REMAINING
A 500 500 0 0
A 500 0 200 300
B 500 300 200 0
B 500 500 0 0
B 500 500 0 0
B 1250 0 0 1250
B 750 0 0 750
C 500 500 0 0
C 500 500 0 0
C 500 500 0 0
C 500 0 500 0
C 500 0 0 500
Obviously my result is far from where I want it to be. My main concern, however, is that the output only has seven rows, when I want it track every coupon issue, which means I need it to have 12 rows (one for each row in the ISSUE table). There is some kind of a problem with my loop I think specifically in the Get Redemptions definition. I've been debugging for a while without success.
Jarom:
A robust solution requires a transactional ledgering approach in order to properly deal with the alternatives of fetching multiple redemptions per coupon and tracking overages, and applying overages to a coupon before fetching additional redemptions.
The following sample code has numerous put statements so you can observe the algorithm decision points in the log. The balance goal is to approach zero (from above or below) at each transaction reconciliation, and track any portions that go beyond the goal.
For the sample these variable names substitutions were done with respect to your data.
coupon_nbr -> G
redemp_coupon_nbr -> XG
trans_amount -> XAMOUNT
You were correct in needing a LINK to fetch the redemptions.
The group wise processing is further facilitated by adding BY XG and END=.
Tests for the redemptions end= variable prevent a premature halting of the data step (which would occur if a subsequent unconditional set is reached after a data sets last record is read).
data reconciliation (keep=G AMOUNT REDEEMED EXPIRED REMAINING EXCESS APP_COUNT _redem_bal _expir_bal fetch_sum)
; * / debug;
set issue;
by G;
REDEEMED = 0;
EXPIRED = 0;
REMAINING = 0;
EXCESS = 0;
if 0 then set redemptions; %* prep pdv;
retain _balance 0;
retain _redem_sum 0;
retain _expir_sum 0;
retain _redem_bal 0;
retain _expir_bal 0;
if first.g then put / '----------- ' G= '-------------';
put '#set ' _N_=;
put 'balance: ' _balance _redem_bal= _expir_bal=;
put 'coupon : ' amount first.g= /;
if first.G then do;
put #3 '#first in group';
_balance = amount;
_redem_sum = 0;
_redem_bal = 0;
_expir_sum = 0;
_expir_bal = 0;
put #3 'balance: ' _balance _redem_bal= _expir_bal= G= XG=;
* spin to first matching redemption or first redemption in a higher by-group;
if (XG ne G) then
do while (not EOT);
link fetch;
if XG >= G then leave;
end;
if (G = XG) then
link apply_redemp;
put #6 'spin: ' G= XG=;
end;
else do; * additional couponage;
put #3 '#next in group';
if (G = XG) then
_balance + amount;
else
_balance = amount;
put #3 'balance: ' _balance _redem_bal= _expir_bal=;
link apply_excess_to_balance;
put #3 'balance: ' _balance _redem_bal= _expir_bal= xg= last.xg=;
if (_balance > 0 and G = XG and not last.XG) then
link fetch_apply;
end;
if (G = XG) then
do while (not EOT and not last.XG and _balance > 0);
link fetch_apply;
end;
redeemed = _redem_sum;
expired = _expir_sum;
remaining = min (_balance, amount);
excess = sum (_redem_bal, _expir_bal, max (0, _balance - amount));
output;
put #4 'output: ' amount= redeemed= expired= remaining= excess= /;
_redem_sum = 0;
_expir_sum = 0;
return;
apply_excess_to_balance:
if (_redem_bal > 0 and _balance > 0) then do;
apply = min ( _balance, _redem_bal );
_redem_sum + apply;
_redem_bal + -apply;
_balance + -apply;
app_count = sum(app_count,1);
put #4 'excess: ' apply= _redem_bal= _redem_sum= _balance= 'reduced amount by excess redemption';
end;
if (_expir_bal > 0 and _balance > 0) then do;
apply = min ( _balance, _expir_bal );
_expir_sum + apply;
_expir_bal + -apply;
_balance + -apply;
app_count = sum(app_count,1);
put #4 'excess: ' apply= _expir_bal= _expir_sum= _balance= 'reduced amount by excess expiration';
end;
return;
fetch:
set redemptions end=EOT;
by XG;
put #5 'fetch: ' xg= xamount= type= first.xg= last.xg= EOT=;
return;
fetch_apply:
link fetch;
if (G = XG) then
link apply_redemp;
return;
apply_redemp:
if type in: ('RED' 'EXP') then do;
apply = min (_balance, -XAMOUNT);
excess = max (0, -XAMOUNT - _balance);
if type =: 'RED' then do;
_redem_sum + apply;
_redem_bal + excess;
end;
else
if type =: 'EXP' then do;
_expir_sum + apply;
_expir_bal + excess;
end;
_balance + -apply;
app_count = sum(app_count,1);
fetch_sum = sum(fetch_sum, -xamount);
put #5 'apply: ' apply= _balance= _redem_sum= _expir_sum= _redem_bal= _expir_bal=;
end;
return;
run;
Here is some additional sample data with
non matching redemption
B group has a first redemption which is a large excess that spans two coupons.
coupon group with no redemptions
Trickier data
data ISSUE; input
G $ AMOUNT;
A 500
A 500
B 500
B 500
B 500
B 1250
B 750
B2 100
B2 200
C 500
C 500
C 500
C 500
C 500
run;
data REDEMPTIONS; input
XG $ XAMOUNT TYPE $16.; datalines;
! -1000 REDEMPTION
A -150 REDEMPTION
A -350 REDEMPTION
A -200 EXPIRATION
B -1100 REDEMPTION was -300
B -200 EXPIRATION
B -1000 REDEMPTION
C -1500 REDEMPTION
C -500 EXPIRATION
run;

Problems with my unix-epoch time converter

I wrote a simple function to fill three variables with the current year, month, and day.
However, for some reason it is not working correctly, and I can't seem to find the problem.
void getDate(int *year, int *month, int *date)
{
int epochTime,
monthLength,
functionYear,
functionMonth,
functionDate;
functionYear = 1970;
functionMonth = 1;
functionDate = 1;
epochTime = time(NULL);
while (epochTime > 1 * 365 * 24 * 60 * 60)
{
epochTime -= 1 * 365 * 24 * 60 * 60;
functionYear++;
}
monthLength = findMonthLength(functionYear, functionMonth, false);
while (epochTime > 1 * monthLength * 24 * 60 * 60)
{
printf("%d\n", epochTime);
epochTime -= 1 * monthLength * 24 * 60 * 60;
functionMonth++;
monthLength = findMonthLength(functionYear, functionMonth, false);
printf("functionMonth = %d\n", functionMonth);
}
while (epochTime > 1 * 24 * 60 * 60)
{
printf("%d\n", epochTime);
epochTime -= 1 * 24 * 60 * 60;
functionDate++;
printf("functionDate = %d\n", functionDate);
}
*year = functionYear;
*month = functionMonth;
*date = functionDate;
}
findMonthLength() returns an integer value which the length of the month it is sent. 1 = January, etc. It uses the year to test if it is a leap year.
It is currently April 3, 2013; however, my function finds April 15, and I can't seem to find where my problem is.
EDIT:
I got it. My first problem was that while I remembered to check for leap years when finding the months, I forgot about that when finding each year, which put me several days off.
My second problem was that I didn't convert to the local time zone from UTC
One problem could in this section:
while (epochTime > 1 * 365 * 24 * 60 * 60)
{
epochTime -= 1 * 365 * 24 * 60 * 60;
functionYear++;
}
Each iteration of this loop, a time in seconds corresponding to one normal year is subtracted. This does not account for leap years, where you need to subtract a time corresponding to 366 days.
For that section, you may want:
int yearLength = findYearLength(functionYear + 1);
while (epochTime > 1 * yearLength * 24 * 60 * 60)
{
epochTime -= 1 * yearLength * 24 * 60 * 60;
functionYear++;
yearLength = findYearLength(functionYear + 1);
}
with findYearLength(int year) being a function that returns the length in days of a given year.
One minor issue is that leap seconds are not accounted for. As only 35 of these have been added, that can be safely ignored in a calculation for a given day.
Why not use gmtime() or localtime() and be done with it? They return a structure with everything you need in it.
I made the complete solution based on yours, in Python. I hope it will help someone, someday. Cheers!
Use: getDate(unixtime)
def leapYear(year):
#returns True if the year is a leap year, return False if it isn't
if year % 400 == 0:
return True
elif year % 100 == 0:
return False
elif year % 4 == 0:
return True
else:
return False
def findMonthLength(year, month):
#returns an integer value with the length of the month it is sent.
#1 = January, etc. It uses the year to test if it is a leap year.
months1 = [0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
months2 = [0,31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if (leapYear(year)==True):
return months2[month]
else:
return months1[month]
def findYearLength(year):
#returns an integer value with the length of the year it is sent.
#It uses the year to test if it is a leap year.
if leapYear(year)==True:
return 366
else:
return 365
def getDate(epoch):
SECONDS_PER_YEAR = 0
SECONDS_PER_MONTH = 0
SECONDS_PER_DAY = 24 * 60 * 60
SECONDS_PER_HOUR = 60*60
SECONDS_PER_MIN = 60
epochTime = epoch
monthLength = 0
yearLength = 0
year = 1970
month = 1
day = 1
hour = 0
minu = 0
seg = 0
#Years
yearLength = findYearLength(year)
SECONDS_PER_YEAR = yearLength * SECONDS_PER_DAY
while (epochTime >= SECONDS_PER_YEAR):
epochTime -= SECONDS_PER_YEAR
year += 1
yearLength = findYearLength(year)
SECONDS_PER_YEAR = yearLength * SECONDS_PER_DAY
#Months
monthLength = findMonthLength(year, month)
SECONDS_PER_MONTH = monthLength * SECONDS_PER_DAY
while (epochTime >= SECONDS_PER_MONTH):
epochTime -= SECONDS_PER_MONTH;
month += 1
monthLength = findMonthLength(year, month)
SECONDS_PER_MONTH = monthLength * SECONDS_PER_DAY
#Days
while (epochTime >= SECONDS_PER_DAY):
epochTime -= SECONDS_PER_DAY;
day += 1
#Hours
while (epochTime >= SECONDS_PER_HOUR):
epochTime -= SECONDS_PER_HOUR;
hour += 1
#Minutes
while (epochTime >= SECONDS_PER_MIN):
epochTime -= SECONDS_PER_MIN;
minu += 1
#Seconds
seg = epochTime
print ("%d-%d-%d %d:%d:%d") % (year, month, day, hour, minu, seg)

Basic C programming help

Hey, I need help writing a simple program. I want to be able to demonstrate the use of integers and the remainders using a modulus. I'm stuck at how I should calculate the information. Any help would be much appreciated, but here's the general idea. The program encompasses the following:
1 week = 40 hours ($200 per week)
1 day = 7 hours ($45 per day)
($2 per hour)
Sample run:
Enter the total hours:59 (59 is just an example.)
You have:
1week
2day(s)
5hr(s)
Payment: $300.00
Here's what I've come up with so far...
int main(){
int totalWeekHrs = 0,
totalDayHrs = 0,
totalWorkedHrs = 0;
float totalPayment = 0,
payPerWeek = 0,
payPerDay = 0,
PayPerHr = 0;
// Input process
printf("Enter the total hours :");
scanf("%i",&totalWeekHrs,&totalDayHrs,&totalWorkedHrs);
// Calculative process
system("pause");
}
This smells like homework so I will explain how modulus works.
The modulus operator, %, performs integer division and returns the remainder. For example:
int foo = 6;
int bar = 4;
int remainder = foo % bar;
In that example, remainder will be set to 2.
You can read more about the modulus operator here.
I won't answer your question with code, since it seems homework. You have also stopped when you should really start coding!
The problem is another skin for the "change return" typical question. This is a eager algorithm which tries to resolve the objective with the biggest step it can take.
You have to have two paralell vectors:
{ 40, 7, 1 } // hours worked (week, day, hour)
{ 200, 45, 2 } // salary for each item above.
Notice that the first vector is sorted and that each position matches the same position in the second. The objective is 59 in your example.
For each position in the first vector, you have to divide by your objective, and annotate the remaining.
For example, for the first position, the biggest amount is 1, for the second, 2...
First step:
( 59 / 40 ) == 1
( 59 % 40 ) == 19
Second step:
( 19 / 7 ) == 2
( 19 % 7 ) == 5
Third step:
( 5 / 1 ) == 5
( 5 % 1 ) == 0
You'll finally get a vector as long as the first one with the results:
{ 1, 2, 5 } // one week, two days and five hours.
In order to show the results, just run over the vector, and multiply each position by the same position in the second vector:
1 week(s) ( 1 * 200 )
2 day(s) ( 2 * 45 )
5 hour(s) ( 5 * 2 )
( 1 * 200 ) + ( 2 * 45 ) + ( 5 * 2 ) = 300
This way you get the result you need.

Resources