ternal Posted July 21, 2018 Share Posted July 21, 2018 Hi, This will be my very first post on the Autoit forums.I hope I posted this in the right place, my apologies if it is not. I am a technician for an automatic storage facility, recently we have grown so big that I hardly get around my electrical and mechnical maintenance. Over the passed years I have been spending more and more time behind the computer arranging the storage so that its optimised for free space. These are very repetitive tasks with a lot of factors to take care off. The company that installed the storage facility has given us functions to optimise space but they hardly work properly and do not take enough parameters in account. So I am giving it a go myself. In the past I have used Autoit to automate things at home of low importance however all the programming I know is hometaught. So far I have a program that extracts an array, the array is checked on any faults during the extraction and checked if its the proper data. From there on I would like to arrange the pallets in the physical storage(there are short rows that hold 2~6 pallets and long rows that hold 9 pallets). The smallest storage rows should be filled up first with the least number of movements of pallets . So for this project I would like to know if I write my code properly , tips and remarks are very welcome. I am uncertain if I wrote this properly and if not how I should write it . Func _Find_Optimisable_rows(Const ByRef $a_Block) ;Declaration ;$a_Block[rows][properties] = an imported array of storage rows with each their own number of pallets and total space ;$a_block[row][0] = number of pallets stored in the storage row ;$a_block[row][1] = maximum storage spaces in this row Local $Total_space = 0 Local $Number_of_pallets = 0 Local $a_Rows_to_be_filled[UBound($a_Block, 1)]; declare an onedimensional array with same number of indices as the imported array ;/declaration For $i = 0 To UBound($a_Block, 1) - 1 ; for all rows in array $a_block $Total_space += $a_Block[$i][1] ; add the current row's total space to the total space $Number_of_pallets += $a_Block[$i][0] ; add current row's number of pallets to total number of pallets Next _Sort_Block($a_Block) ; sort the array on maximum storage spaces, smallest first ;secondary sort all the rows with same number of maximum storage space by number of pallets stored with the biggest number of pallets first For $i = 0 To UBound($a_Block, 1) - 1 ; for all rows in array $a_block If ($Total_space - $Number_of_pallets) > $a_Block[$i][1] And $Number_of_pallets > 0 Then;check if we can free up space by filling this row/check for end-of-loop $a_Rows_to_be_filled[$i] = 1; set the local array so we know the row can be completly filled $Total_space -= $a_Block[$i][1] ; substract the filled row from maximum storage space $Number_of_pallets -= $a_Block[$i][1] ; subtract the number of pallets we used to fill that row Else $a_Rows_to_be_filled[$i] = 0 ReDim $a_Rows_to_be_filled[$i] ; shrinks array to needed size Return $a_Rows_to_be_filled ; end function and return the array with rows that can be optimised EndIf Next EndFunc Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted July 21, 2018 Moderators Share Posted July 21, 2018 Moved to the appropriate forum, as the Developer General Discussion forum very clearly states: Quote General development and scripting discussions. If it's super geeky and you don't know where to put it - it's probably here. Do not create AutoIt-related topics here, use the AutoIt General Help and Support or AutoIt Technical Discussion forums. Moderation Team Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
ternal Posted July 25, 2018 Author Share Posted July 25, 2018 (edited) Ok, time to try a bump and some more information. I am a technician for an automatic storage facility, recently we have grown so big that I hardly get around my electrical and mechnical maintenance. Over the passed years I have been spending more and more time behind the computer arranging the storage so that its optimised for free space. These are very repetitive tasks with a lot of factors to take care off. The company that installed the storage facility has given us functions to optimise space but they hardly work properly and do not take enough parameters in account. So I am giving it a go myself. In the past I have used Autoit to automate things at home of low importance however all the programming I know is hometaught. the automatic warehous is divided up in several blocks (up to 18) each block is maximum 10 rows high, maximum 102 rows far. each row can contain x number of euro pallets, x number of industry pallets or x number of wooden boxes. there are huge cranes driving between blocks that extract and store pallets, the cranes will never place different items together. depending on supply and demand (certain clients ask for specific pallets, others just want entire runs of a product) the cranes will retrievethe product without taking in account of optimalisation. this means after a while there are plenty of rows that each have 2~3 pallets while there are other rows with the same article with also only 2~3 pallets. We have short rows (due to space limitations) and long rows. the short rows are blocked for automatic filling up because we prefer to place batches of a product as close together as possible. From time to time we are supposed to place all articles together that can be placed together and the rows that are not full , if possible, we place them in the short rows then for every 2 blocks (for every crane) I have a list of rows used (kanalenInW2, W2 is block 5 to 8) and for the same locations I have a list with items . I have written a program that finds all buttons/info on the programs available to us. it extracts the lists and places them in a 3d array such that each row is the first and second dimension and the information about the items inside the row is the third dimension. each item has its expiration date and the eldest can be placed behind new ones but never vica versa (there is a FIFO limitation of 5 days, however this is item specific and should be referenced to from another list) so far the output I get is a list of possible rows that I can place together and I can use my logic to place them together but if I have for example the rows are labelled as xx.yyy.zz with x being the block, y being the row of the block, and z being the height so an example in 03.002.05 there are 4 industry pallets with article X, max space there for industry pallets is 8 (euro is smallest, industry pallets slightly bigger and boxes the biggest) in 03.016.01 there are 2 industry pallets with article X, max space there is 6 industry pallets we know that we should try in short channels and they will fit in, so we place them together in 03.016.01. however some rows only have 1 or 2 spaces, some have 4 or 5 , standard is 9 but we have some that go up to 14. freeing up long channels is a major goal and if its not possible to free up long channels we put non-full long rows into short ones. however we cannot treat the short rows lightly because we have over 1000 different items possible stored. so there are a lot of rows that are not completly filled. these belong in short rows.Every new item that is different gets a new row, and automatically it will search for a long row already containing those if none are found it will place it in a new long one. eventually there is a long row that is not completly filled and we place it in short rows then. my attempt currently is just checks for all the items with same article number , some are already manually placed in short rows , some are in long rows by automatic storage. it does not use new short rows and that is fine. but if there are already items in a short row and we can free up a long row by filling up the short one it should do that. how do I translate all of the above into code? without leaving out certain parameters? I would first check to free up long rows by placing items together in short rows IF there is already an item in the short row. then when it is done with ALL of that I would have it place the long rows that are not completly filled in free short rows this is my attempt any ideas? I am on vacation now and would like to work this out before I return. Func _Find_Optimisable_rows(Const ByRef $a_Block) ;Declaration ;$a_Block[rows][properties] = an imported array of storage rows with each their own number of pallets and total space ;$a_block[row][0] = number of pallets stored in the storage row ;$a_block[row][1] = maximum storage spaces in this row Local $Total_space = 0 Local $Number_of_pallets = 0 Local $a_Rows_to_be_filled[UBound($a_Block, 1)]; declare an onedimensional array with same number of indices as the imported array ;/declaration For $i = 0 To UBound($a_Block, 1) - 1 ; for all rows in array $a_block $Total_space += $a_Block[$i][1] ; add the current row's total space to the total space $Number_of_pallets += $a_Block[$i][0] ; add current row's number of pallets to total number of pallets Next _Sort_Block($a_Block) ; sort the array on maximum storage spaces, smallest first ;secondary sort all the rows with same number of maximum storage space by number of pallets stored with the biggest number of pallets first For $i = 0 To UBound($a_Block, 1) - 1 ; for all rows in array $a_block If ($Total_space - $Number_of_pallets) > $a_Block[$i][1] And $Number_of_pallets > 0 Then;check if we can free up space by filling this row/check for end-of-loop $a_Rows_to_be_filled[$i] = 1; set the local array so we know the row can be completly filled $Total_space -= $a_Block[$i][1] ; substract the filled row from maximum storage space $Number_of_pallets -= $a_Block[$i][1] ; subtract the number of pallets we used to fill that row Else $a_Rows_to_be_filled[$i] = 0 ReDim $a_Rows_to_be_filled[$i] ; shrinks array to needed size Return $a_Rows_to_be_filled ; end function and return the array with rows that can be optimised EndIf Next EndFunc edit: there is A mistake with ReDim $a_Rows_to_be_filled[$i] it should be : ReDim $a_Rows_to_be_filled[$i+1] KanalenInW2.xlsx LEInW2.xlsx Edited July 25, 2018 by ternal Link to comment Share on other sites More sharing options...
iamtheky Posted July 25, 2018 Share Posted July 25, 2018 tagging in @czardas as this screams to be treated as 2 3D arrays rather than (6) 7x18 2D arrays on the left and (8) 8x18 2D arrays on the right. I am headed that route but i travel infintely slower than he does. ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__) Link to comment Share on other sites More sharing options...
ternal Posted July 25, 2018 Author Share Posted July 25, 2018 (edited) I actually treat the entire place as 1 3D array, the rows are labelled as XX , YYY,ZZ xx being the block, YYY being the rows , ZZ being the elevation/height. the location, xx.yyy.zz is just one column in both the first excel file and the second. I use the location to merge them into a 3d array the different blocks are just in the same array. the short rows are not bound to any block. in each block we have long and short rows. some block mostly have short rows and others mostly long rows but its kinda mixed we also do not move from block 1 to 9 for example. but I extract the lists in the blocks they are allowed to transfer Edited July 25, 2018 by ternal Link to comment Share on other sites More sharing options...
iamtheky Posted July 25, 2018 Share Posted July 25, 2018 (edited) Is there more code (there are no 3D references)? That optimization of a nearest neighbor solution seems hindered by slicing it into 2D sections in the function (but I have been wronger before) and you have criteria that it be placed into the shorter & nearest rows first? So if you were building an If..Then, you would want to check that entire left side first, no? Edited July 25, 2018 by iamtheky ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__) Link to comment Share on other sites More sharing options...
ternal Posted July 25, 2018 Author Share Posted July 25, 2018 (edited) I use the first page of the 3d array since I placed the highest and lowest expiration date on the first page. but there are different things in there I will need to adress in the future like weight and how often it is retrieved from the warehouse. (heaviest low and lighest items on top for safety and mechanical wear). I added slices of the 3d array . the first page of that array would be what I start with in my example. LE is items so #LE is number of items in a row. thats on the first page (0) from there on forward each page is one slice of the all the rows in the first page (each page contains its own item and just one item, index [0] contains the info on the row edit: the left side is a simple representation. as I stated before maybe 90% of those rows are short, but where it was possible they made long ones. so 10% will be long. my script goes through all rows and checks the space (the space is also dependant on the item, because they have different sizes so it extracts and calculates the max space for current item already(max plaatsen). it also retrieves number of items inside each row(#LE) and free space in that channel (vrije plaatsen in kanaal), then we have article(artikel) the height of the row ( boxes are not high so we have different heights as well in rows, for extra headache?) fifo gebied is how many days they may differ from each other , then we have a few random stuff not of importance now. THT is experiation date currently my script only looks to optimise rows that have at least 1 item in them. And we will start with that. I have enough resources at my disposal (3 pc's with I7's and SSD's ) to work everything out. its not a nearest neighbour issue rather then finding out how it should move them. moving everything into short rows will clog up the short rows and in no time we will have long rows that are not completly filled. so it should only fill up the already used short rows (for now at least) when it can make a long row free else it should just place the remainder in the short row my script right now checks if a row can be freed. when its done with that I would have to restart, take away the shortest row and run it again, then the shortest after that etc etc. then I have all the options I can to move it around . and it should pick one of those options depending on the length of the channels that are freed but I feel like its going to be more work to explain all of this properly then to write something myself. lol just wanted to know how a programmer should start tackling such a problem. I have a technical background, electronics(learned crude basics of programming there), took extra courses in welding on request of my boss, took courses in programming PLC's on request of my boss. however I did not ever receive training as how to program such algorithms I would upload my entire script but its about 1600 lines long, mostly written with dutch or german variable names and comments and I know how it works but it does get confusing sometimes... especially since it covers a lot more then we are talking now and most of the functions acces the same arrays and I did not take any effort in keeping that tidy :/ my apologies Some parts of it are not even used anymore as it was a work in progress, still is. some variables get declared but never used and then a new variable with a very very similar name jumps in and I continue on that one. I should rewrite the entire thing tbh Edited July 25, 2018 by ternal Link to comment Share on other sites More sharing options...
RTFC Posted July 25, 2018 Share Posted July 25, 2018 Many parameters (dimensions) + multiple, partly conflicting constraints: use Simulated Annealing. Study the TSP example (corresponds to the distances to move pallets/boxes), then think long and hard about how to define your cost function, depending on what's relatively most important (you may have to spend some time testing and tuning this for "best" results). ternal 1 My Contributions and Wrappers Spoiler BitMaskSudokuSolver BuildPartitionTable CodeCrypter CodeScanner DigitalDisplay Eigen4AutoIt FAT Suite HighMem MetaCodeFileLibrary OSgrid Pool RdRand SecondDesktop SimulatedAnnealing Xbase I/O Link to comment Share on other sites More sharing options...
ternal Posted July 25, 2018 Author Share Posted July 25, 2018 thank you @RTFC this was the information I was looking for!! any other things I should look into? Link to comment Share on other sites More sharing options...
czardas Posted July 25, 2018 Share Posted July 25, 2018 (edited) Oooh nice - a 3D queuing system. This is one of the most interesting questions I've encountered. As @RTFC says, raw brute force may not be suitable. Rearranging the pallets must be done with the fewest number of moves within localized regions. I don't fully understand the stacking order: I assume older pallets ought to be placed on top (for quick access). Unfortunately I don't have a ready made solution, but this is a very complex problem which requires some study. The pallets should only be moved once within a single reshuffle (presumably unstacked and restacked). Need to reread this question a few times. Edited July 25, 2018 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now